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

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

101 102
#define VIR_FROM_THIS VIR_FROM_QEMU

103 104
VIR_LOG_INIT("qemu.qemu_driver");

105 106
#define QEMU_NB_MEM_PARAM  3

107 108
#define QEMU_NB_BLOCK_IO_TUNE_PARAM  6

109 110
#define QEMU_NB_NUMA_PARAM 2

111
#define QEMU_NB_PER_CPU_STAT_PARAM 2
E
Eric Blake 已提交
112

113 114 115 116 117
#define QEMU_SCHED_MIN_PERIOD              1000LL
#define QEMU_SCHED_MAX_PERIOD           1000000LL
#define QEMU_SCHED_MIN_QUOTA               1000LL
#define QEMU_SCHED_MAX_QUOTA  18446744073709551LL

118 119 120
#if HAVE_LINUX_KVM_H
# include <linux/kvm.h>
#endif
121

122 123
/* device for kvm ioctls */
#define KVM_DEVICE "/dev/kvm"
124

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

136
#define QEMU_NB_BLKIO_PARAM  6
137

138 139
#define QEMU_NB_BANDWIDTH_PARAM 6

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

144 145 146 147
static void processGuestPanicEvent(virQEMUDriverPtr driver,
                                   virDomainObjPtr vm,
                                   int action);

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

150
static int qemuStateCleanup(void);
151

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

157
static int qemuDomainGetMaxVcpus(virDomainPtr dom);
158

159 160
static int qemuDomainManagedSaveLoad(virDomainObjPtr vm,
                                     void *opaque);
161

162 163 164 165 166 167 168 169 170 171
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);

172

173
virQEMUDriverPtr qemu_driver = NULL;
174 175


176
static void
177 178
qemuVMDriverLock(void)
{}
179
static void
180 181
qemuVMDriverUnlock(void)
{}
182 183

static int
184
qemuVMFilterRebuild(virDomainObjListIterator iter, void *data)
185
{
186
    return virDomainObjListForEach(qemu_driver->domains, iter, data);
187 188 189 190 191 192 193 194 195 196
}

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


197
struct qemuAutostartData {
198
    virQEMUDriverPtr driver;
199 200
    virConnectPtr conn;
};
201

202

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

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

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

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

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

276
    if (cfg->autoStartBypassCache)
277
        flags |= VIR_DOMAIN_START_BYPASS_CACHE;
278

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

E
Eric Blake 已提交
299
        if (!qemuDomainObjEndJob(data->driver, vm))
300
            vm = NULL;
301
    }
302

303
    ret = 0;
304
 cleanup:
305
    if (vm)
306
        virObjectUnlock(vm);
307
    virObjectUnref(cfg);
308
    return ret;
309 310
}

311

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

325
    virDomainObjListForEach(driver->domains, qemuAutostartDomain, &data);
326

327
    virObjectUnref(conn);
328
    virObjectUnref(cfg);
329 330
}

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346

static int
qemuSecurityChownCallback(virStorageSourcePtr src,
                          uid_t uid,
                          gid_t gid)
{
    struct stat sb;
    int save_errno = 0;
    int ret = -1;

    if (!virStorageFileSupportsSecurityDriver(src))
        return 0;

    if (virStorageSourceIsLocalStorage(src)) {
        /* use direct chmod for local files so that the file doesn't
         * need to be initialized */
347 348 349
        if (!src->path)
            return 0;

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
        if (stat(src->path, &sb) >= 0) {
            if (sb.st_uid == uid &&
                sb.st_gid == gid) {
                /* It's alright, there's nothing to change anyway. */
                return 0;
            }
        }

        return chown(src->path, uid, gid);
    }

    /* storage file init reports errors, return -2 on failure */
    if (virStorageFileInit(src) < 0)
        return -2;

    if (virStorageFileChown(src, uid, gid) < 0) {
        save_errno = errno;
        goto cleanup;
    }

    ret = 0;

 cleanup:
    virStorageFileDeinit(src);
    errno = save_errno;

    return ret;
}


380
static int
381
qemuSecurityInit(virQEMUDriverPtr driver)
382
{
383
    char **names;
384 385
    virSecurityManagerPtr mgr = NULL;
    virSecurityManagerPtr stack = NULL;
386
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
387

388 389 390
    if (cfg->securityDriverNames &&
        cfg->securityDriverNames[0]) {
        names = cfg->securityDriverNames;
391
        while (names && *names) {
392 393
            if (!(mgr = virSecurityManagerNew(*names,
                                              QEMU_DRIVER_NAME,
394 395 396
                                              cfg->allowDiskFormatProbing,
                                              cfg->securityDefaultConfined,
                                              cfg->securityRequireConfined)))
397
                goto error;
398 399 400 401 402 403 404 405
            if (!stack) {
                if (!(stack = virSecurityManagerNewStack(mgr)))
                    goto error;
            } else {
                if (virSecurityManagerStackAddNested(stack, mgr) < 0)
                    goto error;
            }
            mgr = NULL;
406 407
            names++;
        }
408 409 410
    } else {
        if (!(mgr = virSecurityManagerNew(NULL,
                                          QEMU_DRIVER_NAME,
411 412 413
                                          cfg->allowDiskFormatProbing,
                                          cfg->securityDefaultConfined,
                                          cfg->securityRequireConfined)))
414
            goto error;
415
        if (!(stack = virSecurityManagerNewStack(mgr)))
416
            goto error;
417 418
        mgr = NULL;
    }
419

420
    if (cfg->privileged) {
421
        if (!(mgr = virSecurityManagerNewDAC(QEMU_DRIVER_NAME,
422 423 424 425 426
                                             cfg->user,
                                             cfg->group,
                                             cfg->allowDiskFormatProbing,
                                             cfg->securityDefaultConfined,
                                             cfg->securityRequireConfined,
427
                                             cfg->dynamicOwnership,
428
                                             qemuSecurityChownCallback)))
429 430 431 432 433 434 435 436 437
            goto error;
        if (!stack) {
            if (!(stack = virSecurityManagerNewStack(mgr)))
                goto error;
        } else {
            if (virSecurityManagerStackAddNested(stack, mgr) < 0)
                goto error;
        }
        mgr = NULL;
438
    }
D
Daniel Veillard 已提交
439

440
    driver->securityManager = stack;
441
    virObjectUnref(cfg);
442
    return 0;
443

444
 error:
445
    VIR_ERROR(_("Failed to initialize security drivers"));
446 447
    virObjectUnref(stack);
    virObjectUnref(mgr);
448
    virObjectUnref(cfg);
449 450
    return -1;
}
451

452

453 454
static int
qemuDomainSnapshotLoad(virDomainObjPtr vm,
455
                       void *data)
456
{
457 458 459 460 461 462 463
    char *baseDir = (char *)data;
    char *snapDir = NULL;
    DIR *dir = NULL;
    struct dirent *entry;
    char *xmlStr;
    char *fullpath;
    virDomainSnapshotDefPtr def = NULL;
464
    virDomainSnapshotObjPtr snap = NULL;
465
    virDomainSnapshotObjPtr current = NULL;
466
    char ebuf[1024];
467
    unsigned int flags = (VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE |
468
                          VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
469
                          VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL);
470
    int ret = -1;
471
    virCapsPtr caps = NULL;
E
Eric Blake 已提交
472
    int direrr;
473

474
    virObjectLock(vm);
475 476 477
    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);
478
        goto cleanup;
479 480
    }

481 482 483
    if (!(caps = virQEMUDriverGetCapabilities(qemu_driver, false)))
        goto cleanup;

484 485
    VIR_INFO("Scanning for snapshots for domain %s in %s", vm->def->name,
             snapDir);
486

487 488 489 490 491
    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)));
492
        goto cleanup;
493 494
    }

E
Eric Blake 已提交
495
    while ((direrr = virDirRead(dir, &entry, NULL)) > 0) {
496 497
        if (entry->d_name[0] == '.')
            continue;
498

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

503
        if (virAsprintf(&fullpath, "%s/%s", snapDir, entry->d_name) < 0) {
504
            VIR_ERROR(_("Failed to allocate memory for path"));
505 506
            continue;
        }
507

508
        if (virFileReadAll(fullpath, 1024*1024*1, &xmlStr) < 0) {
509 510 511 512 513 514
            /* 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;
        }
515

516
        def = virDomainSnapshotDefParseString(xmlStr, caps,
517
                                              qemu_driver->xmlopt,
518 519
                                              QEMU_EXPECTED_VIRT_TYPES,
                                              flags);
520 521
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
522 523
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
                      fullpath);
524 525 526 527
            VIR_FREE(fullpath);
            VIR_FREE(xmlStr);
            continue;
        }
528

529
        snap = virDomainSnapshotAssignDef(vm->snapshots, def);
530 531
        if (snap == NULL) {
            virDomainSnapshotDefFree(def);
532 533 534 535
        } else if (snap->def->current) {
            current = snap;
            if (!vm->current_snapshot)
                vm->current_snapshot = snap;
536
        }
537

538 539
        VIR_FREE(fullpath);
        VIR_FREE(xmlStr);
540
    }
E
Eric Blake 已提交
541 542
    if (direrr < 0)
        VIR_ERROR(_("Failed to fully read directory %s"), snapDir);
543

544 545 546 547 548 549
    if (vm->current_snapshot != current) {
        VIR_ERROR(_("Too many snapshots claiming to be current for domain %s"),
                  vm->def->name);
        vm->current_snapshot = NULL;
    }

550
    if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0)
551 552 553
        VIR_ERROR(_("Snapshots have inconsistent relations for domain %s"),
                  vm->def->name);

554 555 556 557 558 559 560 561
    /* 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.
     */
562

563
    virResetLastError();
564

565
    ret = 0;
566
 cleanup:
567 568 569
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
570
    virObjectUnref(caps);
571
    virObjectUnlock(vm);
572
    return ret;
573 574
}

575

576 577
static int
qemuDomainNetsRestart(virDomainObjPtr vm,
578
                      void *data ATTRIBUTE_UNUSED)
579
{
580
    size_t i;
581 582
    virDomainDefPtr def = vm->def;

583
    virObjectLock(vm);
584 585 586 587 588 589 590 591

    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,
592
                                                                 &net->mac,
593 594 595 596 597 598 599
                                                                 virDomainNetGetActualDirectDev(net),
                                                                 def->uuid,
                                                                 virDomainNetGetActualVirtPortProfile(net),
                                                                 VIR_NETDEV_VPORT_PROFILE_OP_CREATE));
        }
    }

600
    virObjectUnlock(vm);
601
    return 0;
602 603
}

604

605 606
static int
qemuDomainFindMaxID(virDomainObjPtr vm,
607 608 609 610 611 612
                    void *data)
{
    int *driver_maxid = data;

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

    return 0;
615 616 617
}


618
/**
619
 * qemuStateInitialize:
620 621 622
 *
 * Initialization function for the QEmu daemon
 */
623
static int
624 625 626
qemuStateInitialize(bool privileged,
                    virStateInhibitCallback callback,
                    void *opaque)
627
{
628 629
    char *driverConf = NULL;
    virConnectPtr conn = NULL;
630
    char ebuf[1024];
631
    virQEMUDriverConfigPtr cfg;
632 633
    uid_t run_uid = -1;
    gid_t run_gid = -1;
634 635
    char *hugepagePath = NULL;
    size_t i;
636

637 638
    if (VIR_ALLOC(qemu_driver) < 0)
        return -1;
639

640
    if (virMutexInit(&qemu_driver->lock) < 0) {
641
        VIR_ERROR(_("cannot initialize mutex"));
642 643
        VIR_FREE(qemu_driver);
        return -1;
644
    }
645

646 647
    qemu_driver->inhibitCallback = callback;
    qemu_driver->inhibitOpaque = opaque;
648

649 650
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;
651

652 653
    if (!(qemu_driver->domains = virDomainObjListNew()))
        goto error;
654

655
    /* Init domain events */
656
    qemu_driver->domainEventState = virObjectEventStateNew();
657
    if (!qemu_driver->domainEventState)
658
        goto error;
659

660 661 662
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();
663

664 665
    if (!(qemu_driver->config = cfg = virQEMUDriverConfigNew(privileged)))
        goto error;
666

667
    if (virAsprintf(&driverConf, "%s/qemu.conf", cfg->configBaseDir) < 0)
668
        goto error;
669

670 671 672
    if (virQEMUDriverConfigLoadFile(cfg, driverConf) < 0)
        goto error;
    VIR_FREE(driverConf);
H
Hu Tao 已提交
673

674
    if (virFileMakePath(cfg->stateDir) < 0) {
675
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
676
                  cfg->stateDir, virStrerror(errno, ebuf, sizeof(ebuf)));
677
        goto error;
H
Hu Tao 已提交
678
    }
679
    if (virFileMakePath(cfg->libDir) < 0) {
680
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
681
                  cfg->libDir, virStrerror(errno, ebuf, sizeof(ebuf)));
682 683
        goto error;
    }
684
    if (virFileMakePath(cfg->cacheDir) < 0) {
685
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
686
                  cfg->cacheDir, virStrerror(errno, ebuf, sizeof(ebuf)));
687 688
        goto error;
    }
689
    if (virFileMakePath(cfg->saveDir) < 0) {
690
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
691
                  cfg->saveDir, virStrerror(errno, ebuf, sizeof(ebuf)));
692 693
        goto error;
    }
694
    if (virFileMakePath(cfg->snapshotDir) < 0) {
695
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
696
                  cfg->snapshotDir, virStrerror(errno, ebuf, sizeof(ebuf)));
697 698
        goto error;
    }
699
    if (virFileMakePath(cfg->autoDumpPath) < 0) {
700
        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
701
                  cfg->autoDumpPath, virStrerror(errno, ebuf, sizeof(ebuf)));
702
        goto error;
703 704
    }

705 706 707
    qemu_driver->qemuImgBinary = virFindFileInPath("kvm-img");
    if (!qemu_driver->qemuImgBinary)
        qemu_driver->qemuImgBinary = virFindFileInPath("qemu-img");
708 709 710 711 712 713 714

    if (!(qemu_driver->lockManager =
          virLockManagerPluginNew(cfg->lockManagerName ?
                                  cfg->lockManagerName : "nop",
                                  "qemu",
                                  cfg->configBaseDir,
                                  0)))
715
        goto error;
716 717 718 719 720 721 722 723 724

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

725
        if (ebtablesAddForwardPolicyReject(qemu_driver->ebtables) < 0)
726 727
            goto error;
   }
728

729 730 731
    /* Allocate bitmap for remote display port reservations. We cannot
     * do this before the config is loaded properly, since the port
     * numbers are configurable now */
732
    if ((qemu_driver->remotePorts =
J
Ján Tomko 已提交
733 734
         virPortAllocatorNew(_("display"),
                             cfg->remotePortMin,
735 736
                             cfg->remotePortMax,
                             0)) == NULL)
737 738
        goto error;

739
    if ((qemu_driver->webSocketPorts =
J
Ján Tomko 已提交
740 741
         virPortAllocatorNew(_("webSocket"),
                             cfg->webSocketPortMin,
742 743
                             cfg->webSocketPortMax,
                             0)) == NULL)
744 745
        goto error;

746
    if ((qemu_driver->migrationPorts =
J
Ján Tomko 已提交
747 748
         virPortAllocatorNew(_("migration"),
                             cfg->migrationPortMin,
749 750
                             cfg->migrationPortMax,
                             0)) == NULL)
751 752
        goto error;

753 754
    if (qemuSecurityInit(qemu_driver) < 0)
        goto error;
755

756
    if (!(qemu_driver->hostdevMgr = virHostdevManagerGetDefault()))
757 758
        goto error;

759
    if (!(qemu_driver->sharedDevices = virHashCreate(30, qemuSharedDeviceEntryFree)))
760 761
        goto error;

762
    if (privileged) {
763
        if (chown(cfg->libDir, cfg->user, cfg->group) < 0) {
764 765
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to user %d:%d"),
E
Eric Blake 已提交
766 767
                                 cfg->libDir, (int) cfg->user,
                                 (int) cfg->group);
768
            goto error;
769
        }
770
        if (chown(cfg->cacheDir, cfg->user, cfg->group) < 0) {
771
            virReportSystemError(errno,
772
                                 _("unable to set ownership of '%s' to %d:%d"),
E
Eric Blake 已提交
773 774
                                 cfg->cacheDir, (int) cfg->user,
                                 (int) cfg->group);
775
            goto error;
776
        }
777
        if (chown(cfg->saveDir, cfg->user, cfg->group) < 0) {
778 779
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
E
Eric Blake 已提交
780 781
                                 cfg->saveDir, (int) cfg->user,
                                 (int) cfg->group);
782 783
            goto error;
        }
784
        if (chown(cfg->snapshotDir, cfg->user, cfg->group) < 0) {
785 786
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
E
Eric Blake 已提交
787 788
                                 cfg->snapshotDir, (int) cfg->user,
                                 (int) cfg->group);
789
            goto error;
790
        }
791 792
        run_uid = cfg->user;
        run_gid = cfg->group;
793
    }
794

795
    qemu_driver->qemuCapsCache = virQEMUCapsCacheNew(cfg->libDir,
796
                                                     cfg->cacheDir,
797 798
                                                     run_uid,
                                                     run_gid);
799
    if (!qemu_driver->qemuCapsCache)
800 801
        goto error;

802
    if ((qemu_driver->caps = virQEMUDriverCreateCapabilities(qemu_driver)) == NULL)
803 804
        goto error;

805
    if (!(qemu_driver->xmlopt = virQEMUDriverCreateXMLConf(qemu_driver)))
806 807
        goto error;

808 809
    /* 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
810 811 812 813 814
     * will let our spawned QEMU instances use it. */
    for (i = 0; i < cfg->nhugetlbfs; i++) {
        hugepagePath = qemuGetHugepagePath(&cfg->hugetlbfs[i]);

        if (!hugepagePath)
815
            goto error;
816

817
        if (virFileMakePath(hugepagePath) < 0) {
818
            virReportSystemError(errno,
819 820
                                 _("unable to create hugepage path %s"),
                                 hugepagePath);
821
            goto error;
822
        }
823
        if (cfg->privileged) {
824 825
            if (virFileUpdatePerm(cfg->hugetlbfs[i].mnt_dir,
                                  0, S_IXGRP | S_IXOTH) < 0)
826
                goto error;
827
            if (chown(hugepagePath, cfg->user, cfg->group) < 0) {
828 829
                virReportSystemError(errno,
                                     _("unable to set ownership on %s to %d:%d"),
830 831
                                     hugepagePath,
                                     (int) cfg->user,
E
Eric Blake 已提交
832
                                     (int) cfg->group);
833 834
                goto error;
            }
G
Guido Günther 已提交
835
        }
836
        VIR_FREE(hugepagePath);
837
    }
838

839
    if (!(qemu_driver->closeCallbacks = virCloseCallbacksNew()))
840 841
        goto error;

842
    /* Get all the running persistent or transient configs first */
843
    if (virDomainObjListLoadAllConfigs(qemu_driver->domains,
844 845
                                       cfg->stateDir,
                                       NULL, 1,
846
                                       qemu_driver->caps,
847
                                       qemu_driver->xmlopt,
848
                                       QEMU_EXPECTED_VIRT_TYPES,
849
                                       NULL, NULL) < 0)
850
        goto error;
851

852 853 854
    /* find the maximum ID from active and transient configs to initialize
     * the driver with. This is to avoid race between autostart and reconnect
     * threads */
855 856 857
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainFindMaxID,
                            &qemu_driver->nextvmid);
858

859 860 861
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainNetsRestart,
                            NULL);
862

863
    conn = virConnectOpen(cfg->uri);
864

865
    /* Then inactive persistent configs */
866
    if (virDomainObjListLoadAllConfigs(qemu_driver->domains,
867 868
                                       cfg->configDir,
                                       cfg->autostartDir, 0,
869
                                       qemu_driver->caps,
870
                                       qemu_driver->xmlopt,
871
                                       QEMU_EXPECTED_VIRT_TYPES,
872
                                       NULL, NULL) < 0)
873
        goto error;
874

875
    qemuProcessReconnectAll(conn, qemu_driver);
876

877 878 879
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainSnapshotLoad,
                            cfg->snapshotDir);
880

881 882 883
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainManagedSaveLoad,
                            qemu_driver);
884

C
Chen Fan 已提交
885
    qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, qemuProcessEventHandler, qemu_driver);
886 887
    if (!qemu_driver->workerPool)
        goto error;
888

889
    virObjectUnref(conn);
890

891
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
892
    return 0;
893

894
 error:
895
    virObjectUnref(conn);
896
    VIR_FREE(driverConf);
897
    VIR_FREE(hugepagePath);
898
    qemuStateCleanup();
899
    return -1;
900 901
}

902 903 904 905 906 907 908 909 910 911 912 913 914 915
/**
 * qemuStateAutoStart:
 *
 * Function to auto start the QEmu daemons
 */
static void
qemuStateAutoStart(void)
{
    if (!qemu_driver)
        return;

    qemuAutostartDomains(qemu_driver);
}

916
static void qemuNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
917
{
918
    virQEMUDriverPtr driver = opaque;
919

920
    if (newVM) {
921
        virObjectEventPtr event =
922
            virDomainEventLifecycleNewFromObj(vm,
923 924 925 926
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
E
Eric Blake 已提交
927
    }
928
}
E
Eric Blake 已提交
929

930
/**
931
 * qemuStateReload:
932 933 934 935 936
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
937 938
qemuStateReload(void)
{
939 940
    virQEMUDriverConfigPtr cfg = NULL;
    virCapsPtr caps = NULL;
941

942 943
    if (!qemu_driver)
        return 0;
944

945 946 947
    if (!(caps = virQEMUDriverGetCapabilities(qemu_driver, false)))
        goto cleanup;

948
    cfg = virQEMUDriverGetConfig(qemu_driver);
949 950
    virDomainObjListLoadAllConfigs(qemu_driver->domains,
                                   cfg->configDir,
951 952 953
                                   cfg->autostartDir, 0,
                                   caps, qemu_driver->xmlopt,
                                   QEMU_EXPECTED_VIRT_TYPES,
954
                                   qemuNotifyLoadDomain, qemu_driver);
955
 cleanup:
956
    virObjectUnref(cfg);
957
    virObjectUnref(caps);
958 959
    return 0;
}
S
Stefan Berger 已提交
960

961 962

/*
963
 * qemuStateStop:
964 965 966 967 968
 *
 * Save any VMs in preparation for shutdown
 *
 */
static int
969 970
qemuStateStop(void)
{
971 972
    int ret = -1;
    virConnectPtr conn;
973
    int numDomains = 0;
974 975 976 977
    size_t i;
    int state;
    virDomainPtr *domains = NULL;
    unsigned int *flags = NULL;
978
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(qemu_driver);
979

980 981
    if (!(conn = virConnectOpen(cfg->uri)))
        goto cleanup;
982 983 984 985 986 987

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

988
    if (VIR_ALLOC_N(flags, numDomains) < 0)
989 990 991 992 993
        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. */
994
    for (i = 0; i < numDomains; i++) {
995 996 997 998 999 1000 1001 1002 1003 1004 1005
        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 */
1006
    for (i = 0; i < numDomains; i++)
1007 1008 1009 1010
        if (virDomainManagedSave(domains[i], flags[i]) < 0)
            ret = -1;

 cleanup:
1011 1012 1013 1014 1015
    if (domains) {
        for (i = 0; i < numDomains; i++)
            virDomainFree(domains[i]);
        VIR_FREE(domains);
    }
1016
    VIR_FREE(flags);
1017
    virObjectUnref(conn);
1018
    virObjectUnref(cfg);
1019 1020 1021 1022

    return ret;
}

1023
/**
1024
 * qemuStateCleanup:
1025 1026 1027 1028
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
1029 1030
qemuStateCleanup(void)
{
1031 1032
    if (!qemu_driver)
        return -1;
1033

1034
    virNWFilterUnRegisterCallbackDriver(&qemuCallbackDriver);
1035
    virObjectUnref(qemu_driver->config);
1036
    virObjectUnref(qemu_driver->hostdevMgr);
1037
    virHashFree(qemu_driver->sharedDevices);
1038
    virObjectUnref(qemu_driver->caps);
1039
    virQEMUCapsCacheFree(qemu_driver->qemuCapsCache);
1040

1041
    virObjectUnref(qemu_driver->domains);
1042
    virObjectUnref(qemu_driver->remotePorts);
1043
    virObjectUnref(qemu_driver->webSocketPorts);
1044
    virObjectUnref(qemu_driver->migrationPorts);
1045

1046
    virObjectUnref(qemu_driver->xmlopt);
1047

1048
    virSysinfoDefFree(qemu_driver->hostsysinfo);
1049

1050
    virObjectUnref(qemu_driver->closeCallbacks);
1051

E
Eric Blake 已提交
1052
    VIR_FREE(qemu_driver->qemuImgBinary);
1053

1054
    virObjectUnref(qemu_driver->securityManager);
1055

1056
    ebtablesContextFree(qemu_driver->ebtables);
1057

1058
    /* Free domain callback list */
1059
    virObjectEventStateFree(qemu_driver->domainEventState);
D
Daniel P. Berrange 已提交
1060

1061 1062
    virLockManagerPluginUnref(qemu_driver->lockManager);

1063 1064 1065
    virMutexDestroy(&qemu_driver->lock);
    virThreadPoolFree(qemu_driver->workerPool);
    VIR_FREE(qemu_driver);
1066

1067
    return 0;
1068 1069
}

1070

1071 1072 1073
static virDrvOpenStatus qemuConnectOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
1074
{
1075 1076
    virQEMUDriverConfigPtr cfg = NULL;
    virDrvOpenStatus ret = VIR_DRV_OPEN_ERROR;
E
Eric Blake 已提交
1077 1078
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1079
    if (conn->uri == NULL) {
1080 1081 1082 1083 1084 1085
        if (qemu_driver == NULL) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }

        cfg = virQEMUDriverGetConfig(qemu_driver);
1086

1087 1088
        if (!(conn->uri = virURIParse(cfg->uri)))
            goto cleanup;
1089 1090 1091
    } else {
        /* If URI isn't 'qemu' its definitely not for us */
        if (conn->uri->scheme == NULL ||
1092 1093 1094 1095
            STRNEQ(conn->uri->scheme, "qemu")) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }
1096 1097

        /* Allow remote driver to deal with URIs with hostname server */
1098 1099 1100 1101
        if (conn->uri->server != NULL) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }
1102

1103
        if (qemu_driver == NULL) {
1104 1105
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("qemu state driver is not active"));
1106
            goto cleanup;
1107 1108
        }

J
Ján Tomko 已提交
1109
        cfg = virQEMUDriverGetConfig(qemu_driver);
1110
        if (conn->uri->path == NULL) {
1111 1112
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no QEMU URI path given, try %s"),
1113 1114
                           cfg->uri);
            goto cleanup;
1115 1116
        }

1117
        if (cfg->privileged) {
1118 1119
            if (STRNEQ(conn->uri->path, "/system") &&
                STRNEQ(conn->uri->path, "/session")) {
1120 1121 1122
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///system"),
                               conn->uri->path);
1123
                goto cleanup;
1124 1125
            }
        } else {
1126
            if (STRNEQ(conn->uri->path, "/session")) {
1127 1128 1129
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///session"),
                               conn->uri->path);
1130
                goto cleanup;
1131 1132
            }
        }
1133
    }
1134 1135 1136 1137

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

1138 1139
    conn->privateData = qemu_driver;

1140
    ret = VIR_DRV_OPEN_SUCCESS;
1141
 cleanup:
1142 1143
    virObjectUnref(cfg);
    return ret;
1144 1145
}

1146
static int qemuConnectClose(virConnectPtr conn)
1147
{
1148
    virQEMUDriverPtr driver = conn->privateData;
1149 1150

    /* Get rid of callbacks registered for this conn */
1151
    virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
1152 1153 1154 1155 1156 1157

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
1158 1159
/* Which features are supported by this driver? */
static int
1160
qemuConnectSupportsFeature(virConnectPtr conn, int feature)
D
Daniel Veillard 已提交
1161
{
1162 1163 1164
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

D
Daniel Veillard 已提交
1165
    switch (feature) {
1166
    case VIR_DRV_FEATURE_MIGRATION_V2:
1167
    case VIR_DRV_FEATURE_MIGRATION_V3:
1168
    case VIR_DRV_FEATURE_MIGRATION_P2P:
1169
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
1170
    case VIR_DRV_FEATURE_FD_PASSING:
1171
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
1172
    case VIR_DRV_FEATURE_XML_MIGRATABLE:
L
liguang 已提交
1173
    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
1174
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
1175 1176 1177
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
1178 1179 1180
    }
}

1181
static const char *qemuConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1182 1183 1184
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

1185
    return "QEMU";
1186 1187
}

1188

1189
static int qemuConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1190 1191 1192 1193 1194
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}

1195
static int qemuConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1196 1197 1198 1199 1200
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}

1201
static int qemuConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1202 1203 1204 1205
{
    return 1;
}

1206

1207
static int
1208 1209
kvmGetMaxVCPUs(void)
{
1210 1211
    int fd;
    int ret;
1212

1213
    if ((fd = open(KVM_DEVICE, O_RDONLY)) < 0) {
1214
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
1215
        return -1;
1216 1217
    }

1218
#ifdef KVM_CAP_MAX_VCPUS
1219 1220 1221
    /* 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;
1222
#endif /* KVM_CAP_MAX_VCPUS */
1223 1224 1225 1226 1227 1228 1229 1230 1231

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

1233
 cleanup:
1234
    VIR_FORCE_CLOSE(fd);
1235
    return ret;
1236 1237 1238
}


E
Eric Blake 已提交
1239
static char *
1240
qemuConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
E
Eric Blake 已提交
1241
{
1242
    virQEMUDriverPtr driver = conn->privateData;
1243
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
1244 1245 1246

    virCheckFlags(0, NULL);

1247 1248 1249
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

E
Eric Blake 已提交
1250
    if (!driver->hostsysinfo) {
1251 1252
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Host SMBIOS information is not available"));
E
Eric Blake 已提交
1253 1254 1255
        return NULL;
    }

1256 1257
    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
1258
    if (virBufferCheckError(&buf) < 0)
1259 1260
        return NULL;
    return virBufferContentAndReset(&buf);
E
Eric Blake 已提交
1261 1262
}

1263 1264 1265
static int
qemuConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type)
{
1266 1267 1268
    if (virConnectGetMaxVcpusEnsureACL(conn) < 0)
        return -1;

1269 1270 1271
    if (!type)
        return 16;

1272
    if (STRCASEEQ(type, "qemu"))
1273 1274
        return 16;

1275
    if (STRCASEEQ(type, "kvm"))
1276
        return kvmGetMaxVCPUs();
1277

1278
    if (STRCASEEQ(type, "kqemu"))
1279
        return 1;
1280

1281 1282
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unknown type '%s'"), type);
1283 1284 1285
    return -1;
}

1286

1287
static char *qemuConnectGetCapabilities(virConnectPtr conn) {
1288
    virQEMUDriverPtr driver = conn->privateData;
1289
    virCapsPtr caps = NULL;
1290
    char *xml = NULL;
1291

1292 1293 1294
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

1295
    if (!(caps = virQEMUDriverGetCapabilities(driver, true)))
1296
        goto cleanup;
1297

1298
    xml = virCapabilitiesFormatXML(caps);
1299
    virObjectUnref(caps);
1300

1301
 cleanup:
1302

1303
    return xml;
1304 1305 1306
}


1307
static int
1308 1309
qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
                   pid_t pid, int tid)
1310 1311
{
    char *proc;
D
Daniel P. Berrange 已提交
1312
    FILE *pidinfo;
1313
    unsigned long long usertime, systime;
1314
    long rss;
1315 1316
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
1317

1318 1319
    /* In general, we cannot assume pid_t fits in int; but /proc parsing
     * is specific to Linux where int works fine.  */
1320
    if (tid)
1321
        ret = virAsprintf(&proc, "/proc/%d/task/%d/stat", (int) pid, tid);
1322
    else
1323
        ret = virAsprintf(&proc, "/proc/%d/stat", (int) pid);
1324
    if (ret < 0)
D
Daniel P. Berrange 已提交
1325 1326 1327 1328
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
1329 1330 1331 1332
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
1333 1334
        if (vm_rss)
            *vm_rss = 0;
1335
        VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1336 1337
        return 0;
    }
1338
    VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1339

1340 1341 1342 1343 1344 1345
    /* 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 */
1346
               "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
1347 1348
               /* startstack -> processor */
               "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
1349
               &usertime, &systime, &rss, &cpu) != 4) {
1350
        VIR_FORCE_FCLOSE(pidinfo);
1351
        VIR_WARN("cannot parse process status data");
1352
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
1353 1354 1355 1356 1357 1358
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
N
Nehal J Wani 已提交
1359
     * So calculate thus....
D
Daniel P. Berrange 已提交
1360
     */
1361 1362 1363 1364 1365
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

1366 1367 1368 1369 1370 1371
    /* 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 已提交
1372

1373 1374

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

1377
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
1378 1379 1380 1381 1382

    return 0;
}


1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452
static int
qemuDomainHelperGetVcpus(virDomainObjPtr vm, virVcpuInfoPtr info, int maxinfo,
                         unsigned char *cpumaps, int maplen)
{
    int maxcpu, hostcpus;
    size_t i, v;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if ((hostcpus = nodeGetCPUCount()) < 0)
        return -1;

    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

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

    if (maxinfo >= 1) {
        if (info != NULL) {
            memset(info, 0, sizeof(*info) * maxinfo);
            for (i = 0; i < maxinfo; i++) {
                info[i].number = i;
                info[i].state = VIR_VCPU_RUNNING;

                if (priv->vcpupids != NULL &&
                    qemuGetProcessInfo(&(info[i].cpuTime),
                                       &(info[i].cpu),
                                       NULL,
                                       vm->pid,
                                       priv->vcpupids[i]) < 0) {
                    virReportSystemError(errno, "%s",
                                         _("cannot get vCPU placement & pCPU time"));
                    return -1;
                }
            }
        }

        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
            if (priv->vcpupids != NULL) {
                for (v = 0; v < maxinfo; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
                    virBitmapPtr map = NULL;
                    unsigned char *tmpmap = NULL;
                    int tmpmapLen = 0;

                    if (virProcessGetAffinity(priv->vcpupids[v],
                                              &map, maxcpu) < 0)
                        return -1;
                    virBitmapToData(map, &tmpmap, &tmpmapLen);
                    if (tmpmapLen > maplen)
                        tmpmapLen = maplen;
                    memcpy(cpumap, tmpmap, tmpmapLen);

                    VIR_FREE(tmpmap);
                    virBitmapFree(map);
                }
            } else {
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("cpu affinity is not available"));
                return -1;
            }
        }
    }
    return maxinfo;
}


1453
static virDomainPtr qemuDomainLookupByID(virConnectPtr conn,
1454 1455
                                         int id)
{
1456
    virQEMUDriverPtr driver = conn->privateData;
1457 1458 1459
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1460
    vm  = virDomainObjListFindByID(driver->domains, id);
1461 1462

    if (!vm) {
1463 1464
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), id);
1465
        goto cleanup;
1466 1467
    }

1468 1469 1470
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1471
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1472
    if (dom) dom->id = vm->def->id;
1473

1474
 cleanup:
1475
    if (vm)
1476
        virObjectUnlock(vm);
1477 1478
    return dom;
}
1479

1480
static virDomainPtr qemuDomainLookupByUUID(virConnectPtr conn,
1481 1482
                                           const unsigned char *uuid)
{
1483
    virQEMUDriverPtr driver = conn->privateData;
1484 1485
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1486

1487
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
1488

1489
    if (!vm) {
1490 1491
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
1492 1493
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1494
        goto cleanup;
1495 1496
    }

1497 1498 1499
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1500
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1501
    if (dom) dom->id = vm->def->id;
1502

1503
 cleanup:
1504
    if (vm)
1505
        virObjectUnlock(vm);
1506 1507
    return dom;
}
1508

1509
static virDomainPtr qemuDomainLookupByName(virConnectPtr conn,
1510 1511
                                           const char *name)
{
1512
    virQEMUDriverPtr driver = conn->privateData;
1513 1514
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1515

1516
    vm = virDomainObjListFindByName(driver->domains, name);
1517

1518
    if (!vm) {
1519 1520
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
1521
        goto cleanup;
1522 1523
    }

1524 1525 1526
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1527
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1528
    if (dom) dom->id = vm->def->id;
1529

1530
 cleanup:
1531
    if (vm)
1532
        virObjectUnlock(vm);
1533 1534 1535
    return dom;
}

1536 1537 1538 1539 1540 1541

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

1542
    if (!(obj = qemuDomObjFromDomain(dom)))
1543
        goto cleanup;
1544

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

1548 1549
    ret = virDomainObjIsActive(obj);

1550
 cleanup:
1551
    if (obj)
1552
        virObjectUnlock(obj);
1553 1554 1555 1556 1557 1558 1559 1560
    return ret;
}

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

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

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

1567 1568
    ret = obj->persistent;

1569
 cleanup:
1570
    if (obj)
1571
        virObjectUnlock(obj);
1572 1573 1574
    return ret;
}

1575 1576 1577 1578 1579
static int qemuDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

1580
    if (!(obj = qemuDomObjFromDomain(dom)))
1581
        goto cleanup;
1582

1583 1584 1585
    if (virDomainIsUpdatedEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

1586 1587
    ret = obj->updated;

1588
 cleanup:
1589
    if (obj)
1590
        virObjectUnlock(obj);
1591 1592
    return ret;
}
1593

1594 1595
static int qemuConnectGetVersion(virConnectPtr conn, unsigned long *version)
{
1596
    virQEMUDriverPtr driver = conn->privateData;
1597
    int ret = -1;
1598
    unsigned int qemuVersion = 0;
1599
    virCapsPtr caps = NULL;
1600

1601 1602 1603
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1604 1605 1606 1607
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (virQEMUCapsGetDefaultVersion(caps,
1608 1609
                                     driver->qemuCapsCache,
                                     &qemuVersion) < 0)
1610
        goto cleanup;
1611

1612
    *version = qemuVersion;
1613 1614
    ret = 0;

1615
 cleanup:
1616
    virObjectUnref(caps);
1617
    return ret;
D
Daniel P. Berrange 已提交
1618 1619
}

1620

1621
static char *qemuConnectGetHostname(virConnectPtr conn)
1622
{
1623 1624 1625
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1626 1627 1628 1629
    return virGetHostname();
}


1630 1631
static int qemuConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
1632
    virQEMUDriverPtr driver = conn->privateData;
1633
    int n;
1634

1635 1636 1637
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

1638 1639
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
1640

1641
    return n;
D
Daniel P. Berrange 已提交
1642
}
1643

1644 1645
static int qemuConnectNumOfDomains(virConnectPtr conn)
{
1646
    virQEMUDriverPtr driver = conn->privateData;
1647
    int n;
1648

1649 1650 1651
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1652 1653
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
1654

1655
    return n;
D
Daniel P. Berrange 已提交
1656
}
1657

1658 1659

static int
1660
qemuCanonicalizeMachine(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
1661
{
1662
    const char *canon;
1663

1664
    if (!(canon = virQEMUCapsGetCanonicalMachine(qemuCaps, def->os.machine)))
1665 1666 1667
        return 0;

    if (STRNEQ(canon, def->os.machine)) {
1668
        char *tmp;
1669
        if (VIR_STRDUP(tmp, canon) < 0)
1670 1671 1672 1673 1674 1675 1676 1677 1678
            return -1;
        VIR_FREE(def->os.machine);
        def->os.machine = tmp;
    }

    return 0;
}


1679 1680
static virDomainPtr qemuDomainCreateXML(virConnectPtr conn,
                                        const char *xml,
1681 1682
                                        unsigned int flags)
{
1683
    virQEMUDriverPtr driver = conn->privateData;
1684
    virDomainDefPtr def = NULL;
1685
    virDomainObjPtr vm = NULL;
1686
    virDomainPtr dom = NULL;
1687 1688
    virObjectEventPtr event = NULL;
    virObjectEventPtr event2 = NULL;
1689
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;
1690
    virQEMUCapsPtr qemuCaps = NULL;
1691
    virCapsPtr caps = NULL;
D
Daniel P. Berrange 已提交
1692

1693 1694
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_AUTODESTROY, NULL);
1695

1696 1697 1698
    if (flags & VIR_DOMAIN_START_PAUSED)
        start_flags |= VIR_QEMU_PROCESS_START_PAUSED;
    if (flags & VIR_DOMAIN_START_AUTODESTROY)
1699
        start_flags |= VIR_QEMU_PROCESS_START_AUTODESTROY;
1700

1701 1702
    virNWFilterReadLockFilterUpdates();

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

1706
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
1707
                                        QEMU_EXPECTED_VIRT_TYPES,
1708
                                        VIR_DOMAIN_XML_INACTIVE)))
1709
        goto cleanup;
1710

1711 1712 1713
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1714
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1715 1716
        goto cleanup;

1717
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
1718 1719
        goto cleanup;

1720
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
1721 1722
        goto cleanup;

1723
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
1724 1725
        goto cleanup;

1726
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1727
                                   driver->xmlopt,
1728 1729
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1730 1731 1732
        goto cleanup;

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

E
Eric Blake 已提交
1734 1735 1736 1737 1738
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) {
        qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
        goto cleanup;
    }
1739

1740 1741
    if (qemuProcessStart(conn, driver, vm, QEMU_ASYNC_JOB_NONE,
                         NULL, -1, NULL, NULL,
1742 1743
                         VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                         start_flags) < 0) {
1744
        virDomainAuditStart(vm, "booted", false);
E
Eric Blake 已提交
1745
        if (qemuDomainObjEndJob(driver, vm))
1746
            qemuDomainRemoveInactive(driver, vm);
1747
        vm = NULL;
1748
        goto cleanup;
D
Daniel P. Berrange 已提交
1749
    }
1750

1751
    event = virDomainEventLifecycleNewFromObj(vm,
1752 1753
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1754 1755 1756 1757 1758 1759
    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.  */
1760
        event2 = virDomainEventLifecycleNewFromObj(vm,
1761 1762 1763
                                          VIR_DOMAIN_EVENT_SUSPENDED,
                                          VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }
1764
    virDomainAuditStart(vm, "booted", true);
D
Daniel P. Berrange 已提交
1765

1766
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
E
Eric Blake 已提交
1767 1768
    if (dom)
        dom->id = vm->def->id;
1769

E
Eric Blake 已提交
1770
    if (!qemuDomainObjEndJob(driver, vm))
1771
        vm = NULL;
1772

1773
 cleanup:
1774
    virDomainDefFree(def);
1775
    if (vm)
1776
        virObjectUnlock(vm);
1777
    if (event) {
1778
        qemuDomainEventQueue(driver, event);
1779 1780 1781
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
1782
    virObjectUnref(caps);
1783
    virObjectUnref(qemuCaps);
1784
    virNWFilterUnlockFilterUpdates();
1785
    return dom;
D
Daniel P. Berrange 已提交
1786 1787 1788
}


1789 1790
static int qemuDomainSuspend(virDomainPtr dom)
{
1791
    virQEMUDriverPtr driver = dom->conn->privateData;
1792 1793
    virDomainObjPtr vm;
    int ret = -1;
1794
    virObjectEventPtr event = NULL;
1795
    qemuDomainObjPrivatePtr priv;
1796 1797
    virDomainPausedReason reason;
    int eventDetail;
1798
    int state;
1799
    virQEMUDriverConfigPtr cfg = NULL;
1800

1801 1802
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
1803

1804 1805 1806
    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
1807
    if (!virDomainObjIsActive(vm)) {
1808 1809
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1810
        goto cleanup;
D
Daniel P. Berrange 已提交
1811
    }
1812

1813
    cfg = virQEMUDriverGetConfig(driver);
1814 1815
    priv = vm->privateData;

1816
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_SUSPEND) < 0)
1817 1818 1819
        goto cleanup;

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

1825 1826 1827
    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) {
        reason = VIR_DOMAIN_PAUSED_MIGRATION;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED;
1828 1829 1830
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_SNAPSHOT) {
        reason = VIR_DOMAIN_PAUSED_SNAPSHOT;
        eventDetail = -1; /* don't create lifecycle events when doing snapshot */
1831 1832 1833 1834 1835
    } else {
        reason = VIR_DOMAIN_PAUSED_USER;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
    }

1836 1837 1838 1839 1840 1841
    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) {
1842
        if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) {
1843
            goto endjob;
1844
        }
1845 1846

        if (eventDetail >= 0) {
1847
            event = virDomainEventLifecycleNewFromObj(vm,
1848 1849 1850
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             eventDetail);
        }
D
Daniel P. Berrange 已提交
1851
    }
1852
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1853 1854
        goto endjob;
    ret = 0;
1855

1856
 endjob:
E
Eric Blake 已提交
1857
    if (!qemuDomainObjEndJob(driver, vm))
1858
        vm = NULL;
1859

1860
 cleanup:
1861
    if (vm)
1862
        virObjectUnlock(vm);
1863

1864
    if (event)
1865
        qemuDomainEventQueue(driver, event);
1866
    virObjectUnref(cfg);
1867
    return ret;
D
Daniel P. Berrange 已提交
1868 1869 1870
}


1871 1872
static int qemuDomainResume(virDomainPtr dom)
{
1873
    virQEMUDriverPtr driver = dom->conn->privateData;
1874 1875
    virDomainObjPtr vm;
    int ret = -1;
1876
    virObjectEventPtr event = NULL;
1877
    int state;
1878
    virQEMUDriverConfigPtr cfg = NULL;
1879
    virCapsPtr caps = NULL;
1880

1881 1882
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
1883

1884 1885
    cfg = virQEMUDriverGetConfig(driver);

1886 1887 1888
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
1892
    if (!virDomainObjIsActive(vm)) {
1893 1894
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1895
        goto endjob;
D
Daniel P. Berrange 已提交
1896
    }
1897 1898 1899 1900 1901 1902 1903

    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 已提交
1904
        if (qemuProcessStartCPUs(driver, vm, dom->conn,
1905 1906
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
1907
            if (virGetLastError() == NULL)
1908 1909
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resume operation failed"));
1910
            goto endjob;
1911
        }
1912
        event = virDomainEventLifecycleNewFromObj(vm,
1913 1914
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
1915
    }
1916 1917
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto endjob;
1918
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1919
        goto endjob;
1920 1921
    ret = 0;

1922
 endjob:
E
Eric Blake 已提交
1923
    if (!qemuDomainObjEndJob(driver, vm))
1924
        vm = NULL;
1925

1926
 cleanup:
1927
    if (vm)
1928
        virObjectUnlock(vm);
1929
    if (event)
1930
        qemuDomainEventQueue(driver, event);
1931
    virObjectUnref(caps);
1932
    virObjectUnref(cfg);
1933
    return ret;
D
Daniel P. Berrange 已提交
1934 1935
}

1936 1937
static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
{
1938
    virQEMUDriverPtr driver = dom->conn->privateData;
1939 1940
    virDomainObjPtr vm;
    int ret = -1;
1941
    qemuDomainObjPrivatePtr priv;
1942
    bool useAgent = false, agentRequested, acpiRequested;
1943
    bool isReboot = false;
1944
    bool agentForced;
1945
    int agentFlag = QEMU_AGENT_SHUTDOWN_POWERDOWN;
1946 1947 1948

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
1949

1950
    if (!(vm = qemuDomObjFromDomain(dom)))
1951
        goto cleanup;
1952

1953 1954 1955 1956 1957 1958 1959
    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");
    }

1960
    priv = vm->privateData;
1961 1962
    agentRequested = flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT;
    acpiRequested  = flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN;
1963

1964 1965
    /* Prefer agent unless we were requested to not to. */
    if (agentRequested || (!flags && priv->agent))
1966 1967
        useAgent = true;

1968
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1969 1970
        goto cleanup;

1971 1972 1973
    agentForced = agentRequested && !acpiRequested;
    if (!qemuDomainAgentAvailable(priv, agentForced)) {
        if (agentForced)
1974
            goto cleanup;
1975
        useAgent = false;
1976 1977
    }

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

D
Daniel P. Berrange 已提交
1981
    if (!virDomainObjIsActive(vm)) {
1982 1983
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1984
        goto endjob;
1985 1986
    }

1987
    if (useAgent) {
1988
        qemuDomainObjEnterAgent(vm);
1989
        ret = qemuAgentShutdown(priv->agent, agentFlag);
1990
        qemuDomainObjExitAgent(vm);
1991 1992 1993 1994 1995 1996 1997
    }

    /* 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))) {
1998
        qemuDomainSetFakeReboot(driver, vm, isReboot);
1999

2000 2001 2002 2003 2004 2005 2006
        /* Even if agent failed, we have to check if guest went away
         * by itself while our locks were down.  */
        if (useAgent && !virDomainObjIsActive(vm)) {
            ret = 0;
            goto endjob;
        }

2007 2008 2009 2010
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSystemPowerdown(priv->mon);
        qemuDomainObjExitMonitor(driver, vm);
    }
2011

2012
 endjob:
E
Eric Blake 已提交
2013
    if (!qemuDomainObjEndJob(driver, vm))
2014
        vm = NULL;
2015

2016
 cleanup:
2017
    if (vm)
2018
        virObjectUnlock(vm);
2019
    return ret;
2020 2021
}

2022 2023
static int qemuDomainShutdown(virDomainPtr dom)
{
2024 2025 2026
    return qemuDomainShutdownFlags(dom, 0);
}

2027

2028 2029 2030
static int
qemuDomainReboot(virDomainPtr dom, unsigned int flags)
{
2031
    virQEMUDriverPtr driver = dom->conn->privateData;
2032 2033 2034
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
2035
    bool useAgent = false;
2036 2037
    bool isReboot = true;
    int agentFlag = QEMU_AGENT_SHUTDOWN_REBOOT;
2038

2039
    virCheckFlags(VIR_DOMAIN_REBOOT_ACPI_POWER_BTN |
E
Eric Blake 已提交
2040
                  VIR_DOMAIN_REBOOT_GUEST_AGENT, -1);
2041

2042 2043 2044 2045 2046 2047 2048 2049
    /* 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;
    }

2050
    if (!(vm = qemuDomObjFromDomain(dom)))
2051 2052
        goto cleanup;

2053 2054 2055 2056 2057 2058 2059
    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");
    }

2060 2061
    priv = vm->privateData;

2062
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
2063 2064
        goto cleanup;

2065 2066
    if ((flags & VIR_DOMAIN_REBOOT_GUEST_AGENT) ||
        (!(flags & VIR_DOMAIN_REBOOT_ACPI_POWER_BTN) &&
2067 2068 2069
         priv->agent))
        useAgent = true;

2070 2071
    if (useAgent && !qemuDomainAgentAvailable(priv, true)) {
        goto cleanup;
2072
    } else {
2073
#if WITH_YAJL
2074 2075
        if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
            if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) {
2076 2077
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Reboot is not supported with this QEMU binary"));
2078 2079 2080 2081
                goto cleanup;
            }
        } else {
#endif
2082 2083
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Reboot is not supported without the JSON monitor"));
2084
            goto cleanup;
2085
#if WITH_YAJL
2086
        }
2087 2088
#endif
    }
2089

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

2093
    if (!virDomainObjIsActive(vm)) {
2094 2095
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2096 2097
        goto endjob;
    }
2098

2099
    if (useAgent) {
2100
        qemuDomainObjEnterAgent(vm);
2101
        ret = qemuAgentShutdown(priv->agent, agentFlag);
2102
        qemuDomainObjExitAgent(vm);
2103
    } else {
2104
        qemuDomainObjEnterMonitor(driver, vm);
2105
        ret = qemuMonitorSystemPowerdown(priv->mon);
2106
        qemuDomainObjExitMonitor(driver, vm);
2107

2108
        if (ret == 0)
2109
            qemuDomainSetFakeReboot(driver, vm, isReboot);
2110 2111
    }

2112
 endjob:
E
Eric Blake 已提交
2113
    if (!qemuDomainObjEndJob(driver, vm))
2114 2115
        vm = NULL;

2116
 cleanup:
2117
    if (vm)
2118
        virObjectUnlock(vm);
2119 2120 2121 2122
    return ret;
}


2123 2124 2125
static int
qemuDomainReset(virDomainPtr dom, unsigned int flags)
{
2126
    virQEMUDriverPtr driver = dom->conn->privateData;
2127 2128 2129 2130 2131 2132
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2133
    if (!(vm = qemuDomObjFromDomain(dom)))
2134 2135
        goto cleanup;

2136 2137 2138
    if (virDomainResetEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2139 2140 2141 2142
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
2143 2144
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2145 2146 2147 2148 2149 2150 2151 2152 2153 2154
        goto endjob;
    }

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

    priv->fakeReboot = false;

2155
 endjob:
E
Eric Blake 已提交
2156
    if (!qemuDomainObjEndJob(driver, vm))
2157 2158
        vm = NULL;

2159
 cleanup:
2160
    if (vm)
2161
        virObjectUnlock(vm);
2162 2163 2164 2165
    return ret;
}


2166
/* Count how many snapshots in a set are external snapshots or checkpoints.  */
2167 2168 2169 2170 2171 2172 2173 2174
static void
qemuDomainSnapshotCountExternal(void *payload,
                                const void *name ATTRIBUTE_UNUSED,
                                void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    int *count = data;

2175
    if (virDomainSnapshotIsExternal(snap))
2176 2177 2178
        (*count)++;
}

2179 2180 2181 2182
static int
qemuDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
2183
    virQEMUDriverPtr driver = dom->conn->privateData;
2184 2185
    virDomainObjPtr vm;
    int ret = -1;
2186
    virObjectEventPtr event = NULL;
2187
    qemuDomainObjPrivatePtr priv;
2188

2189
    virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1);
2190

2191 2192
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
2193

2194 2195
    priv = vm->privateData;

2196 2197 2198
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2199
    qemuDomainSetFakeReboot(driver, vm, false);
2200

2201 2202 2203 2204 2205 2206

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

2207 2208 2209 2210 2211
    /* 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
     */
2212
    if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
2213
        if (qemuProcessKill(vm, 0) < 0) {
2214
            priv->beingDestroyed = false;
2215
            goto cleanup;
2216
        }
2217
    } else {
2218
        if (qemuProcessKill(vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
2219
            priv->beingDestroyed = false;
2220
            goto cleanup;
2221
        }
2222
    }
2223

2224
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_DESTROY) < 0)
2225 2226
        goto cleanup;

2227 2228
    priv->beingDestroyed = false;

D
Daniel P. Berrange 已提交
2229
    if (!virDomainObjIsActive(vm)) {
2230 2231
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2232
        goto endjob;
2233
    }
2234

2235
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED, 0);
2236
    event = virDomainEventLifecycleNewFromObj(vm,
2237 2238
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
2239
    virDomainAuditStop(vm, "destroyed");
2240

2241
    if (!vm->persistent) {
E
Eric Blake 已提交
2242
        if (qemuDomainObjEndJob(driver, vm))
2243
            qemuDomainRemoveInactive(driver, vm);
2244 2245
        vm = NULL;
    }
2246 2247
    ret = 0;

2248
 endjob:
E
Eric Blake 已提交
2249
    if (vm && !qemuDomainObjEndJob(driver, vm))
2250
        vm = NULL;
2251

2252
 cleanup:
2253
    if (vm)
2254
        virObjectUnlock(vm);
2255 2256
    if (event)
        qemuDomainEventQueue(driver, event);
2257
    return ret;
D
Daniel P. Berrange 已提交
2258 2259
}

2260 2261 2262 2263 2264
static int
qemuDomainDestroy(virDomainPtr dom)
{
    return qemuDomainDestroyFlags(dom, 0);
}
D
Daniel P. Berrange 已提交
2265

2266
static char *qemuDomainGetOSType(virDomainPtr dom) {
2267 2268
    virDomainObjPtr vm;
    char *type = NULL;
2269

2270
    if (!(vm = qemuDomObjFromDomain(dom)))
2271
        goto cleanup;
2272

2273 2274 2275
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2276
    ignore_value(VIR_STRDUP(type, vm->def->os.type));
2277

2278
 cleanup:
2279
    if (vm)
2280
        virObjectUnlock(vm);
2281 2282 2283
    return type;
}

2284
/* Returns max memory in kb, 0 if error */
2285 2286 2287
static unsigned long long
qemuDomainGetMaxMemory(virDomainPtr dom)
{
2288
    virDomainObjPtr vm;
2289
    unsigned long long ret = 0;
2290

2291
    if (!(vm = qemuDomObjFromDomain(dom)))
2292
        goto cleanup;
2293

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

2297
    ret = vm->def->mem.max_balloon;
2298

2299
 cleanup:
2300
    if (vm)
2301
        virObjectUnlock(vm);
2302
    return ret;
2303 2304
}

2305
static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
2306 2307
                                    unsigned int flags)
{
2308
    virQEMUDriverPtr driver = dom->conn->privateData;
2309
    qemuDomainObjPrivatePtr priv;
2310
    virDomainObjPtr vm;
2311
    virDomainDefPtr persistentDef = NULL;
2312
    int ret = -1, r;
2313
    virQEMUDriverConfigPtr cfg = NULL;
2314
    virCapsPtr caps = NULL;
2315

2316 2317
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
2318
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
2319

2320
    if (!(vm = qemuDomObjFromDomain(dom)))
2321
        goto cleanup;
2322

2323 2324
    cfg = virQEMUDriverGetConfig(driver);

2325 2326 2327
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

2331 2332
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto endjob;
2333
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
2334
                                        &persistentDef) < 0)
2335
        goto endjob;
2336

2337 2338 2339
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */

2340
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2341 2342 2343
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot resize the maximum memory on an "
                             "active domain"));
2344
            goto endjob;
2345
        }
2346

2347
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2348 2349
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
2350 2351 2352
            persistentDef->mem.max_balloon = newmem;
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
2353
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
2354 2355 2356
            goto endjob;
        }

2357 2358
    } else {
        /* resize the current memory */
2359
        unsigned long oldmax = 0;
2360

2361 2362 2363 2364 2365 2366 2367 2368
        if (flags & VIR_DOMAIN_AFFECT_LIVE)
            oldmax = vm->def->mem.max_balloon;
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
            if (!oldmax || oldmax > persistentDef->mem.max_balloon)
                oldmax = persistentDef->mem.max_balloon;
        }

        if (newmem > oldmax) {
2369 2370
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
2371 2372 2373
            goto endjob;
        }

2374
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2375
            priv = vm->privateData;
2376
            qemuDomainObjEnterMonitor(driver, vm);
2377
            r = qemuMonitorSetBalloon(priv->mon, newmem);
2378
            qemuDomainObjExitMonitor(driver, vm);
2379 2380
            virDomainAuditMemory(vm, vm->def->mem.cur_balloon, newmem, "update",
                                 r == 1);
2381 2382 2383 2384 2385
            if (r < 0)
                goto endjob;

            /* Lack of balloon support is a fatal error */
            if (r == 0) {
2386 2387 2388
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Unable to change memory of active domain without "
                                 "the balloon device and guest OS balloon driver"));
2389 2390 2391 2392
                goto endjob;
            }
        }

2393
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2394
            sa_assert(persistentDef);
2395
            persistentDef->mem.cur_balloon = newmem;
2396
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
2397 2398
            goto endjob;
        }
2399
    }
2400

2401
    ret = 0;
2402
 endjob:
E
Eric Blake 已提交
2403
    if (!qemuDomainObjEndJob(driver, vm))
2404
        vm = NULL;
2405

2406
 cleanup:
2407
    if (vm)
2408
        virObjectUnlock(vm);
2409
    virObjectUnref(caps);
2410
    virObjectUnref(cfg);
2411
    return ret;
2412 2413
}

2414
static int qemuDomainSetMemory(virDomainPtr dom, unsigned long newmem)
2415
{
2416
    return qemuDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
2417 2418
}

2419
static int qemuDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
2420
{
2421
    return qemuDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
2422 2423
}

2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462
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);
2463
        if (r < 0) {
2464 2465
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("unable to set balloon driver collection period"));
2466 2467 2468 2469 2470 2471
            goto endjob;
        }

        vm->def->memballoon->period = period;
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
            goto endjob;
2472 2473 2474 2475 2476 2477 2478 2479 2480 2481
    }

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

    ret = 0;
2482
 endjob:
E
Eric Blake 已提交
2483
    if (!qemuDomainObjEndJob(driver, vm))
2484 2485
        vm = NULL;

2486
 cleanup:
2487 2488 2489 2490 2491 2492 2493
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
}

2494 2495
static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
{
2496
    virQEMUDriverPtr driver = domain->conn->privateData;
2497 2498 2499 2500 2501 2502
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2503 2504
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
2505

2506 2507 2508
    if (virDomainInjectNMIEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

2509
    if (!virDomainObjIsActive(vm)) {
2510 2511
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2512 2513 2514 2515 2516
        goto cleanup;
    }

    priv = vm->privateData;

2517
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2518
        goto cleanup;
2519 2520

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

2526
    qemuDomainObjEnterMonitor(driver, vm);
2527
    ret = qemuMonitorInjectNMI(priv->mon);
2528
    qemuDomainObjExitMonitor(driver, vm);
2529

2530
 endjob:
E
Eric Blake 已提交
2531
    if (!qemuDomainObjEndJob(driver, vm))
2532 2533
        vm = NULL;

2534
 cleanup:
2535
    if (vm)
2536
        virObjectUnlock(vm);
2537 2538 2539
    return ret;
}

2540 2541 2542 2543 2544 2545 2546
static int qemuDomainSendKey(virDomainPtr domain,
                             unsigned int codeset,
                             unsigned int holdtime,
                             unsigned int *keycodes,
                             int nkeycodes,
                             unsigned int flags)
{
2547
    virQEMUDriverPtr driver = domain->conn->privateData;
2548 2549 2550 2551 2552 2553
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2554 2555
    /* translate the keycode to RFB for qemu driver */
    if (codeset != VIR_KEYCODE_SET_RFB) {
2556
        size_t i;
2557 2558 2559
        int keycode;

        for (i = 0; i < nkeycodes; i++) {
2560
            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_RFB,
2561 2562
                                               keycodes[i]);
            if (keycode < 0) {
2563 2564 2565 2566
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot translate keycode %u of %s codeset to rfb keycode"),
                               keycodes[i],
                               virKeycodeSetTypeToString(codeset));
2567 2568 2569 2570 2571 2572
                return -1;
            }
            keycodes[i] = keycode;
        }
    }

2573
    if (!(vm = qemuDomObjFromDomain(domain)))
2574 2575 2576 2577
        goto cleanup;

    priv = vm->privateData;

2578 2579 2580
    if (virDomainSendKeyEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

2581
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2582 2583 2584
        goto cleanup;

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

2590
    qemuDomainObjEnterMonitor(driver, vm);
2591
    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
2592
    qemuDomainObjExitMonitor(driver, vm);
2593

2594
 endjob:
E
Eric Blake 已提交
2595
    if (!qemuDomainObjEndJob(driver, vm))
2596 2597
        vm = NULL;

2598
 cleanup:
2599
    if (vm)
2600
        virObjectUnlock(vm);
2601 2602 2603
    return ret;
}

2604 2605
static int qemuDomainGetInfo(virDomainPtr dom,
                             virDomainInfoPtr info)
2606
{
2607
    virQEMUDriverPtr driver = dom->conn->privateData;
2608 2609
    virDomainObjPtr vm;
    int ret = -1;
2610
    int err;
2611
    unsigned long long balloon;
2612

2613
    if (!(vm = qemuDomObjFromDomain(dom)))
2614
        goto cleanup;
D
Daniel P. Berrange 已提交
2615

2616 2617 2618
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
2621
    if (!virDomainObjIsActive(vm)) {
2622
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2623
    } else {
2624
        if (qemuGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) {
2625 2626
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("cannot read cputime for domain"));
2627
            goto cleanup;
D
Daniel P. Berrange 已提交
2628 2629 2630
        }
    }

2631
    info->maxMem = vm->def->mem.max_balloon;
2632

D
Daniel P. Berrange 已提交
2633
    if (virDomainObjIsActive(vm)) {
2634
        qemuDomainObjPrivatePtr priv = vm->privateData;
2635 2636 2637

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
2638
            info->memory = vm->def->mem.max_balloon;
2639
        } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) {
2640
            info->memory = vm->def->mem.cur_balloon;
2641
        } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
2642
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
2643
                goto cleanup;
2644
            if (!virDomainObjIsActive(vm)) {
2645
                err = 0;
2646
            } else {
2647
                qemuDomainObjEnterMonitor(driver, vm);
2648
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
2649
                qemuDomainObjExitMonitor(driver, vm);
2650
            }
E
Eric Blake 已提交
2651
            if (!qemuDomainObjEndJob(driver, vm)) {
2652
                vm = NULL;
2653 2654 2655
                goto cleanup;
            }

2656 2657 2658 2659 2660 2661 2662
            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) {
2663
                /* Balloon not supported, so maxmem is always the allocation */
2664
                info->memory = vm->def->mem.max_balloon;
2665
            } else {
2666
                info->memory = balloon;
2667
            }
2668
        } else {
2669
            info->memory = vm->def->mem.cur_balloon;
2670
        }
2671
    } else {
2672
        info->memory = 0;
2673 2674
    }

2675
    info->nrVirtCpu = vm->def->vcpus;
2676 2677
    ret = 0;

2678
 cleanup:
2679
    if (vm)
2680
        virObjectUnlock(vm);
2681
    return ret;
D
Daniel P. Berrange 已提交
2682 2683
}

2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694
static int
qemuDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

2695
    if (!(vm = qemuDomObjFromDomain(dom)))
2696 2697
        goto cleanup;

2698 2699 2700
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
2701
    *state = virDomainObjGetState(vm, reason);
2702 2703
    ret = 0;

2704
 cleanup:
2705
    if (vm)
2706
        virObjectUnlock(vm);
2707 2708 2709
    return ret;
}

2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720
static int
qemuDomainGetControlInfo(virDomainPtr dom,
                          virDomainControlInfoPtr info,
                          unsigned int flags)
{
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

2721
    if (!(vm = qemuDomObjFromDomain(dom)))
2722 2723
        goto cleanup;

2724 2725 2726
    if (virDomainGetControlInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2727
    if (!virDomainObjIsActive(vm)) {
2728 2729
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2730 2731 2732 2733 2734 2735 2736 2737 2738
        goto cleanup;
    }

    priv = vm->privateData;

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

    if (priv->monError) {
        info->state = VIR_DOMAIN_CONTROL_ERROR;
2739
    } else if (priv->job.active) {
J
Jiri Denemark 已提交
2740 2741 2742
        if (virTimeMillisNow(&info->stateTime) < 0)
            goto cleanup;
        if (priv->job.current) {
2743
            info->state = VIR_DOMAIN_CONTROL_JOB;
J
Jiri Denemark 已提交
2744
            info->stateTime -= priv->job.current->started;
2745 2746 2747 2748 2749 2750 2751 2752 2753 2754
        } else {
            info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
            info->stateTime -= priv->monStart;
        }
    } else {
        info->state = VIR_DOMAIN_CONTROL_OK;
    }

    ret = 0;

2755
 cleanup:
2756
    if (vm)
2757
        virObjectUnlock(vm);
2758 2759 2760
    return ret;
}

D
Daniel P. Berrange 已提交
2761

2762 2763 2764 2765 2766 2767
/* 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
2768

2769
verify(sizeof(QEMU_SAVE_MAGIC) == sizeof(QEMU_SAVE_PARTIAL));
E
Eric Blake 已提交
2770

2771
typedef enum {
2772 2773 2774
    QEMU_SAVE_FORMAT_RAW = 0,
    QEMU_SAVE_FORMAT_GZIP = 1,
    QEMU_SAVE_FORMAT_BZIP2 = 2,
2775 2776
    /*
     * Deprecated by xz and never used as part of a release
2777
     * QEMU_SAVE_FORMAT_LZMA
2778
     */
2779 2780
    QEMU_SAVE_FORMAT_XZ = 3,
    QEMU_SAVE_FORMAT_LZOP = 4,
2781 2782 2783
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2784

2785
    QEMU_SAVE_FORMAT_LAST
2786
} virQEMUSaveFormat;
2787

2788 2789
VIR_ENUM_DECL(qemuSaveCompression)
VIR_ENUM_IMPL(qemuSaveCompression, QEMU_SAVE_FORMAT_LAST,
2790 2791 2792
              "raw",
              "gzip",
              "bzip2",
2793 2794
              "xz",
              "lzop")
2795

2796 2797 2798 2799 2800 2801 2802
VIR_ENUM_DECL(qemuDumpFormat)
VIR_ENUM_IMPL(qemuDumpFormat, VIR_DOMAIN_CORE_DUMP_FORMAT_LAST,
              "elf",
              "kdump-zlib",
              "kdump-lzo",
              "kdump-snappy")

2803 2804 2805
typedef struct _virQEMUSaveHeader virQEMUSaveHeader;
typedef virQEMUSaveHeader *virQEMUSaveHeaderPtr;
struct _virQEMUSaveHeader {
2806
    char magic[sizeof(QEMU_SAVE_MAGIC)-1];
2807 2808 2809 2810 2811
    uint32_t version;
    uint32_t xml_len;
    uint32_t was_running;
    uint32_t compressed;
    uint32_t unused[15];
2812 2813
};

2814
static inline void
2815 2816
bswap_header(virQEMUSaveHeaderPtr hdr)
{
2817 2818 2819 2820 2821 2822 2823
    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);
}


2824
/* return -errno on failure, or 0 on success */
E
Eric Blake 已提交
2825
static int
2826
qemuDomainSaveHeader(int fd, const char *path, const char *xml,
2827
                     virQEMUSaveHeaderPtr header)
E
Eric Blake 已提交
2828
{
2829 2830
    int ret = 0;

E
Eric Blake 已提交
2831
    if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
2832
        ret = -errno;
2833 2834 2835
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write header to domain save file '%s'"),
                       path);
2836 2837 2838
        goto endjob;
    }

E
Eric Blake 已提交
2839
    if (safewrite(fd, xml, header->xml_len) != header->xml_len) {
2840
        ret = -errno;
2841 2842
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write xml to '%s'"), path);
2843 2844
        goto endjob;
    }
2845
 endjob:
2846 2847 2848
    return ret;
}

2849
/* Given a virQEMUSaveFormat compression level, return the name
2850 2851 2852 2853
 * of the program to run, or NULL if no program is needed.  */
static const char *
qemuCompressProgramName(int compress)
{
2854 2855
    return (compress == QEMU_SAVE_FORMAT_RAW ? NULL :
            qemuSaveCompressionTypeToString(compress));
2856 2857
}

2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884
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 已提交
2885
/* Internal function to properly create or open existing files, with
2886
 * ownership affected by qemu driver setup and domain DAC label.  */
E
Eric Blake 已提交
2887
static int
2888 2889 2890
qemuOpenFile(virQEMUDriverPtr driver,
             virDomainObjPtr vm,
             const char *path, int oflags,
E
Eric Blake 已提交
2891
             bool *needUnlink, bool *bypassSecurityDriver)
2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904
{
    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 &&
2905
        seclabel->label != NULL &&
2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920
        (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 已提交
2921 2922 2923 2924 2925
{
    struct stat sb;
    bool is_reg = true;
    bool need_unlink = false;
    bool bypass_security = false;
L
Laine Stump 已提交
2926
    unsigned int vfoflags = 0;
E
Eric Blake 已提交
2927
    int fd = -1;
2928
    int path_shared = virFileIsSharedFS(path);
2929 2930
    uid_t uid = geteuid();
    gid_t gid = getegid();
E
Eric Blake 已提交
2931 2932 2933 2934 2935 2936

    /* 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;
2937 2938 2939

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

E
Eric Blake 已提交
2943 2944 2945 2946 2947
        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 */
2948
            if (is_reg && !dynamicOwnership) {
E
Eric Blake 已提交
2949 2950 2951 2952 2953 2954 2955 2956
                uid = sb.st_uid;
                gid = sb.st_gid;
            }
        }
    }

    /* First try creating the file as root */
    if (!is_reg) {
2957 2958 2959
        if ((fd = open(path, oflags & ~O_CREAT)) < 0) {
            fd = -errno;
            goto error;
E
Eric Blake 已提交
2960 2961
        }
    } else {
L
Laine Stump 已提交
2962 2963
        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
E
Eric Blake 已提交
2964 2965 2966
            /* 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
2967
               qemu user is non-root, just set a flag to
E
Eric Blake 已提交
2968 2969
               bypass security driver shenanigans, and retry the operation
               after doing setuid to qemu user */
2970
            if ((fd != -EACCES && fd != -EPERM) || fallback_uid == geteuid())
2971
                goto error;
E
Eric Blake 已提交
2972 2973

            /* On Linux we can also verify the FS-type of the directory. */
2974
            switch (path_shared) {
E
Eric Blake 已提交
2975
                case 1:
2976 2977 2978 2979
                    /* it was on a network share, so we'll continue
                     * as outlined above
                     */
                    break;
E
Eric Blake 已提交
2980 2981

                case -1:
2982 2983 2984 2985 2986 2987 2988
                    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 已提交
2989 2990 2991

                case 0:
                default:
2992 2993
                    /* local file - log the error returned by virFileOpenAs */
                    goto error;
E
Eric Blake 已提交
2994 2995
            }

2996
            /* Retry creating the file as qemu user */
E
Eric Blake 已提交
2997 2998 2999

            if ((fd = virFileOpenAs(path, oflags,
                                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
3000
                                    fallback_uid, fallback_gid,
L
Laine Stump 已提交
3001
                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
3002 3003 3004
                virReportSystemError(-fd, oflags & O_CREAT
                                     ? _("Error from child process creating '%s'")
                                     : _("Error from child process opening '%s'"),
E
Eric Blake 已提交
3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015
                                     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;
        }
    }
3016
 cleanup:
E
Eric Blake 已提交
3017 3018 3019 3020 3021
    if (needUnlink)
        *needUnlink = need_unlink;
    if (bypassSecurityDriver)
        *bypassSecurityDriver = bypass_security;
    return fd;
3022

3023
 error:
3024 3025 3026 3027 3028
    virReportSystemError(-fd, oflags & O_CREAT
                         ? _("Failed to create file '%s'")
                         : _("Failed to open file '%s'"),
                         path);
    goto cleanup;
E
Eric Blake 已提交
3029 3030
}

3031 3032 3033
/* 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 */
3034
static int
3035
qemuDomainSaveMemory(virQEMUDriverPtr driver,
3036 3037
                     virDomainObjPtr vm,
                     const char *path,
3038
                     const char *domXML,
3039 3040 3041
                     int compressed,
                     bool was_running,
                     unsigned int flags,
3042
                     qemuDomainAsyncJob asyncJob)
3043
{
3044
    virQEMUSaveHeader header;
3045
    bool bypassSecurityDriver = false;
E
Eric Blake 已提交
3046
    bool needUnlink = false;
3047
    int ret = -1;
3048
    int fd = -1;
3049
    int directFlag = 0;
J
Jiri Denemark 已提交
3050
    virFileWrapperFdPtr wrapperFd = NULL;
3051
    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
3052 3053 3054
    unsigned long long pad;
    unsigned long long offset;
    size_t len;
3055
    char *xml = NULL;
3056

3057
    memset(&header, 0, sizeof(header));
3058 3059
    memcpy(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic));
    header.version = QEMU_SAVE_VERSION;
3060
    header.was_running = was_running ? 1 : 0;
3061

3062
    header.compressed = compressed;
3063

3064
    len = strlen(domXML) + 1;
3065 3066 3067 3068 3069 3070 3071
    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
N
Nehal J Wani 已提交
3072
     * slightly larger XML, so we add a minimum padding prior to
3073 3074 3075 3076 3077
     * rounding out to page boundaries.
     */
    pad = 1024;
    pad += (QEMU_MONITOR_MIGRATE_TO_FILE_BS -
            ((offset + pad) % QEMU_MONITOR_MIGRATE_TO_FILE_BS));
3078
    if (VIR_ALLOC_N(xml, len + pad) < 0)
3079
        goto cleanup;
3080 3081
    strcpy(xml, domXML);

3082 3083
    offset += pad;
    header.xml_len = len;
3084

3085
    /* Obtain the file handle.  */
3086 3087
    if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
3088 3089
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
3090 3091
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
E
Eric Blake 已提交
3092
            goto cleanup;
3093
        }
3094
    }
3095 3096
    fd = qemuOpenFile(driver, vm, path,
                      O_WRONLY | O_TRUNC | O_CREAT | directFlag,
E
Eric Blake 已提交
3097 3098
                      &needUnlink, &bypassSecurityDriver);
    if (fd < 0)
3099 3100
        goto cleanup;

3101 3102 3103
    if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def, fd) < 0)
        goto cleanup;

3104
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
3105
        goto cleanup;
3106

3107
    /* Write header to file, followed by XML */
3108 3109
    if (qemuDomainSaveHeader(fd, path, xml, &header) < 0)
        goto cleanup;
3110

3111
    /* Perform the migration */
3112
    if (qemuMigrationToFile(driver, vm, fd, offset, path,
3113
                            qemuCompressProgramName(compressed),
E
Eric Blake 已提交
3114
                            bypassSecurityDriver,
3115 3116
                            asyncJob) < 0)
        goto cleanup;
E
Eric Blake 已提交
3117

3118 3119 3120 3121 3122 3123 3124 3125
    /* 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);
3126
        goto cleanup;
E
Eric Blake 已提交
3127
    }
3128

3129
    if (virFileWrapperFdClose(wrapperFd) < 0)
3130 3131
        goto cleanup;

3132
    if ((fd = qemuOpenFile(driver, vm, path, O_WRONLY, NULL, NULL)) < 0)
3133
        goto cleanup;
3134

3135
    memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic));
3136

E
Eric Blake 已提交
3137 3138
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        virReportSystemError(errno, _("unable to write %s"), path);
3139
        goto cleanup;
E
Eric Blake 已提交
3140
    }
3141

3142 3143
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
3144
        goto cleanup;
3145 3146
    }

3147 3148
    ret = 0;

3149
 cleanup:
3150 3151
    VIR_FORCE_CLOSE(fd);
    virFileWrapperFdFree(wrapperFd);
3152
    VIR_FREE(xml);
3153 3154 3155 3156 3157 3158 3159

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

    return ret;
}

3160
/* The vm must be active + locked. Vm will be unlocked and
3161 3162 3163 3164 3165
 * 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
3166
qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
3167 3168 3169 3170 3171 3172 3173
                       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;
3174
    virObjectEventPtr event = NULL;
3175
    qemuDomainObjPrivatePtr priv = vm->privateData;
3176 3177 3178 3179
    virCapsPtr caps;

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

3181
    if (!qemuMigrationIsAllowed(driver, vm, vm->def, false, false))
3182 3183
        goto cleanup;

3184 3185
    if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_SAVE) < 0)
        goto cleanup;
3186

3187 3188 3189 3190 3191 3192
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
        goto endjob;
    }

J
Jiri Denemark 已提交
3193
    priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;
3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221

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

3222
        if (!(def = virDomainDefParseString(xmlin, caps, driver->xmlopt,
3223 3224 3225 3226
                                            QEMU_EXPECTED_VIRT_TYPES,
                                            VIR_DOMAIN_XML_INACTIVE))) {
            goto endjob;
        }
3227
        if (!qemuDomainDefCheckABIStability(driver, vm->def, def)) {
3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245
            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;

3246
    /* Shut it down */
3247
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED, 0);
3248
    virDomainAuditStop(vm, "saved");
3249
    event = virDomainEventLifecycleNewFromObj(vm,
3250 3251
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
3252
    if (!vm->persistent) {
3253
        if (qemuDomainObjEndAsyncJob(driver, vm) > 0)
3254
            qemuDomainRemoveInactive(driver, vm);
3255 3256
        vm = NULL;
    }
3257

3258
 endjob:
3259
    if (vm) {
3260
        if (ret != 0) {
3261
            if (was_running && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
3262
                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
3263 3264
                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED,
                                          QEMU_ASYNC_JOB_SAVE);
3265
                if (rc < 0) {
3266
                    VIR_WARN("Unable to resume guest CPUs after save failure");
3267
                    event = virDomainEventLifecycleNewFromObj(vm,
3268 3269 3270
                                                     VIR_DOMAIN_EVENT_SUSPENDED,
                                                     VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
                }
3271
            }
3272
        }
3273
        if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3274
            vm = NULL;
3275
    }
3276

3277
 cleanup:
3278
    VIR_FREE(xml);
3279 3280
    if (event)
        qemuDomainEventQueue(driver, event);
3281
    if (vm)
3282
        virObjectUnlock(vm);
3283
    virObjectUnref(caps);
3284
    return ret;
D
Daniel P. Berrange 已提交
3285 3286
}

3287
/* Returns true if a compression program is available in PATH */
3288 3289
static bool
qemuCompressProgramAvailable(virQEMUSaveFormat compress)
3290
{
3291
    char *path;
3292

3293
    if (compress == QEMU_SAVE_FORMAT_RAW)
3294
        return true;
3295 3296

    if (!(path = virFindFileInPath(qemuSaveCompressionTypeToString(compress))))
3297
        return false;
3298 3299

    VIR_FREE(path);
3300 3301 3302
    return true;
}

3303 3304 3305
static int
qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                    unsigned int flags)
3306
{
3307
    virQEMUDriverPtr driver = dom->conn->privateData;
3308
    int compressed = QEMU_SAVE_FORMAT_RAW;
3309 3310
    int ret = -1;
    virDomainObjPtr vm = NULL;
3311
    virQEMUDriverConfigPtr cfg = NULL;
3312

3313 3314 3315
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3316

3317
    cfg = virQEMUDriverGetConfig(driver);
3318
    if (cfg->saveImageFormat) {
3319
        compressed = qemuSaveCompressionTypeFromString(cfg->saveImageFormat);
3320
        if (compressed < 0) {
3321 3322 3323
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Invalid save image format specified "
                             "in configuration file"));
3324
            goto cleanup;
3325
        }
3326
        if (!qemuCompressProgramAvailable(compressed)) {
3327 3328 3329
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Compression program for image format "
                             "in configuration file isn't available"));
3330
            goto cleanup;
3331
        }
3332 3333
    }

3334
    if (!(vm = qemuDomObjFromDomain(dom)))
3335 3336
        goto cleanup;

3337 3338 3339
    if (virDomainSaveFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3340
    if (!virDomainObjIsActive(vm)) {
3341 3342
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3343 3344 3345
        goto cleanup;
    }

3346
    ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
3347
                                 dxml, flags);
3348
    vm = NULL;
3349

3350
 cleanup:
3351
    if (vm)
3352
        virObjectUnlock(vm);
3353
    virObjectUnref(cfg);
3354
    return ret;
3355 3356
}

3357 3358 3359 3360 3361 3362
static int
qemuDomainSave(virDomainPtr dom, const char *path)
{
    return qemuDomainSaveFlags(dom, path, NULL, 0);
}

3363
static char *
3364 3365
qemuDomainManagedSavePath(virQEMUDriverPtr driver, virDomainObjPtr vm)
{
3366
    char *ret;
3367
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3368

3369 3370
    if (virAsprintf(&ret, "%s/%s.save", cfg->saveDir, vm->def->name) < 0) {
        virObjectUnref(cfg);
3371
        return NULL;
3372 3373
    }

3374
    virObjectUnref(cfg);
3375
    return ret;
3376 3377 3378 3379 3380
}

static int
qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
3381
    virQEMUDriverPtr driver = dom->conn->privateData;
3382 3383
    virQEMUDriverConfigPtr cfg = NULL;
    int compressed = QEMU_SAVE_FORMAT_RAW;
3384
    virDomainObjPtr vm;
3385 3386 3387
    char *name = NULL;
    int ret = -1;

3388 3389 3390
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3391

3392
    if (!(vm = qemuDomObjFromDomain(dom)))
3393
        return -1;
3394

3395 3396 3397
    if (virDomainManagedSaveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3398
    if (!virDomainObjIsActive(vm)) {
3399 3400
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3401 3402
        goto cleanup;
    }
3403
    if (!vm->persistent) {
3404 3405
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
3406 3407
        goto cleanup;
    }
3408

3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425
    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;
        }
    }

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

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

3431
    if ((ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
3432 3433 3434
                                      NULL, flags)) == 0)
        vm->hasManagedSave = true;

3435
    vm = NULL;
3436

3437
 cleanup:
3438
    if (vm)
3439
        virObjectUnlock(vm);
3440
    VIR_FREE(name);
3441
    virObjectUnref(cfg);
3442 3443

    return ret;
3444 3445
}

3446 3447
static int
qemuDomainManagedSaveLoad(virDomainObjPtr vm,
3448 3449
                          void *opaque)
{
3450
    virQEMUDriverPtr driver = opaque;
3451
    char *name;
3452
    int ret = -1;
3453

3454
    virObjectLock(vm);
3455 3456 3457 3458 3459 3460

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

    vm->hasManagedSave = virFileExists(name);

3461
    ret = 0;
3462
 cleanup:
3463
    virObjectUnlock(vm);
3464
    VIR_FREE(name);
3465
    return ret;
3466 3467
}

3468

3469 3470 3471 3472
static int
qemuDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
3473
    int ret = -1;
3474

3475
    virCheckFlags(0, -1);
3476

3477 3478
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
3479

3480 3481 3482
    if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3483
    ret = vm->hasManagedSave;
3484

3485
 cleanup:
3486
    virObjectUnlock(vm);
3487 3488 3489 3490 3491 3492
    return ret;
}

static int
qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
3493
    virQEMUDriverPtr driver = dom->conn->privateData;
3494
    virDomainObjPtr vm;
3495 3496 3497
    int ret = -1;
    char *name = NULL;

3498
    virCheckFlags(0, -1);
3499

3500
    if (!(vm = qemuDomObjFromDomain(dom)))
3501
        return -1;
3502

3503 3504 3505
    if (virDomainManagedSaveRemoveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

3509 3510 3511 3512 3513 3514 3515
    if (unlink(name) < 0) {
        virReportSystemError(errno,
                             _("Failed to remove managed save file '%s'"),
                             name);
        goto cleanup;
    }

3516
    vm->hasManagedSave = false;
3517
    ret = 0;
3518

3519
 cleanup:
3520
    VIR_FREE(name);
3521
    virObjectUnlock(vm);
3522 3523
    return ret;
}
D
Daniel P. Berrange 已提交
3524

3525
static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
3526
                        int fd, qemuDomainAsyncJob asyncJob,
3527
                        const char *dumpformat)
3528 3529 3530 3531
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

3532
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
3533
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3534
                       _("dump-guest-memory is not supported"));
3535 3536 3537 3538 3539 3540 3541
        return -1;
    }

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

J
Jiri Denemark 已提交
3542
    VIR_FREE(priv->job.current);
3543 3544 3545 3546 3547
    priv->job.dump_memory_only = true;

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

3548 3549 3550 3551 3552
    if (dumpformat) {
        ret = qemuMonitorGetDumpGuestMemoryCapability(priv->mon, dumpformat);

        if (ret <= 0) {
            virReportError(VIR_ERR_INVALID_ARG,
3553 3554 3555
                           _("unsupported dumpformat '%s' "
                             "for this QEMU binary"),
                           dumpformat);
3556 3557 3558 3559 3560 3561 3562
            ret = -1;
            goto cleanup;
        }
    }

    ret = qemuMonitorDumpToFd(priv->mon, fd, dumpformat);

3563
 cleanup:
3564
    qemuDomainObjExitMonitor(driver, vm);
3565 3566 3567 3568

    return ret;
}

3569
static int
3570
doCoreDump(virQEMUDriverPtr driver,
3571 3572
           virDomainObjPtr vm,
           const char *path,
3573
           virQEMUSaveFormat compress,
3574 3575
           unsigned int dump_flags,
           unsigned int dumpformat)
H
Hu Tao 已提交
3576 3577 3578
{
    int fd = -1;
    int ret = -1;
J
Jiri Denemark 已提交
3579
    virFileWrapperFdPtr wrapperFd = NULL;
3580
    int directFlag = 0;
3581
    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
3582
    const char *memory_dump_format = NULL;
H
Hu Tao 已提交
3583 3584

    /* Create an empty file with appropriate ownership.  */
3585
    if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
3586
        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
3587 3588
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
3589 3590
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
3591 3592 3593
            goto cleanup;
        }
    }
E
Eric Blake 已提交
3594 3595 3596
    /* Core dumps usually imply last-ditch analysis efforts are
     * desired, so we intentionally do not unlink even if a file was
     * created.  */
3597
    if ((fd = qemuOpenFile(driver, vm, path,
E
Eric Blake 已提交
3598 3599
                           O_CREAT | O_TRUNC | O_WRONLY | directFlag,
                           NULL, NULL)) < 0)
H
Hu Tao 已提交
3600 3601
        goto cleanup;

3602
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags)))
3603 3604
        goto cleanup;

3605
    if (dump_flags & VIR_DUMP_MEMORY_ONLY) {
3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617
        if (!(memory_dump_format = qemuDumpFormatTypeToString(dumpformat))) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("unknown dumpformat '%d'"), dumpformat);
            goto cleanup;
        }

        /* qemu dumps in "elf" without dumpformat set */
        if (STREQ(memory_dump_format, "elf"))
            memory_dump_format = NULL;

        ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP,
                           memory_dump_format);
3618
    } else {
3619 3620 3621 3622 3623 3624
        if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("kdump-compressed format is only supported with "
                             "memory-only dump"));
            goto cleanup;
        }
3625 3626 3627 3628

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

3629 3630 3631 3632 3633 3634
        ret = qemuMigrationToFile(driver, vm, fd, 0, path,
                                  qemuCompressProgramName(compress), false,
                                  QEMU_ASYNC_JOB_DUMP);
    }

    if (ret < 0)
3635 3636
        goto cleanup;

H
Hu Tao 已提交
3637 3638
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
3639
                             _("unable to close file %s"),
H
Hu Tao 已提交
3640 3641 3642
                             path);
        goto cleanup;
    }
J
Jiri Denemark 已提交
3643
    if (virFileWrapperFdClose(wrapperFd) < 0)
3644
        goto cleanup;
H
Hu Tao 已提交
3645

3646
    ret = 0;
H
Hu Tao 已提交
3647

3648
 cleanup:
3649
    VIR_FORCE_CLOSE(fd);
3650
    if (ret != 0)
H
Hu Tao 已提交
3651
        unlink(path);
3652
    virFileWrapperFdFree(wrapperFd);
H
Hu Tao 已提交
3653 3654 3655
    return ret;
}

3656
static virQEMUSaveFormat
3657
getCompressionType(virQEMUDriverPtr driver)
3658
{
3659 3660
    int ret = QEMU_SAVE_FORMAT_RAW;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3661

3662 3663 3664 3665
    /*
     * We reuse "save" flag for "dump" here. Then, we can support the same
     * format in "save" and "dump".
     */
3666 3667
    if (cfg->dumpImageFormat) {
        ret = qemuSaveCompressionTypeFromString(cfg->dumpImageFormat);
3668 3669 3670
        /* Use "raw" as the format if the specified format is not valid,
         * or the compress program is not available.
         */
3671
        if (ret < 0) {
3672 3673
            VIR_WARN("%s", _("Invalid dump image format specified in "
                             "configuration file, using raw"));
3674 3675
            ret = QEMU_SAVE_FORMAT_RAW;
            goto cleanup;
3676
        }
3677
        if (!qemuCompressProgramAvailable(ret)) {
3678 3679 3680
            VIR_WARN("%s", _("Compression program for dump image format "
                             "in configuration file isn't available, "
                             "using raw"));
3681 3682
            ret = QEMU_SAVE_FORMAT_RAW;
            goto cleanup;
3683
        }
3684
    }
3685
 cleanup:
3686 3687
    virObjectUnref(cfg);
    return ret;
3688 3689
}

3690 3691 3692 3693 3694 3695

static int
qemuDomainCoreDumpWithFormat(virDomainPtr dom,
                             const char *path,
                             unsigned int dumpformat,
                             unsigned int flags)
3696
{
3697
    virQEMUDriverPtr driver = dom->conn->privateData;
3698
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
3699
    qemuDomainObjPrivatePtr priv;
3700
    bool resume = false, paused = false;
H
Hu Tao 已提交
3701
    int ret = -1;
3702
    virObjectEventPtr event = NULL;
3703

M
Michal Privoznik 已提交
3704
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH |
3705 3706
                  VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET |
                  VIR_DUMP_MEMORY_ONLY, -1);
3707

3708 3709
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
P
Paolo Bonzini 已提交
3710

3711
    if (virDomainCoreDumpWithFormatEnsureACL(dom->conn, vm->def) < 0)
3712 3713
        goto cleanup;

3714 3715
    if (qemuDomainObjBeginAsyncJob(driver, vm,
                                   QEMU_ASYNC_JOB_DUMP) < 0)
3716 3717
        goto cleanup;

D
Daniel P. Berrange 已提交
3718
    if (!virDomainObjIsActive(vm)) {
3719 3720
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3721
        goto endjob;
P
Paolo Bonzini 已提交
3722 3723
    }

P
Paolo Bonzini 已提交
3724 3725
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
J
Jiri Denemark 已提交
3726
    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
3727 3728

    /* Pause domain for non-live dump */
J
Jiri Denemark 已提交
3729 3730
    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3731 3732
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP,
                                QEMU_ASYNC_JOB_DUMP) < 0)
3733
            goto endjob;
3734
        paused = true;
3735 3736

        if (!virDomainObjIsActive(vm)) {
3737 3738
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
3739 3740
            goto endjob;
        }
P
Paolo Bonzini 已提交
3741 3742
    }

3743 3744
    ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags,
                     dumpformat);
3745 3746 3747
    if (ret < 0)
        goto endjob;

3748
    paused = true;
3749

3750
 endjob:
3751
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
3752
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
3753
        virDomainAuditStop(vm, "crashed");
3754
        event = virDomainEventLifecycleNewFromObj(vm,
3755 3756
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
3757 3758
    } else if (((resume && paused) || (flags & VIR_DUMP_RESET)) &&
               virDomainObjIsActive(vm)) {
M
Michal Privoznik 已提交
3759 3760
        if ((ret == 0) && (flags & VIR_DUMP_RESET)) {
            priv =  vm->privateData;
3761
            qemuDomainObjEnterMonitor(driver, vm);
M
Michal Privoznik 已提交
3762
            ret = qemuMonitorSystemReset(priv->mon);
3763
            qemuDomainObjExitMonitor(driver, vm);
M
Michal Privoznik 已提交
3764 3765
        }

3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776
        if (resume && virDomainObjIsActive(vm)) {
            if (qemuProcessStartCPUs(driver, vm, dom->conn,
                                     VIR_DOMAIN_RUNNING_UNPAUSED,
                                     QEMU_ASYNC_JOB_DUMP) < 0) {
                event = virDomainEventLifecycleNewFromObj(vm,
                                                          VIR_DOMAIN_EVENT_SUSPENDED,
                                                          VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
                if (virGetLastError() == NULL)
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   "%s", _("resuming after dump failed"));
            }
P
Paolo Bonzini 已提交
3777 3778
        }
    }
3779

3780
    if (qemuDomainObjEndAsyncJob(driver, vm) == 0) {
3781
        vm = NULL;
3782
    } else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
3783
        qemuDomainRemoveInactive(driver, vm);
3784 3785
        vm = NULL;
    }
3786

3787
 cleanup:
P
Paolo Bonzini 已提交
3788
    if (vm)
3789
        virObjectUnlock(vm);
3790 3791
    if (event)
        qemuDomainEventQueue(driver, event);
P
Paolo Bonzini 已提交
3792 3793 3794
    return ret;
}

3795 3796 3797 3798 3799

static int
qemuDomainCoreDump(virDomainPtr dom,
                   const char *path,
                   unsigned int flags)
3800 3801
{
    return qemuDomainCoreDumpWithFormat(dom, path,
3802 3803
                                        VIR_DOMAIN_CORE_DUMP_FORMAT_RAW,
                                        flags);
3804 3805
}

3806

3807 3808 3809 3810
static char *
qemuDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
3811
                     unsigned int flags)
3812
{
3813
    virQEMUDriverPtr driver = dom->conn->privateData;
3814 3815 3816 3817 3818
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *tmp = NULL;
    int tmp_fd = -1;
    char *ret = NULL;
E
Eric Blake 已提交
3819
    bool unlink_tmp = false;
3820
    virQEMUDriverConfigPtr cfg = NULL;
3821

E
Eric Blake 已提交
3822 3823
    virCheckFlags(0, NULL);

3824
    if (!(vm = qemuDomObjFromDomain(dom)))
3825 3826 3827
        goto cleanup;

    priv = vm->privateData;
3828
    cfg = virQEMUDriverGetConfig(driver);
3829

3830 3831 3832
    if (virDomainScreenshotEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3833
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3834 3835 3836
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
3837 3838
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3839 3840 3841 3842 3843 3844
        goto endjob;
    }

    /* Well, even if qemu allows multiple graphic cards, heads, whatever,
     * screenshot command does not */
    if (screen) {
3845 3846 3847
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("currently is supported only taking "
                               "screenshots of screen ID 0"));
3848 3849 3850
        goto endjob;
    }

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

3854 3855
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
3856 3857
        goto endjob;
    }
E
Eric Blake 已提交
3858
    unlink_tmp = true;
3859

3860
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
3861

3862
    qemuDomainObjEnterMonitor(driver, vm);
3863
    if (qemuMonitorScreendump(priv->mon, tmp) < 0) {
3864
        qemuDomainObjExitMonitor(driver, vm);
3865 3866
        goto endjob;
    }
3867
    qemuDomainObjExitMonitor(driver, vm);
3868 3869 3870 3871 3872 3873

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

E
Eric Blake 已提交
3874
    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
3875 3876
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to open stream"));
3877 3878 3879
        goto endjob;
    }

3880
    ignore_value(VIR_STRDUP(ret, "image/x-portable-pixmap"));
3881

3882
 endjob:
3883
    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
3884 3885
    if (unlink_tmp)
        unlink(tmp);
E
Eric Blake 已提交
3886
    VIR_FREE(tmp);
3887

E
Eric Blake 已提交
3888
    if (!qemuDomainObjEndJob(driver, vm))
3889 3890
        vm = NULL;

3891
 cleanup:
3892
    if (vm)
3893
        virObjectUnlock(vm);
3894
    virObjectUnref(cfg);
3895 3896 3897
    return ret;
}

C
Chen Fan 已提交
3898
static void processWatchdogEvent(virQEMUDriverPtr driver, virDomainObjPtr vm, int action)
H
Hu Tao 已提交
3899 3900
{
    int ret;
C
Chen Fan 已提交
3901
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
W
Wen Congyang 已提交
3902

C
Chen Fan 已提交
3903
    switch (action) {
H
Hu Tao 已提交
3904 3905 3906
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;
3907
            unsigned int flags = 0;
H
Hu Tao 已提交
3908

E
Eric Blake 已提交
3909
            if (virAsprintf(&dumpfile, "%s/%s-%u",
3910
                            cfg->autoDumpPath,
C
Chen Fan 已提交
3911
                            vm->def->name,
3912
                            (unsigned int)time(NULL)) < 0)
C
Chen Fan 已提交
3913
                goto cleanup;
H
Hu Tao 已提交
3914

C
Chen Fan 已提交
3915 3916
            if (qemuDomainObjBeginAsyncJob(driver, vm,
                                           QEMU_ASYNC_JOB_DUMP) < 0) {
W
Wen Congyang 已提交
3917
                VIR_FREE(dumpfile);
C
Chen Fan 已提交
3918
                goto cleanup;
W
Wen Congyang 已提交
3919
            }
H
Hu Tao 已提交
3920

C
Chen Fan 已提交
3921
            if (!virDomainObjIsActive(vm)) {
3922 3923
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
W
Wen Congyang 已提交
3924 3925
                VIR_FREE(dumpfile);
                goto endjob;
H
Hu Tao 已提交
3926 3927
            }

3928
            flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
C
Chen Fan 已提交
3929
            ret = doCoreDump(driver, vm, dumpfile,
3930 3931
                             getCompressionType(driver), flags,
                             VIR_DOMAIN_CORE_DUMP_FORMAT_RAW);
H
Hu Tao 已提交
3932
            if (ret < 0)
3933 3934
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Dump failed"));
H
Hu Tao 已提交
3935

C
Chen Fan 已提交
3936
            ret = qemuProcessStartCPUs(driver, vm, NULL,
3937 3938
                                       VIR_DOMAIN_RUNNING_UNPAUSED,
                                       QEMU_ASYNC_JOB_DUMP);
H
Hu Tao 已提交
3939 3940

            if (ret < 0)
3941 3942
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Resuming after dump failed"));
H
Hu Tao 已提交
3943 3944 3945 3946

            VIR_FREE(dumpfile);
        }
        break;
W
Wen Congyang 已提交
3947
    default:
C
Chen Fan 已提交
3948
        goto cleanup;
H
Hu Tao 已提交
3949 3950
    }

3951
 endjob:
W
Wen Congyang 已提交
3952 3953 3954
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleWatchdog().
     */
C
Chen Fan 已提交
3955
    ignore_value(qemuDomainObjEndAsyncJob(driver, vm));
W
Wen Congyang 已提交
3956

3957
 cleanup:
3958
    virObjectUnref(cfg);
H
Hu Tao 已提交
3959
}
P
Paolo Bonzini 已提交
3960

3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978
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,
3979
                    timestr) < 0)
3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994
        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,
3995 3996
                     getCompressionType(driver), flags,
                     VIR_DOMAIN_CORE_DUMP_FORMAT_RAW);
3997 3998 3999 4000
    if (ret < 0)
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("Dump failed"));

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

4007
 cleanup:
4008 4009 4010 4011 4012
    VIR_FREE(dumpfile);
    virObjectUnref(cfg);
    return ret;
}

4013 4014 4015 4016 4017 4018
static void
processGuestPanicEvent(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       int action)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4019
    virObjectEventPtr event = NULL;
4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031
    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);

4032
    event = virDomainEventLifecycleNewFromObj(vm,
4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048
                                     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) {
4049 4050 4051 4052 4053 4054
    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY:
        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0) {
            goto cleanup;
        }
        /* fall through */

4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071
    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);
4072
        event = virDomainEventLifecycleNewFromObj(vm,
4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);

        if (event)
            qemuDomainEventQueue(driver, event);

        virDomainAuditStop(vm, "destroyed");

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

4086 4087 4088 4089 4090 4091
    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_RESTART:
        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0) {
            goto cleanup;
        }
        /* fall through */

4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103
    case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART:
        qemuDomainSetFakeReboot(driver, vm, true);
        qemuProcessShutdownOrReboot(driver, vm);
        break;

    case VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE:
        break;

    default:
        break;
    }

4104
 cleanup:
4105 4106 4107
    virObjectUnref(cfg);
}

4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148

static void
processDeviceDeletedEvent(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          char *devAlias)
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    virDomainDeviceDef dev;

    VIR_DEBUG("Removing device %s from domain %p %s",
              devAlias, vm, vm->def->name);

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

    if (!virDomainObjIsActive(vm)) {
        VIR_DEBUG("Domain is not running");
        goto endjob;
    }

    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0)
        goto endjob;

    qemuDomainRemoveDevice(driver, vm, &dev);

    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
        VIR_WARN("unable to save domain status after removing device %s",
                 devAlias);

 endjob:
    /* We had an extra reference to vm before starting a new job so ending the
     * job is guaranteed not to remove the last reference.
     */
    ignore_value(qemuDomainObjEndJob(driver, vm));

 cleanup:
    VIR_FREE(devAlias);
    virObjectUnref(cfg);
}


4149 4150 4151 4152 4153 4154
static void
processNicRxFilterChangedEvent(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               char *devAlias)
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4155
    qemuDomainObjPrivatePtr priv = vm->privateData;
4156 4157
    virDomainDeviceDef dev;
    virDomainNetDefPtr def;
4158 4159 4160 4161
    virNetDevRxFilterPtr filter = NULL;
    virMacAddr oldMAC;
    char newMacStr[VIR_MAC_STRING_BUFLEN];
    int ret;
4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188

    VIR_DEBUG("Received NIC_RX_FILTER_CHANGED event for device %s "
              "from domain %p %s",
              devAlias, vm, vm->def->name);

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

    if (!virDomainObjIsActive(vm)) {
        VIR_DEBUG("Domain is not running");
        goto endjob;
    }

    if (virDomainDefFindDevice(vm->def, devAlias, &dev, true) < 0) {
        VIR_WARN("NIC_RX_FILTER_CHANGED event received for "
                 "non-existent device %s in domain %s",
                 devAlias, vm->def->name);
        goto endjob;
    }
    if (dev.type != VIR_DOMAIN_DEVICE_NET) {
        VIR_WARN("NIC_RX_FILTER_CHANGED event received for "
                 "non-network device %s in domain %s",
                 devAlias, vm->def->name);
        goto endjob;
    }
    def = dev.data.net;

4189 4190 4191 4192 4193 4194 4195 4196 4197 4198
    if (!virDomainNetGetActualTrustGuestRxFilters(def)) {
        VIR_WARN("ignore NIC_RX_FILTER_CHANGED event for network "
                  "device %s in domain %s",
                  def->info.alias, vm->def->name);
        /* not sending "query-rx-filter" will also suppress any
         * further NIC_RX_FILTER_CHANGED events for this device
         */
        goto endjob;
    }

4199 4200 4201 4202 4203
    /* handle the event - send query-rx-filter and respond to it. */

    VIR_DEBUG("process NIC_RX_FILTER_CHANGED event for network "
              "device %s in domain %s", def->info.alias, vm->def->name);

4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorQueryRxFilter(priv->mon, devAlias, &filter);
    qemuDomainObjExitMonitor(driver, vm);
    if (ret < 0)
        goto endjob;

    virMacAddrFormat(&filter->mac, newMacStr);

    if (virDomainNetGetActualType(def) == VIR_DOMAIN_NET_TYPE_DIRECT) {

        /* For macvtap connections, set the macvtap device's MAC
         * address to match that of the guest device.
         */

        if (virNetDevGetMAC(def->ifname, &oldMAC) < 0) {
            VIR_WARN("Couldn't get current MAC address of device %s "
                     "while responding to NIC_RX_FILTER_CHANGED",
                     def->ifname);
            goto endjob;
        }

        if (virMacAddrCmp(&oldMAC, &filter->mac)) {
            /* set new MAC address from guest to associated macvtap device */
            if (virNetDevSetMAC(def->ifname, &filter->mac) < 0) {
                VIR_WARN("Couldn't set new MAC address %s to device %s "
                         "while responding to NIC_RX_FILTER_CHANGED",
                         newMacStr, def->ifname);
            } else {
                VIR_DEBUG("device %s MAC address set to %s",
                          def->ifname, newMacStr);
            }
        }
    }

4238 4239 4240 4241 4242 4243 4244
 endjob:
    /* We had an extra reference to vm before starting a new job so ending the
     * job is guaranteed not to remove the last reference.
     */
    ignore_value(qemuDomainObjEndJob(driver, vm));

 cleanup:
4245
    virNetDevRxFilterFree(filter);
4246 4247 4248 4249 4250
    VIR_FREE(devAlias);
    virObjectUnref(cfg);
}


C
Chen Fan 已提交
4251 4252 4253 4254 4255 4256
static void qemuProcessEventHandler(void *data, void *opaque)
{
    struct qemuProcessEvent *processEvent = data;
    virDomainObjPtr vm = processEvent->vm;
    virQEMUDriverPtr driver = opaque;

4257 4258
    VIR_DEBUG("vm=%p", vm);

C
Chen Fan 已提交
4259 4260 4261 4262 4263 4264
    virObjectLock(vm);

    switch (processEvent->eventType) {
    case QEMU_PROCESS_EVENT_WATCHDOG:
        processWatchdogEvent(driver, vm, processEvent->action);
        break;
4265 4266 4267
    case QEMU_PROCESS_EVENT_GUESTPANIC:
        processGuestPanicEvent(driver, vm, processEvent->action);
        break;
4268 4269 4270
    case QEMU_PROCESS_EVENT_DEVICE_DELETED:
        processDeviceDeletedEvent(driver, vm, processEvent->data);
        break;
4271 4272 4273
    case QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED:
        processNicRxFilterChangedEvent(driver, vm, processEvent->data);
        break;
4274 4275
    case QEMU_PROCESS_EVENT_LAST:
        break;
C
Chen Fan 已提交
4276 4277 4278 4279 4280 4281 4282
    }

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

4283
static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
4284 4285
                                  virDomainObjPtr vm,
                                  unsigned int nvcpus)
4286 4287
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4288 4289
    size_t i;
    int rc = 1;
4290
    int ret = -1;
4291
    int oldvcpus = vm->def->vcpus;
E
Eric Blake 已提交
4292
    int vcpus = oldvcpus;
4293 4294
    pid_t *cpupids = NULL;
    int ncpupids;
4295
    virCgroupPtr cgroup_vcpu = NULL;
4296

4297
    qemuDomainObjEnterMonitor(driver, vm);
4298

4299 4300 4301
    /* 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 已提交
4302
    if (nvcpus > vcpus) {
4303
        for (i = vcpus; i < nvcpus; i++) {
4304
            /* Online new CPU */
4305
            rc = qemuMonitorSetCPU(priv->mon, i, true);
4306 4307 4308 4309 4310
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
4311
            vcpus++;
4312 4313
        }
    } else {
4314
        for (i = vcpus - 1; i >= nvcpus; i--) {
4315
            /* Offline old CPU */
4316
            rc = qemuMonitorSetCPU(priv->mon, i, false);
4317 4318 4319 4320 4321
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
4322
            vcpus--;
4323 4324 4325
        }
    }

4326 4327
    /* hotplug succeeded */

4328 4329
    ret = 0;

4330 4331 4332 4333 4334 4335 4336 4337 4338 4339
    /* 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;
    }

4340 4341 4342 4343 4344 4345 4346 4347 4348
    /* 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;
    }

4349
    if (ncpupids != vcpus) {
4350 4351 4352 4353
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("got wrong number of vCPU pids from QEMU monitor. "
                         "got %d, wanted %d"),
                       ncpupids, vcpus);
4354
        vcpus = oldvcpus;
4355 4356 4357 4358
        ret = -1;
        goto cleanup;
    }

4359 4360
    if (nvcpus > oldvcpus) {
        for (i = oldvcpus; i < nvcpus; i++) {
4361
            if (priv->cgroup) {
4362
                int rv = -1;
4363
                /* Create cgroup for the onlined vcpu */
4364
                if (virCgroupNewVcpu(priv->cgroup, i, true, &cgroup_vcpu) < 0)
4365 4366 4367 4368 4369 4370
                    goto cleanup;

                /* Add vcpu thread to the cgroup */
                rv = virCgroupAddTask(cgroup_vcpu, cpupids[i]);
                if (rv < 0) {
                    virReportSystemError(-rv,
4371
                                         _("unable to add vcpu %zu task %d to cgroup"),
4372 4373 4374 4375
                                         i, cpupids[i]);
                    virCgroupRemove(cgroup_vcpu);
                    goto cleanup;
                }
4376
            }
4377

4378 4379 4380 4381 4382 4383 4384
            /* 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;

4385
                if (VIR_ALLOC(vcpupin) < 0)
4386 4387 4388 4389 4390
                    goto cleanup;

                vcpupin->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN);
                virBitmapCopy(vcpupin->cpumask, vm->def->cpumask);
                vcpupin->vcpuid = i;
4391 4392 4393 4394 4395 4396 4397
                if (VIR_APPEND_ELEMENT_COPY(vm->def->cputune.vcpupin,
                                            vm->def->cputune.nvcpupin, vcpupin) < 0) {
                    virBitmapFree(vcpupin->cpumask);
                    VIR_FREE(vcpupin);
                    ret = -1;
                    goto cleanup;
                }
4398

4399
                if (cgroup_vcpu) {
4400 4401 4402 4403 4404
                    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"
4405
                                         " for vcpu %zu"), i);
4406 4407 4408 4409
                        ret = -1;
                        goto cleanup;
                    }
                } else {
4410 4411
                    if (virProcessSetAffinity(cpupids[i],
                                              vcpupin->cpumask) < 0) {
4412
                        virReportError(VIR_ERR_SYSTEM_ERROR,
4413
                                       _("failed to set cpu affinity for vcpu %zu"),
4414 4415 4416 4417 4418
                                       i);
                        ret = -1;
                        goto cleanup;
                    }
                }
4419
            }
4420 4421

            virCgroupFree(&cgroup_vcpu);
G
Guido Günther 已提交
4422
        }
4423 4424
    } else {
        for (i = oldvcpus - 1; i >= nvcpus; i--) {
4425
            if (priv->cgroup) {
4426
                if (virCgroupNewVcpu(priv->cgroup, i, false, &cgroup_vcpu) < 0)
4427 4428 4429 4430 4431 4432 4433
                    goto cleanup;

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

4434
            /* Free vcpupin setting */
4435
            virDomainVcpuPinDel(vm->def, i);
4436
        }
4437 4438
    }

4439 4440 4441 4442 4443
    priv->nvcpupids = ncpupids;
    VIR_FREE(priv->vcpupids);
    priv->vcpupids = cpupids;
    cpupids = NULL;

4444
 cleanup:
4445
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
4446
    vm->def->vcpus = vcpus;
4447
    VIR_FREE(cpupids);
4448
    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
4449 4450
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
4451 4452
    return ret;

4453
 unsupported:
4454 4455
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("cannot change vcpu count of this domain"));
4456 4457 4458 4459
    goto cleanup;
}


4460
static int
4461 4462
qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
4463
{
4464
    virQEMUDriverPtr driver = dom->conn->privateData;
4465
    virDomainObjPtr vm = NULL;
4466
    virDomainDefPtr persistentDef;
4467
    int ret = -1;
4468
    bool maximum;
4469
    unsigned int maxvcpus = 0;
4470
    virQEMUDriverConfigPtr cfg = NULL;
4471
    virCapsPtr caps = NULL;
4472 4473 4474
    qemuAgentCPUInfoPtr cpuinfo = NULL;
    int ncpuinfo;
    qemuDomainObjPrivatePtr priv;
4475
    size_t i;
4476

4477 4478
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4479
                  VIR_DOMAIN_VCPU_MAXIMUM |
4480
                  VIR_DOMAIN_VCPU_GUEST, -1);
4481 4482

    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
4483 4484
        virReportError(VIR_ERR_INVALID_ARG,
                       _("argument out of range: %d"), nvcpus);
4485 4486 4487
        return -1;
    }

4488 4489 4490
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;

4491
    cfg = virQEMUDriverGetConfig(driver);
4492 4493

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

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

4499 4500
    priv = vm->privateData;

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

4504 4505 4506
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

4507
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4508 4509
                                        &persistentDef) < 0)
        goto endjob;
4510 4511 4512

    /* MAXIMUM cannot be mixed with LIVE.  */
    if (maximum && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
4513 4514
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("cannot adjust maximum on running domain"));
4515 4516 4517
        goto endjob;
    }

4518 4519 4520 4521 4522 4523 4524
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
        maxvcpus = vm->def->maxvcpus;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!maxvcpus || maxvcpus > persistentDef->maxvcpus)
            maxvcpus = persistentDef->maxvcpus;
    }
    if (!maximum && nvcpus > maxvcpus) {
4525 4526
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
4527
                         " vcpus for the domain: %d > %d"),
4528
                       nvcpus, maxvcpus);
4529 4530 4531
        goto endjob;
    }

4532
    if (flags & VIR_DOMAIN_VCPU_GUEST) {
4533 4534
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4535
                           _("changing of maximum vCPU count isn't supported "
4536
                             "via guest agent"));
4537
            goto endjob;
4538
        }
4539

4540
        if (!qemuDomainAgentAvailable(priv, true))
4541 4542
            goto endjob;

4543 4544 4545 4546 4547 4548 4549 4550
        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;
        }

4551 4552 4553 4554 4555 4556 4557
        qemuDomainObjEnterAgent(vm);
        ncpuinfo = qemuAgentGetVCPUs(priv->agent, &cpuinfo);
        qemuDomainObjExitAgent(vm);

        if (ncpuinfo < 0)
            goto endjob;

4558 4559 4560 4561 4562 4563
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain is not running"));
            goto endjob;
        }

4564
        if (qemuAgentUpdateCPUInfo(nvcpus, cpuinfo, ncpuinfo) < 0)
4565 4566 4567 4568 4569 4570 4571
            goto endjob;

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

        if (ret < 0)
4572
            goto endjob;
4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584

        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;
4585 4586 4587

            if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
                goto endjob;
4588 4589 4590
        }

        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4591 4592 4593 4594 4595 4596
            /* remove vcpupin entries for vcpus that were unplugged */
            if (nvcpus < persistentDef->vcpus) {
                for (i = persistentDef->vcpus; i >= nvcpus; i--)
                    virDomainVcpuPinDel(persistentDef, i);
            }

4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607
            if (maximum) {
                persistentDef->maxvcpus = nvcpus;
                if (nvcpus < persistentDef->vcpus)
                    persistentDef->vcpus = nvcpus;
            } else {
                persistentDef->vcpus = nvcpus;
            }

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

4610
    ret = 0;
4611

4612
 endjob:
E
Eric Blake 已提交
4613
    if (!qemuDomainObjEndJob(driver, vm))
4614
        vm = NULL;
4615

4616
 cleanup:
4617
    if (vm)
4618
        virObjectUnlock(vm);
4619
    virObjectUnref(caps);
4620
    VIR_FREE(cpuinfo);
4621
    virObjectUnref(cfg);
4622
    return ret;
4623 4624
}

4625
static int
4626
qemuDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
4627
{
4628
    return qemuDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
4629 4630
}

4631 4632

static int
4633 4634 4635 4636
qemuDomainPinVcpuFlags(virDomainPtr dom,
                       unsigned int vcpu,
                       unsigned char *cpumap,
                       int maplen,
4637 4638
                       unsigned int flags)
{
4639

4640
    virQEMUDriverPtr driver = dom->conn->privateData;
4641
    virDomainObjPtr vm;
4642
    virDomainDefPtr persistentDef = NULL;
4643
    virCgroupPtr cgroup_vcpu = NULL;
4644
    int ret = -1;
4645
    qemuDomainObjPrivatePtr priv;
4646
    bool doReset = false;
4647
    size_t newVcpuPinNum = 0;
4648
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4649
    virBitmapPtr pcpumap = NULL;
4650
    virQEMUDriverConfigPtr cfg = NULL;
4651
    virCapsPtr caps = NULL;
4652 4653 4654 4655 4656 4657
    virObjectEventPtr event = NULL;
    char paramField[VIR_TYPED_PARAM_FIELD_LENGTH] = "";
    char *str = NULL;
    virTypedParameterPtr eventParams = NULL;
    int eventNparams = 0;
    int eventMaxparams = 0;
4658

4659 4660 4661
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4662 4663
    cfg = virQEMUDriverGetConfig(driver);

4664
    if (!(vm = qemuDomObjFromDomain(dom)))
4665 4666
        goto cleanup;

4667 4668 4669
    if (virDomainPinVcpuFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

4673
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4674
                                        &persistentDef) < 0)
4675
        goto cleanup;
4676

4677 4678 4679
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
4680 4681
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu number out of range %d > %d"),
4682
                       vcpu, priv->nvcpupids - 1);
4683
        goto cleanup;
4684 4685
    }

4686 4687 4688 4689
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

4690 4691 4692 4693 4694 4695
    if (virBitmapIsAllClear(pcpumap)) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Empty cpu list for pinning"));
        goto cleanup;
    }

4696 4697 4698
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4699 4700
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
4701

4702
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4703

4704
        if (priv->vcpupids == NULL) {
4705 4706
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
4707 4708 4709
            goto cleanup;
        }

4710 4711 4712 4713 4714 4715 4716 4717
        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 {
4718
            if (VIR_ALLOC(newVcpuPin) < 0)
4719 4720 4721 4722
                goto cleanup;
            newVcpuPinNum = 0;
        }

4723
        if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, vcpu) < 0) {
4724 4725
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to update vcpupin"));
H
Hu Tao 已提交
4726
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
4727 4728 4729 4730
            goto cleanup;
        }

        /* Configure the corresponding cpuset cgroup before set affinity. */
4731
        if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
4732 4733 4734
            if (virCgroupNewVcpu(priv->cgroup, vcpu, false, &cgroup_vcpu) < 0)
                goto cleanup;
            if (qemuSetupCgroupVcpuPin(cgroup_vcpu, newVcpuPin, newVcpuPinNum, vcpu) < 0) {
4735 4736 4737
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("failed to set cpuset.cpus in cgroup"
                                 " for vcpu %d"), vcpu);
4738 4739 4740
                goto cleanup;
            }
        } else {
4741
            if (virProcessSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) {
4742 4743 4744 4745
                virReportError(VIR_ERR_SYSTEM_ERROR,
                               _("failed to set cpu affinity for vcpu %d"),
                               vcpu);
                goto cleanup;
H
Hu Tao 已提交
4746
            }
4747 4748
        }

4749
        if (doReset) {
4750
            virDomainVcpuPinDel(vm->def, vcpu);
4751 4752
        } else {
            if (vm->def->cputune.vcpupin)
H
Hu Tao 已提交
4753
                virDomainVcpuPinDefArrayFree(vm->def->cputune.vcpupin, vm->def->cputune.nvcpupin);
4754 4755 4756 4757

            vm->def->cputune.vcpupin = newVcpuPin;
            vm->def->cputune.nvcpupin = newVcpuPinNum;
            newVcpuPin = NULL;
4758 4759
        }

4760
        if (newVcpuPin)
H
Hu Tao 已提交
4761
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
4762

4763
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
4764
            goto cleanup;
4765 4766

        if (snprintf(paramField, VIR_TYPED_PARAM_FIELD_LENGTH,
4767
                     VIR_DOMAIN_TUNABLE_CPU_VCPUPIN, vcpu) < 0) {
4768 4769 4770 4771 4772 4773 4774 4775 4776
            goto cleanup;
        }

        str = virBitmapFormat(pcpumap);
        if (virTypedParamsAddString(&eventParams, &eventNparams,
                                    &eventMaxparams, paramField, str) < 0)
            goto cleanup;

        event = virDomainEventTunableNewFromDom(dom, eventParams, eventNparams);
4777
    }
4778

4779 4780
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

4781
        if (doReset) {
4782
            virDomainVcpuPinDel(persistentDef, vcpu);
4783
        } else {
H
Hu Tao 已提交
4784
            if (!persistentDef->cputune.vcpupin) {
4785
                if (VIR_ALLOC(persistentDef->cputune.vcpupin) < 0)
H
Hu Tao 已提交
4786 4787 4788
                    goto cleanup;
                persistentDef->cputune.nvcpupin = 0;
            }
4789
            if (virDomainVcpuPinAdd(&persistentDef->cputune.vcpupin,
H
Hu Tao 已提交
4790 4791 4792 4793
                                    &persistentDef->cputune.nvcpupin,
                                    cpumap,
                                    maplen,
                                    vcpu) < 0) {
4794 4795 4796
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update or add vcpupin xml of "
                                 "a persistent domain"));
4797 4798
                goto cleanup;
            }
4799
        }
4800

4801
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
4802 4803 4804
        goto cleanup;
    }

4805
    ret = 0;
4806

4807
 cleanup:
4808 4809
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
4810
    if (vm)
4811
        virObjectUnlock(vm);
4812 4813 4814
    if (event)
        qemuDomainEventQueue(driver, event);
    VIR_FREE(str);
4815
    virBitmapFree(pcpumap);
4816
    virObjectUnref(caps);
4817
    virObjectUnref(cfg);
4818
    return ret;
4819 4820
}

4821
static int
4822
qemuDomainPinVcpu(virDomainPtr dom,
4823 4824
                   unsigned int vcpu,
                   unsigned char *cpumap,
4825 4826
                   int maplen)
{
4827 4828
    return qemuDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                  VIR_DOMAIN_AFFECT_LIVE);
4829 4830
}

4831
static int
4832 4833 4834 4835
qemuDomainGetVcpuPinInfo(virDomainPtr dom,
                         int ncpumaps,
                         unsigned char *cpumaps,
                         int maplen,
4836 4837
                         unsigned int flags)
{
4838

4839
    virQEMUDriverPtr driver = dom->conn->privateData;
E
Eric Blake 已提交
4840
    virDomainObjPtr vm = NULL;
4841 4842 4843 4844
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, vcpu, pcpu;
    int n;
E
Eric Blake 已提交
4845
    virDomainVcpuPinDefPtr *vcpupin_list;
H
Hu Tao 已提交
4846
    virBitmapPtr cpumask = NULL;
4847
    unsigned char *cpumap;
H
Hu Tao 已提交
4848
    bool pinned;
4849
    virCapsPtr caps = NULL;
4850 4851 4852 4853

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4854
    if (!(vm = qemuDomObjFromDomain(dom)))
4855 4856
        goto cleanup;

4857 4858 4859
    if (virDomainGetVcpuPinInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

4863
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4864 4865
                                        &targetDef) < 0)
        goto cleanup;
4866 4867 4868 4869 4870

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

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

4874
    if ((hostcpus = nodeGetCPUCount()) < 0)
4875
        goto cleanup;
4876

4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904
    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 已提交
4905 4906 4907
            if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
                goto cleanup;
            if (!pinned)
4908 4909 4910 4911 4912
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

4913
 cleanup:
4914
    if (vm)
4915
        virObjectUnlock(vm);
4916
    virObjectUnref(caps);
4917 4918 4919
    return ret;
}

H
Hu Tao 已提交
4920
static int
4921 4922 4923 4924
qemuDomainPinEmulator(virDomainPtr dom,
                      unsigned char *cpumap,
                      int maplen,
                      unsigned int flags)
H
Hu Tao 已提交
4925
{
4926
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4927 4928 4929 4930 4931 4932
    virDomainObjPtr vm;
    virCgroupPtr cgroup_emulator = NULL;
    pid_t pid;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
4933
    bool doReset = false;
4934
    size_t newVcpuPinNum = 0;
H
Hu Tao 已提交
4935
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4936
    virBitmapPtr pcpumap = NULL;
4937
    virQEMUDriverConfigPtr cfg = NULL;
4938
    virCapsPtr caps = NULL;
4939 4940 4941 4942 4943 4944
    virObjectEventPtr event = NULL;
    char * str = NULL;
    virTypedParameterPtr eventParams = NULL;
    int eventNparams = 0;
    int eventMaxparams = 0;

H
Hu Tao 已提交
4945 4946 4947 4948

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4949 4950
    cfg = virQEMUDriverGetConfig(driver);

4951
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4952 4953
        goto cleanup;

4954 4955 4956
    if (virDomainPinEmulatorEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

4960 4961 4962 4963 4964 4965 4966
    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;
    }

4967
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
H
Hu Tao 已提交
4968 4969 4970 4971 4972
                                        &persistentDef) < 0)
        goto cleanup;

    priv = vm->privateData;

4973 4974 4975 4976
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

4977 4978 4979 4980 4981 4982
    if (virBitmapIsAllClear(pcpumap)) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Empty cpu list for pinning"));
        goto cleanup;
    }

H
Hu Tao 已提交
4983 4984 4985
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4986 4987
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
H
Hu Tao 已提交
4988 4989 4990 4991 4992 4993

    pid = vm->pid;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {

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

4997
            if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, -1) < 0) {
H
Hu Tao 已提交
4998 4999
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update vcpupin"));
H
Hu Tao 已提交
5000
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
5001 5002 5003
                goto cleanup;
            }

5004 5005
            if (virCgroupHasController(priv->cgroup,
                                       VIR_CGROUP_CONTROLLER_CPUSET)) {
H
Hu Tao 已提交
5006 5007 5008
                /*
                 * Configure the corresponding cpuset cgroup.
                 */
5009 5010 5011 5012 5013 5014 5015 5016
                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 已提交
5017 5018
                }
            } else {
5019
                if (virProcessSetAffinity(pid, pcpumap) < 0) {
H
Hu Tao 已提交
5020 5021 5022 5023 5024 5025 5026
                    virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
                                   _("failed to set cpu affinity for "
                                     "emulator threads"));
                    goto cleanup;
                }
            }

5027
            if (doReset) {
H
Hu Tao 已提交
5028 5029 5030 5031 5032 5033 5034
                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 已提交
5035
                virDomainVcpuPinDefFree(vm->def->cputune.emulatorpin);
H
Hu Tao 已提交
5036 5037 5038 5039 5040
                vm->def->cputune.emulatorpin = newVcpuPin[0];
                VIR_FREE(newVcpuPin);
            }

            if (newVcpuPin)
H
Hu Tao 已提交
5041
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
5042 5043 5044 5045 5046 5047
        } else {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
            goto cleanup;
        }

5048
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
H
Hu Tao 已提交
5049
            goto cleanup;
5050 5051 5052 5053

        str = virBitmapFormat(pcpumap);
        if (virTypedParamsAddString(&eventParams, &eventNparams,
                                    &eventMaxparams,
5054
                                    VIR_DOMAIN_TUNABLE_CPU_EMULATORPIN,
5055 5056 5057 5058
                                    str) < 0)
            goto cleanup;

        event = virDomainEventTunableNewFromDom(dom, eventParams, eventNparams);
H
Hu Tao 已提交
5059 5060 5061 5062
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

5063
        if (doReset) {
H
Hu Tao 已提交
5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078
            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;
            }
        }

5079
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
H
Hu Tao 已提交
5080 5081 5082 5083 5084
        goto cleanup;
    }

    ret = 0;

5085
 cleanup:
H
Hu Tao 已提交
5086 5087
    if (cgroup_emulator)
        virCgroupFree(&cgroup_emulator);
5088 5089 5090
    if (event)
        qemuDomainEventQueue(driver, event);
    VIR_FREE(str);
5091
    virBitmapFree(pcpumap);
5092
    virObjectUnref(caps);
H
Hu Tao 已提交
5093
    if (vm)
5094
        virObjectUnlock(vm);
5095
    virObjectUnref(cfg);
H
Hu Tao 已提交
5096 5097 5098 5099
    return ret;
}

static int
5100 5101 5102 5103
qemuDomainGetEmulatorPinInfo(virDomainPtr dom,
                             unsigned char *cpumaps,
                             int maplen,
                             unsigned int flags)
H
Hu Tao 已提交
5104
{
5105
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
5106 5107 5108 5109
    virDomainObjPtr vm = NULL;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, pcpu;
H
Hu Tao 已提交
5110 5111
    virBitmapPtr cpumask = NULL;
    bool pinned;
5112
    virCapsPtr caps = NULL;
H
Hu Tao 已提交
5113 5114 5115 5116

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

5117
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
5118 5119
        goto cleanup;

5120 5121 5122
    if (virDomainGetEmulatorPinInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

5126
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
5127
                                        vm, &flags, &targetDef) < 0)
H
Hu Tao 已提交
5128 5129 5130 5131 5132 5133 5134 5135
        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);

5136
    if ((hostcpus = nodeGetCPUCount()) < 0)
H
Hu Tao 已提交
5137
        goto cleanup;
5138

H
Hu Tao 已提交
5139 5140 5141 5142 5143 5144 5145 5146 5147 5148
    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

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

5149 5150 5151 5152 5153
    if (targetDef->cputune.emulatorpin) {
        cpumask = targetDef->cputune.emulatorpin->cpumask;
    } else if (targetDef->cpumask) {
        cpumask = targetDef->cpumask;
    } else {
H
Hu Tao 已提交
5154 5155 5156 5157 5158
        ret = 0;
        goto cleanup;
    }

    for (pcpu = 0; pcpu < maxcpu; pcpu++) {
H
Hu Tao 已提交
5159 5160 5161
        if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
            goto cleanup;
        if (!pinned)
H
Hu Tao 已提交
5162 5163 5164 5165 5166
            VIR_UNUSE_CPU(cpumaps, pcpu);
    }

    ret = 1;

5167
 cleanup:
H
Hu Tao 已提交
5168
    if (vm)
5169
        virObjectUnlock(vm);
5170
    virObjectUnref(caps);
H
Hu Tao 已提交
5171 5172 5173
    return ret;
}

5174
static int
5175 5176 5177 5178
qemuDomainGetVcpus(virDomainPtr dom,
                   virVcpuInfoPtr info,
                   int maxinfo,
                   unsigned char *cpumaps,
5179 5180
                   int maplen)
{
5181 5182
    virDomainObjPtr vm;
    int ret = -1;
5183

5184
    if (!(vm = qemuDomObjFromDomain(dom)))
5185 5186
        goto cleanup;

5187 5188 5189
    if (virDomainGetVcpusEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
5190
    if (!virDomainObjIsActive(vm)) {
5191 5192 5193
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s",
                       _("cannot list vcpu pinning for an inactive domain"));
5194
        goto cleanup;
5195 5196
    }

5197
    ret = qemuDomainHelperGetVcpus(vm, info, maxinfo, cpumaps, maplen);
5198

5199
 cleanup:
5200
    if (vm)
5201
        virObjectUnlock(vm);
5202
    return ret;
5203 5204 5205
}


5206
static int
5207
qemuDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
5208
{
5209
    virQEMUDriverPtr driver = dom->conn->privateData;
5210
    qemuDomainObjPrivatePtr priv;
5211
    virDomainObjPtr vm;
5212
    virDomainDefPtr def;
5213
    int ret = -1;
5214
    virCapsPtr caps = NULL;
5215
    qemuAgentCPUInfoPtr cpuinfo = NULL;
5216
    int ncpuinfo = -1;
5217
    size_t i;
5218

5219 5220
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
5221
                  VIR_DOMAIN_VCPU_MAXIMUM |
5222
                  VIR_DOMAIN_VCPU_GUEST, -1);
5223

5224
    if (!(vm = qemuDomObjFromDomain(dom)))
5225 5226 5227
        return -1;

    priv = vm->privateData;
5228

5229
    if (virDomainGetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
5230 5231
        goto cleanup;

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

5235
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
5236
                                        vm, &flags, &def) < 0)
5237
        goto cleanup;
5238

5239
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
5240
        def = vm->def;
5241

5242
    if (flags & VIR_DOMAIN_VCPU_GUEST) {
5243 5244 5245 5246 5247 5248 5249 5250 5251 5252
        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;

5253
        if (!qemuDomainAgentAvailable(priv, true))
5254 5255
            goto endjob;

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

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

5266
 endjob:
E
Eric Blake 已提交
5267
        if (!qemuDomainObjEndJob(driver, vm))
5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288
            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;
5289 5290 5291
    }


5292
 cleanup:
5293
    if (vm)
5294
        virObjectUnlock(vm);
5295
    virObjectUnref(caps);
5296
    VIR_FREE(cpuinfo);
5297 5298 5299
    return ret;
}

5300
static int
5301
qemuDomainGetMaxVcpus(virDomainPtr dom)
5302
{
5303 5304
    return qemuDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
5305 5306
}

5307
static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
5308
{
5309
    virQEMUDriverPtr driver = dom->conn->privateData;
5310 5311 5312
    virDomainObjPtr vm;
    int ret = -1;

5313 5314
    memset(seclabel, 0, sizeof(*seclabel));

5315 5316
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
5317

5318 5319 5320
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

5321
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
5322 5323 5324
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341
        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 已提交
5342
    if (virDomainObjIsActive(vm)) {
5343
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
5344
                                              vm->def, vm->pid, seclabel) < 0) {
5345 5346
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
5347
            goto cleanup;
5348 5349 5350 5351 5352
        }
    }

    ret = 0;

5353
 cleanup:
5354
    if (vm)
5355
        virObjectUnlock(vm);
5356 5357 5358
    return ret;
}

M
Marcelo Cerri 已提交
5359 5360 5361
static int qemuDomainGetSecurityLabelList(virDomainPtr dom,
                                          virSecurityLabelPtr* seclabels)
{
5362
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Marcelo Cerri 已提交
5363
    virDomainObjPtr vm;
5364 5365
    size_t i;
    int ret = -1;
M
Marcelo Cerri 已提交
5366

5367 5368
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
M
Marcelo Cerri 已提交
5369

5370 5371 5372
    if (virDomainGetSecurityLabelListEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

M
Marcelo Cerri 已提交
5373 5374 5375 5376 5377 5378 5379 5380
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
        goto cleanup;
    }

    /*
5381
     * Check the comment in qemuDomainGetSecurityLabel function.
M
Marcelo Cerri 已提交
5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418
     */
    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);
    }

5419
 cleanup:
M
Marcelo Cerri 已提交
5420
    if (vm)
5421
        virObjectUnlock(vm);
M
Marcelo Cerri 已提交
5422 5423
    return ret;
}
5424 5425


5426 5427
static int qemuNodeGetSecurityModel(virConnectPtr conn,
                                    virSecurityModelPtr secmodel)
5428
{
5429
    virQEMUDriverPtr driver = conn->privateData;
5430
    char *p;
5431
    int ret = 0;
5432
    virCapsPtr caps = NULL;
5433

5434 5435
    memset(secmodel, 0, sizeof(*secmodel));

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

5439 5440 5441
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

5442
    /* We treat no driver as success, but simply return no data in *secmodel */
5443 5444
    if (caps->host.nsecModels == 0 ||
        caps->host.secModels[0].model == NULL)
5445
        goto cleanup;
5446

5447
    p = caps->host.secModels[0].model;
5448
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
5449 5450 5451
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN-1);
5452 5453
        ret = -1;
        goto cleanup;
5454 5455 5456
    }
    strcpy(secmodel->model, p);

5457
    p = caps->host.secModels[0].doi;
5458
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
5459 5460 5461
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
5462 5463
        ret = -1;
        goto cleanup;
5464 5465
    }
    strcpy(secmodel->doi, p);
5466

5467
 cleanup:
5468
    virObjectUnref(caps);
5469
    return ret;
5470 5471
}

5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533

/**
 * qemuDomainSaveImageUpdateDef:
 * @driver: qemu driver data
 * @def: def of the domain from the save image
 * @newxml: user provided replacement XML
 *
 * Returns the new domain definition in case @newxml is ABI compatible with the
 * guest.
 */
static virDomainDefPtr
qemuDomainSaveImageUpdateDef(virQEMUDriverPtr driver,
                             virDomainDefPtr def,
                             const char *newxml)
{
    virDomainDefPtr ret = NULL;
    virDomainDefPtr newdef_migr = NULL;
    virDomainDefPtr newdef = NULL;
    virCapsPtr caps = NULL;

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

    if (!(newdef = virDomainDefParseString(newxml, caps, driver->xmlopt,
                                           QEMU_EXPECTED_VIRT_TYPES,
                                           VIR_DOMAIN_XML_INACTIVE)))
        goto cleanup;

    if (!(newdef_migr = qemuDomainDefCopy(driver,
                                          newdef,
                                          VIR_DOMAIN_XML_MIGRATABLE)))
        goto cleanup;

    if (!virDomainDefCheckABIStability(def, newdef_migr)) {
        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, newdef))
            goto cleanup;

        /* use the user provided XML */
        ret = newdef;
        newdef = NULL;
    } else {
        ret = newdef_migr;
        newdef_migr = NULL;
    }

 cleanup:
    virObjectUnref(caps);
    virDomainDefFree(newdef);
    virDomainDefFree(newdef_migr);

    return ret;
}


5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549
/**
 * qemuDomainSaveImageOpen:
 * @driver: qemu driver data
 * @path: path of the save image
 * @ret_def: returns domain definition created from the XML stored in the image
 * @ret_header: returns structure filled with data from the image header
 * @xmlout: returns the XML from the image file (may be NULL)
 * @bypass_cache: bypass cache when opening the file
 * @wrapperFd: returns the file wrapper structure
 * @open_write: open the file for writing (for updates)
 * @unlink_corrupt: remove the image file if it is corrupted
 *
 * Returns the opened fd of the save image file and fills the apropriate fields
 * on success. On error returns -1 on most failures, -3 if corrupt image was
 * unlinked (no error raised).
 */
5550
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
5551
qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
5552 5553
                        const char *path,
                        virDomainDefPtr *ret_def,
5554
                        virQEMUSaveHeaderPtr ret_header,
5555
                        char **xmlout,
J
Jiri Denemark 已提交
5556 5557
                        bool bypass_cache,
                        virFileWrapperFdPtr *wrapperFd,
5558
                        bool open_write,
5559
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
5560
{
W
Wen Congyang 已提交
5561
    int fd = -1;
5562
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5563 5564
    char *xml = NULL;
    virDomainDefPtr def = NULL;
5565
    int oflags = open_write ? O_RDWR : O_RDONLY;
5566
    virCapsPtr caps = NULL;
5567

5568
    if (bypass_cache) {
5569
        int directFlag = virFileDirectFdFlag();
5570
        if (directFlag < 0) {
5571 5572
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
5573 5574
            goto error;
        }
5575
        oflags |= directFlag;
5576
    }
5577

5578 5579 5580
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto error;

5581
    if ((fd = qemuOpenFile(driver, NULL, path, oflags, NULL, NULL)) < 0)
E
Eric Blake 已提交
5582
        goto error;
J
Jiri Denemark 已提交
5583 5584 5585
    if (bypass_cache &&
        !(*wrapperFd = virFileWrapperFdNew(&fd, path,
                                           VIR_FILE_WRAPPER_BYPASS_CACHE)))
5586
        goto error;
5587 5588

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
5589 5590 5591 5592 5593 5594 5595 5596 5597
        if (unlink_corrupt) {
            if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove corrupt file: %s"),
                                     path);
                goto error;
            }
            return -3;
        }
5598 5599
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
5600
        goto error;
5601 5602
    }

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

5606
        if (memcmp(header.magic, QEMU_SAVE_PARTIAL,
E
Eric Blake 已提交
5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618
                   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;
            }
        }
5619
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", msg);
J
Jiri Denemark 已提交
5620
        goto error;
5621 5622
    }

5623
    if (header.version > QEMU_SAVE_VERSION) {
5624 5625 5626 5627
        /* convert endianess and try again */
        bswap_header(&header);
    }

5628
    if (header.version > QEMU_SAVE_VERSION) {
5629 5630
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("image version is not supported (%d > %d)"),
5631
                       header.version, QEMU_SAVE_VERSION);
J
Jiri Denemark 已提交
5632
        goto error;
5633 5634
    }

5635
    if (header.xml_len <= 0) {
5636 5637
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
5638
        goto error;
5639 5640
    }

5641
    if (VIR_ALLOC_N(xml, header.xml_len) < 0)
J
Jiri Denemark 已提交
5642
        goto error;
5643 5644

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
5645 5646
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
5647
        goto error;
5648 5649 5650
    }

    /* Create a domain from this XML */
5651
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
5652
                                        QEMU_EXPECTED_VIRT_TYPES,
5653
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
5654
        goto error;
5655

5656 5657 5658 5659
    if (xmlout)
        *xmlout = xml;
    else
        VIR_FREE(xml);
5660

J
Jiri Denemark 已提交
5661 5662
    *ret_def = def;
    *ret_header = header;
5663

5664 5665
    virObjectUnref(caps);

J
Jiri Denemark 已提交
5666
    return fd;
5667

5668
 error:
J
Jiri Denemark 已提交
5669 5670
    virDomainDefFree(def);
    VIR_FREE(xml);
5671
    VIR_FORCE_CLOSE(fd);
5672
    virObjectUnref(caps);
J
Jiri Denemark 已提交
5673 5674 5675 5676

    return -1;
}

5677 5678
static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6)
qemuDomainSaveImageStartVM(virConnectPtr conn,
5679
                           virQEMUDriverPtr driver,
5680 5681
                           virDomainObjPtr vm,
                           int *fd,
E
Eric Blake 已提交
5682
                           const virQEMUSaveHeader *header,
5683 5684
                           const char *path,
                           bool start_paused)
J
Jiri Denemark 已提交
5685 5686
{
    int ret = -1;
5687
    virObjectEventPtr event;
J
Jiri Denemark 已提交
5688
    int intermediatefd = -1;
5689
    virCommandPtr cmd = NULL;
5690
    char *errbuf = NULL;
5691
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
J
Jiri Denemark 已提交
5692

5693 5694 5695
    if ((header->version == 2) &&
        (header->compressed != QEMU_SAVE_FORMAT_RAW)) {
        if (!(cmd = qemuCompressGetCommand(header->compressed)))
5696
            goto cleanup;
5697

5698 5699
        intermediatefd = *fd;
        *fd = -1;
5700

5701 5702 5703 5704
        virCommandSetInputFD(cmd, intermediatefd);
        virCommandSetOutputFD(cmd, fd);
        virCommandSetErrorBuffer(cmd, &errbuf);
        virCommandDoAsyncIO(cmd);
5705

5706 5707 5708
        if (virCommandRunAsync(cmd, NULL) < 0) {
            *fd = intermediatefd;
            goto cleanup;
5709 5710
        }
    }
J
Jiri Denemark 已提交
5711

5712
    /* Set the migration source and start it up. */
5713 5714
    ret = qemuProcessStart(conn, driver, vm, QEMU_ASYNC_JOB_NONE,
                           "stdio", *fd, path, NULL,
5715 5716
                           VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
                           VIR_QEMU_PROCESS_START_PAUSED);
J
Jiri Denemark 已提交
5717

5718
    if (intermediatefd != -1) {
5719
        if (ret < 0) {
5720 5721 5722
            /* if there was an error setting up qemu, the intermediate
             * process will wait forever to write to stdout, so we
             * must manually kill it.
5723 5724
             */
            VIR_FORCE_CLOSE(intermediatefd);
5725
            VIR_FORCE_CLOSE(*fd);
5726 5727
        }

5728 5729
        if (virCommandWait(cmd, NULL) < 0) {
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
5730
            ret = -1;
5731
        }
5732
        VIR_DEBUG("Decompression binary stderr: %s", NULLSTR(errbuf));
5733
    }
5734
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
5735

5736 5737 5738
    if (VIR_CLOSE(*fd) < 0) {
        virReportSystemError(errno, _("cannot close file: %s"), path);
        ret = -1;
5739
    }
J
Jiri Denemark 已提交
5740

5741
    if (ret < 0) {
5742
        virDomainAuditStart(vm, "restored", false);
5743
        goto cleanup;
5744
    }
5745

5746
    event = virDomainEventLifecycleNewFromObj(vm,
5747 5748
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
5749
    virDomainAuditStart(vm, "restored", true);
J
Jiri Denemark 已提交
5750 5751 5752
    if (event)
        qemuDomainEventQueue(driver, event);

5753

5754 5755
    /* If it was running before, resume it now unless caller requested pause. */
    if (header->was_running && !start_paused) {
J
Jiri Denemark 已提交
5756
        if (qemuProcessStartCPUs(driver, vm, conn,
5757 5758
                                 VIR_DOMAIN_RUNNING_RESTORED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
5759
            if (virGetLastError() == NULL)
5760 5761
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("failed to resume domain"));
5762
            goto cleanup;
5763
        }
5764
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
5765
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
5766
            goto cleanup;
5767
        }
5768 5769 5770
    } else {
        int detail = (start_paused ? VIR_DOMAIN_EVENT_SUSPENDED_PAUSED :
                      VIR_DOMAIN_EVENT_SUSPENDED_RESTORED);
5771
        event = virDomainEventLifecycleNewFromObj(vm,
5772 5773 5774 5775
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         detail);
        if (event)
            qemuDomainEventQueue(driver, event);
5776
    }
J
Jiri Denemark 已提交
5777

5778
    ret = 0;
5779

5780
 cleanup:
5781
    virCommandFree(cmd);
5782
    VIR_FREE(errbuf);
5783
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
5784
                                                 vm->def, path) < 0)
5785
        VIR_WARN("failed to restore save state label on %s", path);
5786
    virObjectUnref(cfg);
J
Jiri Denemark 已提交
5787 5788 5789
    return ret;
}

5790
static int
5791 5792 5793 5794
qemuDomainRestoreFlags(virConnectPtr conn,
                       const char *path,
                       const char *dxml,
                       unsigned int flags)
5795
{
5796
    virQEMUDriverPtr driver = conn->privateData;
5797
    qemuDomainObjPrivatePtr priv = NULL;
J
Jiri Denemark 已提交
5798 5799
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
5800 5801 5802
    char *xml = NULL;
    char *xmlout = NULL;
    const char *newxml = dxml;
J
Jiri Denemark 已提交
5803 5804
    int fd = -1;
    int ret = -1;
5805
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5806
    virFileWrapperFdPtr wrapperFd = NULL;
5807
    bool hook_taint = false;
J
Jiri Denemark 已提交
5808

5809 5810 5811
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5812

J
Jiri Denemark 已提交
5813

5814
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, &xml,
5815
                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
5816
                                 &wrapperFd, false, false);
J
Jiri Denemark 已提交
5817 5818 5819
    if (fd < 0)
        goto cleanup;

5820 5821 5822
    if (virDomainRestoreFlagsEnsureACL(conn, def) < 0)
        goto cleanup;

5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843
    if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
        int hookret;

        if ((hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, def->name,
                                   VIR_HOOK_QEMU_OP_RESTORE,
                                   VIR_HOOK_SUBOP_BEGIN,
                                   NULL,
                                   dxml ? dxml : xml,
                                   &xmlout)) < 0)
            goto cleanup;

        if (hookret == 0 && xmlout) {
            VIR_DEBUG("Using hook-filtered domain XML: %s", xmlout);
            hook_taint = true;
            newxml = xmlout;
        }
    }

    if (newxml) {
        virDomainDefPtr tmp;
        if (!(tmp = qemuDomainSaveImageUpdateDef(driver, def, newxml)))
5844 5845 5846
            goto cleanup;

        virDomainDefFree(def);
5847
        def = tmp;
5848 5849
    }

5850
    if (!(vm = virDomainObjListAdd(driver->domains, def,
5851
                                   driver->xmlopt,
5852 5853 5854
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jiri Denemark 已提交
5855 5856 5857
        goto cleanup;
    def = NULL;

5858 5859 5860 5861 5862
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        header.was_running = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        header.was_running = 0;

5863 5864 5865 5866 5867
    if (hook_taint) {
        priv = vm->privateData;
        priv->hookRun = true;
    }

5868
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
5869 5870
        goto cleanup;

5871 5872
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     false);
J
Jiri Denemark 已提交
5873
    if (virFileWrapperFdClose(wrapperFd) < 0)
5874
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5875

5876
    if (!qemuDomainObjEndJob(driver, vm)) {
5877
        vm = NULL;
5878
    } else if (ret < 0 && !vm->persistent) {
5879
        qemuDomainRemoveInactive(driver, vm);
J
Jiri Denemark 已提交
5880 5881
        vm = NULL;
    }
5882

5883
 cleanup:
5884
    virDomainDefFree(def);
5885
    VIR_FORCE_CLOSE(fd);
5886 5887
    VIR_FREE(xml);
    VIR_FREE(xmlout);
J
Jiri Denemark 已提交
5888
    virFileWrapperFdFree(wrapperFd);
5889
    if (vm)
5890
        virObjectUnlock(vm);
5891
    return ret;
D
Daniel P. Berrange 已提交
5892 5893
}

5894 5895 5896 5897 5898 5899 5900
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

5901 5902 5903 5904
static char *
qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
                              unsigned int flags)
{
5905
    virQEMUDriverPtr driver = conn->privateData;
5906 5907 5908
    char *ret = NULL;
    virDomainDefPtr def = NULL;
    int fd = -1;
5909
    virQEMUSaveHeader header;
5910 5911 5912 5913

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

5914
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, NULL,
5915
                                 false, NULL, false, false);
5916 5917 5918 5919

    if (fd < 0)
        goto cleanup;

5920 5921 5922
    if (virDomainSaveImageGetXMLDescEnsureACL(conn, def) < 0)
        goto cleanup;

5923
    ret = qemuDomainDefFormatXML(driver, def, flags);
5924

5925
 cleanup:
5926 5927 5928 5929 5930 5931 5932 5933 5934
    virDomainDefFree(def);
    VIR_FORCE_CLOSE(fd);
    return ret;
}

static int
qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
                             const char *dxml, unsigned int flags)
{
5935
    virQEMUDriverPtr driver = conn->privateData;
5936 5937
    int ret = -1;
    virDomainDefPtr def = NULL;
5938
    virDomainDefPtr newdef = NULL;
5939
    int fd = -1;
5940
    virQEMUSaveHeader header;
5941 5942
    char *xml = NULL;
    size_t len;
5943
    int state = -1;
5944

5945 5946
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5947

5948 5949 5950 5951 5952
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

5953 5954
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, &xml,
                                 false, NULL, true, false);
5955

5956
    if (fd < 0)
5957 5958
        goto cleanup;

5959 5960 5961
    if (virDomainSaveImageDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

5962 5963 5964 5965 5966 5967 5968 5969 5970 5971
    if (STREQ(xml, dxml) &&
        (state < 0 || state == header.was_running)) {
        /* no change to the XML */
        ret = 0;
        goto cleanup;
    }

    if (state >= 0)
        header.was_running = state;

5972 5973 5974
    if (!(newdef = qemuDomainSaveImageUpdateDef(driver, def, dxml)))
        goto cleanup;

5975 5976
    VIR_FREE(xml);

5977
    xml = qemuDomainDefFormatXML(driver, newdef,
5978
                                 VIR_DOMAIN_XML_INACTIVE |
5979 5980
                                 VIR_DOMAIN_XML_SECURE |
                                 VIR_DOMAIN_XML_MIGRATABLE);
5981 5982 5983 5984 5985
    if (!xml)
        goto cleanup;
    len = strlen(xml) + 1;

    if (len > header.xml_len) {
5986 5987
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("new xml too large to fit in file"));
5988 5989
        goto cleanup;
    }
5990
    if (VIR_EXPAND_N(xml, len, header.xml_len - len) < 0)
5991 5992
        goto cleanup;

5993
    if (lseek(fd, 0, SEEK_SET) != 0) {
5994 5995 5996
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
5997 5998
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
5999 6000 6001 6002 6003 6004 6005
        VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("failed to write xml to '%s'"), path);
        goto cleanup;
    }

    ret = 0;

6006
 cleanup:
6007
    virDomainDefFree(def);
6008
    virDomainDefFree(newdef);
6009 6010 6011 6012 6013
    VIR_FORCE_CLOSE(fd);
    VIR_FREE(xml);
    return ret;
}

E
Eric Blake 已提交
6014 6015
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
6016 6017
static int
qemuDomainObjRestore(virConnectPtr conn,
6018
                     virQEMUDriverPtr driver,
6019
                     virDomainObjPtr vm,
6020
                     const char *path,
6021
                     bool start_paused,
6022
                     bool bypass_cache)
J
Jiri Denemark 已提交
6023 6024
{
    virDomainDefPtr def = NULL;
6025
    qemuDomainObjPrivatePtr priv = vm->privateData;
J
Jiri Denemark 已提交
6026 6027
    int fd = -1;
    int ret = -1;
6028 6029
    char *xml = NULL;
    char *xmlout = NULL;
6030
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
6031
    virFileWrapperFdPtr wrapperFd = NULL;
J
Jiri Denemark 已提交
6032

6033
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, &xml,
6034
                                 bypass_cache, &wrapperFd, false, true);
E
Eric Blake 已提交
6035 6036 6037
    if (fd < 0) {
        if (fd == -3)
            ret = 1;
J
Jiri Denemark 已提交
6038
        goto cleanup;
E
Eric Blake 已提交
6039
    }
J
Jiri Denemark 已提交
6040

6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063
    if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
        int hookret;

        if ((hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, def->name,
                                   VIR_HOOK_QEMU_OP_RESTORE,
                                   VIR_HOOK_SUBOP_BEGIN,
                                   NULL, xml, &xmlout)) < 0)
            goto cleanup;

        if (hookret == 0 && xmlout) {
            virDomainDefPtr tmp;

            VIR_DEBUG("Using hook-filtered domain XML: %s", xmlout);

            if (!(tmp = qemuDomainSaveImageUpdateDef(driver, def, xmlout)))
                goto cleanup;

            virDomainDefFree(def);
            def = tmp;
            priv->hookRun = true;
        }
    }

J
Jiri Denemark 已提交
6064 6065 6066 6067 6068 6069
    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);
6070 6071 6072 6073 6074
        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 已提交
6075 6076 6077
        goto cleanup;
    }

6078
    virDomainObjAssignDef(vm, def, true, NULL);
J
Jiri Denemark 已提交
6079 6080
    def = NULL;

6081 6082
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     start_paused);
J
Jiri Denemark 已提交
6083
    if (virFileWrapperFdClose(wrapperFd) < 0)
6084
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
6085

6086
 cleanup:
6087 6088
    VIR_FREE(xml);
    VIR_FREE(xmlout);
J
Jiri Denemark 已提交
6089
    virDomainDefFree(def);
6090
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
6091
    virFileWrapperFdFree(wrapperFd);
J
Jiri Denemark 已提交
6092 6093 6094
    return ret;
}

D
Daniel P. Berrange 已提交
6095

6096
static char *qemuDomainGetXMLDesc(virDomainPtr dom,
6097 6098
                                  unsigned int flags)
{
6099
    virQEMUDriverPtr driver = dom->conn->privateData;
6100 6101
    virDomainObjPtr vm;
    char *ret = NULL;
6102
    unsigned long long balloon;
6103
    int err = 0;
6104
    qemuDomainObjPrivatePtr priv;
6105

6106
    /* Flags checked by virDomainDefFormat */
6107

6108
    if (!(vm = qemuDomObjFromDomain(dom)))
6109
        goto cleanup;
D
Daniel P. Berrange 已提交
6110

6111 6112
    priv = vm->privateData;

6113 6114 6115
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

6116 6117 6118
    /* Refresh current memory based on balloon info if supported */
    if ((vm->def->memballoon != NULL) &&
        (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
6119
        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT) &&
6120
        (virDomainObjIsActive(vm))) {
6121 6122
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
6123
        if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
6124
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
6125 6126
                goto cleanup;

6127
            if (!virDomainObjIsActive(vm)) {
6128 6129
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
6130 6131 6132
                goto endjob;
            }

6133
            qemuDomainObjEnterMonitor(driver, vm);
6134
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
6135
            qemuDomainObjExitMonitor(driver, vm);
6136

6137
 endjob:
E
Eric Blake 已提交
6138
            if (!qemuDomainObjEndJob(driver, vm)) {
6139 6140 6141
                vm = NULL;
                goto cleanup;
            }
6142 6143 6144
            if (err < 0)
                goto cleanup;
            if (err > 0)
6145
                vm->def->mem.cur_balloon = balloon;
6146 6147
            /* err == 0 indicates no balloon support, so ignore it */
        }
6148
    }
6149

6150 6151 6152 6153
    if ((flags & VIR_DOMAIN_XML_MIGRATABLE))
        flags |= QEMU_DOMAIN_FORMAT_LIVE_FLAGS;

    ret = qemuDomainFormatXML(driver, vm, flags);
6154

6155
 cleanup:
6156
    if (vm)
6157
        virObjectUnlock(vm);
6158
    return ret;
D
Daniel P. Berrange 已提交
6159 6160 6161
}


6162 6163 6164 6165
static char *qemuConnectDomainXMLFromNative(virConnectPtr conn,
                                            const char *format,
                                            const char *config,
                                            unsigned int flags)
E
Eric Blake 已提交
6166
{
6167
    virQEMUDriverPtr driver = conn->privateData;
6168 6169
    virDomainDefPtr def = NULL;
    char *xml = NULL;
6170
    virCapsPtr caps = NULL;
6171

E
Eric Blake 已提交
6172 6173
    virCheckFlags(0, NULL);

6174 6175 6176
    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
        goto cleanup;

6177
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
6178 6179
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
6180 6181 6182
        goto cleanup;
    }

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

6186
    def = qemuParseCommandLineString(caps, driver->xmlopt, config,
6187
                                     NULL, NULL, NULL);
6188 6189 6190
    if (!def)
        goto cleanup;

6191
    if (!def->name && VIR_STRDUP(def->name, "unnamed") < 0)
6192 6193
        goto cleanup;

6194
    xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE);
6195

6196
 cleanup:
6197
    virDomainDefFree(def);
6198
    virObjectUnref(caps);
6199 6200 6201
    return xml;
}

6202 6203 6204 6205
static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
                                          const char *format,
                                          const char *xmlData,
                                          unsigned int flags)
E
Eric Blake 已提交
6206
{
6207
    virQEMUDriverPtr driver = conn->privateData;
6208
    virDomainDefPtr def = NULL;
6209
    virDomainChrSourceDef monConfig;
6210
    virQEMUCapsPtr qemuCaps = NULL;
T
tangchen 已提交
6211
    bool monitor_json = false;
E
Eric Blake 已提交
6212
    virCommandPtr cmd = NULL;
6213
    char *ret = NULL;
6214
    size_t i;
6215
    virQEMUDriverConfigPtr cfg;
6216
    virCapsPtr caps = NULL;
6217

E
Eric Blake 已提交
6218 6219
    virCheckFlags(0, NULL);

6220
    cfg = virQEMUDriverGetConfig(driver);
6221

6222 6223 6224
    if (virConnectDomainXMLToNativeEnsureACL(conn) < 0)
        goto cleanup;

6225
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
6226 6227
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
6228 6229 6230
        goto cleanup;
    }

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

6234
    def = virDomainDefParseString(xmlData, caps, driver->xmlopt,
6235 6236
                                  QEMU_EXPECTED_VIRT_TYPES,
                                  VIR_DOMAIN_XML_INACTIVE);
6237 6238 6239
    if (!def)
        goto cleanup;

6240
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
6241 6242
        goto cleanup;

6243 6244
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
6245 6246 6247
     * directly. We convert those configs into generic 'ethernet'
     * config and assume the user has suitable 'ifup-qemu' scripts
     */
6248
    for (i = 0; i < def->nnets; i++) {
6249
        virDomainNetDefPtr net = def->nets[i];
6250
        int bootIndex = net->info.bootIndex;
6251
        char *model = net->model;
6252
        virMacAddr mac = net->mac;
6253

6254 6255 6256 6257
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

6258
            VIR_FREE(net->data.network.name);
6259 6260 6261 6262
            VIR_FREE(net->data.network.portgroup);
            if ((actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
                (brname = virDomainNetGetActualBridgeName(net))) {

6263 6264
                char *brnamecopy;
                if (VIR_STRDUP(brnamecopy, brname) < 0)
6265 6266 6267 6268
                    goto cleanup;

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

6269
                memset(net, 0, sizeof(*net));
6270 6271

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
6272
                net->script = NULL;
6273 6274 6275 6276 6277 6278 6279
                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);
6280
                memset(net, 0, sizeof(*net));
6281 6282

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
6283
                net->script = NULL;
6284 6285 6286 6287 6288
                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);
6289

6290
            memset(net, 0, sizeof(*net));
6291 6292

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
6293
            net->script = NULL;
6294 6295 6296
            net->data.ethernet.dev = NULL;
            net->data.ethernet.ipaddr = NULL;
        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
6297
            char *script = net->script;
6298 6299 6300
            char *brname = net->data.bridge.brname;
            char *ipaddr = net->data.bridge.ipaddr;

6301
            memset(net, 0, sizeof(*net));
6302 6303

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
6304
            net->script = script;
6305 6306 6307
            net->data.ethernet.dev = brname;
            net->data.ethernet.ipaddr = ipaddr;
        }
6308

6309
        VIR_FREE(net->virtPortProfile);
6310
        net->info.bootIndex = bootIndex;
6311
        net->model = model;
6312
        net->mac = mac;
6313 6314
    }

6315
    monitor_json = virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON);
T
tangchen 已提交
6316

6317
    if (qemuProcessPrepareMonitorChr(cfg, &monConfig, def->name) < 0)
6318
        goto cleanup;
6319

6320
    if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
6321 6322
        goto cleanup;

6323 6324 6325
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
        goto cleanup;

6326
    /* do fake auto-alloc of graphics ports, if such config is used */
6327
    for (i = 0; i < def->ngraphics; ++i) {
6328 6329 6330 6331 6332
        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) {
6333
            size_t j;
6334 6335 6336 6337 6338 6339
            bool needTLSPort = false;
            bool needPort = false;
            int defaultMode = graphics->data.spice.defaultMode;

            if (graphics->data.spice.autoport) {
                /* check if tlsPort or port need allocation */
6340
                for (j = 0; j < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST; j++) {
6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360
                    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:
6361 6362
                            if (cfg->spiceTLS)
                                needTLSPort = true;
6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378
                            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;
        }
    }

6379
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
6380
                                     &monConfig, monitor_json, qemuCaps,
C
Cole Robinson 已提交
6381 6382 6383
                                     NULL, -1, NULL,
                                     VIR_NETDEV_VPORT_PROFILE_OP_NO_OP,
                                     &buildCommandLineCallbacks,
6384 6385
                                     true,
                                     qemuCheckFips())))
6386 6387
        goto cleanup;

E
Eric Blake 已提交
6388
    ret = virCommandToString(cmd);
6389

6390
 cleanup:
6391

6392
    virObjectUnref(qemuCaps);
E
Eric Blake 已提交
6393
    virCommandFree(cmd);
6394
    virDomainDefFree(def);
6395
    virObjectUnref(caps);
6396
    virObjectUnref(cfg);
6397 6398 6399 6400
    return ret;
}


6401 6402
static int qemuConnectListDefinedDomains(virConnectPtr conn,
                                         char **const names, int nnames) {
6403
    virQEMUDriverPtr driver = conn->privateData;
6404
    int ret = -1;
6405

6406 6407 6408
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        goto cleanup;

6409
    ret = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
6410 6411
                                           virConnectListDefinedDomainsCheckACL,
                                           conn);
6412

6413
 cleanup:
6414
    return ret;
D
Daniel P. Berrange 已提交
6415 6416
}

6417 6418
static int qemuConnectNumOfDefinedDomains(virConnectPtr conn)
{
6419
    virQEMUDriverPtr driver = conn->privateData;
6420 6421 6422 6423
    int ret = -1;

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

6425
    ret = virDomainObjListNumOfDomains(driver->domains, false,
6426 6427
                                       virConnectNumOfDefinedDomainsCheckACL,
                                       conn);
6428

6429
 cleanup:
6430
    return ret;
D
Daniel P. Berrange 已提交
6431 6432 6433
}


6434 6435
static int
qemuDomainObjStart(virConnectPtr conn,
6436
                   virQEMUDriverPtr driver,
6437
                   virDomainObjPtr vm,
6438
                   unsigned int flags)
J
Jiri Denemark 已提交
6439 6440 6441
{
    int ret = -1;
    char *managed_save;
6442 6443 6444 6445
    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;
6446 6447 6448
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;

    start_flags |= start_paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
6449
    start_flags |= autodestroy ? VIR_QEMU_PROCESS_START_AUTODESTROY : 0;
J
Jiri Denemark 已提交
6450 6451 6452

    /*
     * If there is a managed saved state restore it instead of starting
6453
     * from scratch. The old state is removed once the restoring succeeded.
J
Jiri Denemark 已提交
6454 6455
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
6456 6457 6458 6459

    if (!managed_save)
        goto cleanup;

E
Eric Blake 已提交
6460
    if (virFileExists(managed_save)) {
6461 6462 6463 6464 6465 6466 6467
        if (force_boot) {
            if (unlink(managed_save) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove managed save file %s"),
                                     managed_save);
                goto cleanup;
            }
6468
            vm->hasManagedSave = false;
6469 6470
        } else {
            ret = qemuDomainObjRestore(conn, driver, vm, managed_save,
6471
                                       start_paused, bypass_cache);
J
Jiri Denemark 已提交
6472

6473 6474 6475 6476 6477 6478
            if (ret == 0) {
                if (unlink(managed_save) < 0)
                    VIR_WARN("Failed to remove the managed state %s", managed_save);
                else
                    vm->hasManagedSave = false;

6479 6480
                goto cleanup;
            } else if (ret < 0) {
6481 6482
                VIR_WARN("Unable to restore from managed state %s. "
                         "Maybe the file is corrupted?", managed_save);
E
Eric Blake 已提交
6483
                goto cleanup;
6484 6485
            } else {
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
6486
            }
6487
        }
J
Jiri Denemark 已提交
6488 6489
    }

6490 6491
    ret = qemuProcessStart(conn, driver, vm, QEMU_ASYNC_JOB_NONE,
                           NULL, -1, NULL, NULL,
6492
                           VIR_NETDEV_VPORT_PROFILE_OP_CREATE, start_flags);
6493
    virDomainAuditStart(vm, "booted", ret >= 0);
6494
    if (ret >= 0) {
6495
        virObjectEventPtr event =
6496
            virDomainEventLifecycleNewFromObj(vm,
J
Jiri Denemark 已提交
6497 6498
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
6499
        if (event) {
J
Jiri Denemark 已提交
6500
            qemuDomainEventQueue(driver, event);
6501
            if (start_paused) {
6502
                event = virDomainEventLifecycleNewFromObj(vm,
6503 6504 6505 6506 6507 6508
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
                if (event)
                    qemuDomainEventQueue(driver, event);
            }
        }
J
Jiri Denemark 已提交
6509 6510
    }

6511
 cleanup:
J
Jiri Denemark 已提交
6512 6513 6514 6515
    VIR_FREE(managed_save);
    return ret;
}

6516
static int
6517
qemuDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
6518
{
6519
    virQEMUDriverPtr driver = dom->conn->privateData;
6520 6521
    virDomainObjPtr vm;
    int ret = -1;
6522

6523
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
6524
                  VIR_DOMAIN_START_AUTODESTROY |
6525 6526
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
6527

6528 6529
    virNWFilterReadLockFilterUpdates();

6530
    if (!(vm = qemuDomObjFromDomain(dom)))
6531
        goto cleanup;
6532

6533 6534 6535
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

6536
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
6537 6538 6539
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
6540 6541
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is already running"));
6542 6543 6544
        goto endjob;
    }

6545
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
6546 6547 6548
        goto endjob;

    ret = 0;
6549

6550
 endjob:
E
Eric Blake 已提交
6551
    if (!qemuDomainObjEndJob(driver, vm))
6552
        vm = NULL;
6553

6554
 cleanup:
6555
    if (vm)
6556
        virObjectUnlock(vm);
6557
    virNWFilterUnlockFilterUpdates();
6558
    return ret;
D
Daniel P. Berrange 已提交
6559 6560
}

6561
static int
6562
qemuDomainCreate(virDomainPtr dom)
6563
{
6564
    return qemuDomainCreateWithFlags(dom, 0);
6565 6566
}

6567 6568
static virDomainPtr qemuDomainDefineXML(virConnectPtr conn, const char *xml)
{
6569
    virQEMUDriverPtr driver = conn->privateData;
6570
    virDomainDefPtr def = NULL;
6571
    virDomainDefPtr oldDef = NULL;
6572
    virDomainObjPtr vm = NULL;
6573
    virDomainPtr dom = NULL;
6574
    virObjectEventPtr event = NULL;
6575
    virQEMUCapsPtr qemuCaps = NULL;
6576
    virQEMUDriverConfigPtr cfg;
6577
    virCapsPtr caps = NULL;
6578

6579
    cfg = virQEMUDriverGetConfig(driver);
6580 6581 6582 6583

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

6584
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
6585
                                        QEMU_EXPECTED_VIRT_TYPES,
6586
                                        VIR_DOMAIN_XML_INACTIVE)))
6587
        goto cleanup;
6588

6589 6590 6591
    if (virDomainDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

6592
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
6593 6594
        goto cleanup;

6595
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
6596 6597
        goto cleanup;

6598
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
6599 6600
        goto cleanup;

6601
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
6602 6603
        goto cleanup;

6604
    if (!(vm = virDomainObjListAdd(driver->domains, def,
6605
                                   driver->xmlopt,
6606
                                   0, &oldDef)))
6607 6608
        goto cleanup;

6609
    def = NULL;
E
Eric Blake 已提交
6610 6611
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
6612
                       _("domain has active block job"));
6613
        virDomainObjAssignDef(vm, NULL, false, NULL);
E
Eric Blake 已提交
6614 6615
        goto cleanup;
    }
6616
    vm->persistent = 1;
6617

6618
    if (virDomainSaveConfig(cfg->configDir,
6619
                            vm->newDef ? vm->newDef : vm->def) < 0) {
6620
        if (oldDef) {
M
Michal Privoznik 已提交
6621 6622 6623 6624
            /* 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))
6625
                vm->newDef = oldDef;
M
Michal Privoznik 已提交
6626
            else
6627 6628
                vm->def = oldDef;
            oldDef = NULL;
M
Michal Privoznik 已提交
6629 6630 6631 6632 6633 6634
        } else {
            /* Brand new domain. Remove it */
            VIR_INFO("Deleting domain '%s'", vm->def->name);
            qemuDomainRemoveInactive(driver, vm);
            vm = NULL;
        }
6635
        goto cleanup;
6636 6637
    }

6638
    event = virDomainEventLifecycleNewFromObj(vm,
6639
                                     VIR_DOMAIN_EVENT_DEFINED,
6640
                                     !oldDef ?
6641 6642
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
6643

6644
    VIR_INFO("Creating domain '%s'", vm->def->name);
6645
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
6646
    if (dom) dom->id = vm->def->id;
6647

6648
 cleanup:
6649
    virDomainDefFree(oldDef);
6650
    virDomainDefFree(def);
6651
    if (vm)
6652
        virObjectUnlock(vm);
6653 6654
    if (event)
        qemuDomainEventQueue(driver, event);
6655
    virObjectUnref(qemuCaps);
6656
    virObjectUnref(caps);
6657
    virObjectUnref(cfg);
6658
    return dom;
D
Daniel P. Berrange 已提交
6659 6660
}

6661 6662
static int
qemuDomainUndefineFlags(virDomainPtr dom,
6663
                        unsigned int flags)
6664
{
6665
    virQEMUDriverPtr driver = dom->conn->privateData;
6666
    virDomainObjPtr vm;
6667
    virObjectEventPtr event = NULL;
6668
    char *name = NULL;
6669
    int ret = -1;
6670
    int nsnapshots;
6671
    virQEMUDriverConfigPtr cfg = NULL;
D
Daniel P. Berrange 已提交
6672

6673
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
6674 6675
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA |
                  VIR_DOMAIN_UNDEFINE_NVRAM, -1);
6676

6677 6678
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
6679

6680
    cfg = virQEMUDriverGetConfig(driver);
D
Daniel P. Berrange 已提交
6681

6682 6683 6684
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

6685
    if (!vm->persistent) {
6686 6687
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
6688 6689 6690
        goto cleanup;
    }

6691
    if (!virDomainObjIsActive(vm) &&
6692
        (nsnapshots = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0))) {
6693
        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
6694 6695 6696 6697
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("cannot delete inactive domain with %d "
                             "snapshots"),
                           nsnapshots);
6698 6699
            goto cleanup;
        }
6700
        if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0)
6701
            goto cleanup;
6702 6703
    }

6704 6705 6706 6707 6708 6709 6710
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
6711 6712 6713
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed "
                                 "save image"));
6714 6715 6716
                goto cleanup;
            }
        } else {
6717 6718 6719
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
6720 6721 6722 6723
            goto cleanup;
        }
    }

6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740
    if (!virDomainObjIsActive(vm) &&
        vm->def->os.loader && vm->def->os.loader->nvram &&
        virFileExists(vm->def->os.loader->nvram)) {
        if (!(flags & VIR_DOMAIN_UNDEFINE_NVRAM)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete inactive domain with nvram"));
            goto cleanup;
        }

        if (unlink(vm->def->os.loader->nvram) < 0) {
            virReportSystemError(errno,
                                 _("failed to remove nvram: %s"),
                                 vm->def->os.loader->nvram);
            goto cleanup;
        }
    }

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

6744
    event = virDomainEventLifecycleNewFromObj(vm,
6745 6746
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
6747

6748
    VIR_INFO("Undefining domain '%s'", vm->def->name);
6749 6750 6751 6752 6753 6754 6755 6756

    /* 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 {
6757
        qemuDomainRemoveInactive(driver, vm);
6758 6759 6760
        vm = NULL;
    }

6761
    ret = 0;
D
Daniel P. Berrange 已提交
6762

6763
 cleanup:
6764
    VIR_FREE(name);
6765
    if (vm)
6766
        virObjectUnlock(vm);
6767 6768
    if (event)
        qemuDomainEventQueue(driver, event);
6769
    virObjectUnref(cfg);
6770
    return ret;
D
Daniel P. Berrange 已提交
6771 6772
}

6773
static int
6774
qemuDomainUndefine(virDomainPtr dom)
6775 6776 6777 6778
{
    return qemuDomainUndefineFlags(dom, 0);
}

6779
static int
6780
qemuDomainAttachDeviceControllerLive(virQEMUDriverPtr driver,
6781
                                     virDomainObjPtr vm,
6782
                                     virDomainDeviceDefPtr dev)
6783 6784 6785 6786 6787 6788
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
6789
        ret = qemuDomainAttachControllerDevice(driver, vm, cont);
6790 6791
        break;
    default:
6792 6793
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
6794
                       virDomainControllerTypeToString(cont->type));
6795 6796 6797 6798 6799 6800 6801 6802
        break;
    }
    return ret;
}

static int
qemuDomainAttachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
6803
                           virDomainPtr dom)
6804
{
6805
    virQEMUDriverPtr driver = dom->conn->privateData;
6806 6807 6808 6809
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6810
        qemuDomainObjCheckDiskTaint(driver, vm, dev->data.disk, -1);
6811
        ret = qemuDomainAttachDeviceDiskLive(dom->conn, driver, vm, dev);
6812 6813 6814 6815 6816
        if (!ret)
            dev->data.disk = NULL;
        break;

    case VIR_DOMAIN_DEVICE_CONTROLLER:
6817
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
6818 6819 6820 6821
        if (!ret)
            dev->data.controller = NULL;
        break;

6822 6823 6824 6825 6826 6827 6828
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

6829
    case VIR_DOMAIN_DEVICE_NET:
6830
        qemuDomainObjCheckNetTaint(driver, vm, dev->data.net, -1);
6831
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
6832
                                        dev->data.net);
6833 6834 6835 6836 6837
        if (!ret)
            dev->data.net = NULL;
        break;

    case VIR_DOMAIN_DEVICE_HOSTDEV:
6838
        qemuDomainObjCheckHostdevTaint(driver, vm, dev->data.hostdev, -1);
6839
        ret = qemuDomainAttachHostDevice(dom->conn, driver, vm,
6840
                                         dev->data.hostdev);
6841 6842 6843 6844
        if (!ret)
            dev->data.hostdev = NULL;
        break;

6845 6846 6847 6848 6849 6850 6851
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

6852 6853 6854 6855 6856 6857 6858
    case VIR_DOMAIN_DEVICE_CHR:
        ret = qemuDomainAttachChrDevice(driver, vm,
                                        dev->data.chr);
        if (!ret)
            dev->data.chr = NULL;
        break;

6859
    default:
6860 6861
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live attach of device '%s' is not supported"),
6862
                       virDomainDeviceTypeToString(dev->type));
6863 6864 6865
        break;
    }

6866
    if (ret == 0)
6867
        qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE);
6868

6869 6870 6871 6872
    return ret;
}

static int
6873
qemuDomainDetachDeviceControllerLive(virQEMUDriverPtr driver,
6874
                                     virDomainObjPtr vm,
6875
                                     virDomainDeviceDefPtr dev)
6876 6877 6878 6879 6880 6881
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
6882
        ret = qemuDomainDetachControllerDevice(driver, vm, dev);
6883 6884
        break;
    default :
6885 6886
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot unplugged."),
6887
                       virDomainControllerTypeToString(cont->type));
6888 6889 6890 6891 6892 6893 6894
    }
    return ret;
}

static int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
6895
                           virDomainPtr dom)
6896
{
6897
    virQEMUDriverPtr driver = dom->conn->privateData;
6898 6899 6900 6901
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6902
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
6903 6904
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
6905
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
6906
        break;
6907 6908 6909
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
6910
    case VIR_DOMAIN_DEVICE_NET:
6911
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
6912 6913
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
6914
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
6915
        break;
6916 6917 6918
    case VIR_DOMAIN_DEVICE_CHR:
        ret = qemuDomainDetachChrDevice(driver, vm, dev->data.chr);
        break;
6919
    default:
6920 6921 6922
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live detach of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
6923 6924 6925
        break;
    }

6926
    if (ret == 0)
6927
        qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE);
6928

6929 6930 6931
    return ret;
}

6932
static int
6933 6934
qemuDomainChangeDiskMediaLive(virConnectPtr conn,
                              virDomainObjPtr vm,
6935
                              virDomainDeviceDefPtr dev,
6936
                              virQEMUDriverPtr driver,
6937 6938 6939
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
6940 6941
    virDomainDiskDefPtr orig_disk = NULL;
    virCapsPtr caps = NULL;
6942
    int ret = -1;
6943

6944
    if (virStorageTranslateDiskSourcePool(conn, disk) < 0)
6945 6946
        goto end;

6947
    if (qemuDomainDetermineDiskChain(driver, vm, disk, false, true) < 0)
6948 6949
        goto end;

6950 6951 6952
    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964
        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;

6965
        /* Add the new disk src into shared disk hash table */
6966
        if (qemuAddSharedDevice(driver, dev, vm->def->name) < 0)
6967 6968
            goto end;

6969 6970 6971 6972
        if (qemuDomainChangeEjectableMedia(driver, conn, vm,
                                           orig_disk, dev->data.disk->src, force) < 0) {
            ignore_value(qemuRemoveSharedDisk(driver, dev->data.disk, vm->def->name));
            goto end;
6973
        }
6974 6975 6976

        dev->data.disk->src = NULL;
        ret = 0;
6977
        break;
6978

6979
    default:
6980 6981 6982
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk bus '%s' cannot be updated."),
                       virDomainDiskBusTypeToString(disk->bus));
6983 6984 6985
        break;
    }

6986
 end:
6987
    virObjectUnref(caps);
6988 6989 6990 6991
    return ret;
}

static int
6992 6993
qemuDomainUpdateDeviceLive(virConnectPtr conn,
                           virDomainObjPtr vm,
6994 6995 6996 6997
                           virDomainDeviceDefPtr dev,
                           virDomainPtr dom,
                           bool force)
{
6998
    virQEMUDriverPtr driver = dom->conn->privateData;
6999 7000 7001 7002
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
7003
        ret = qemuDomainChangeDiskMediaLive(conn, vm, dev, driver, force);
7004 7005 7006 7007
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;
7008
    case VIR_DOMAIN_DEVICE_NET:
7009
        ret = qemuDomainChangeNet(driver, vm, dom, dev);
7010
        break;
7011
    default:
7012
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
7013
                       _("live update of device '%s' is not supported"),
7014
                       virDomainDeviceTypeToString(dev->type));
7015 7016 7017 7018 7019 7020
        break;
    }

    return ret;
}

7021
static int
7022
qemuDomainAttachDeviceConfig(virQEMUCapsPtr qemuCaps,
7023
                             virDomainDefPtr vmdef,
7024 7025
                             virDomainDeviceDefPtr dev)
{
7026
    virDomainDiskDefPtr disk;
7027
    virDomainNetDefPtr net;
7028
    virDomainHostdevDefPtr hostdev;
7029
    virDomainLeaseDefPtr lease;
7030
    virDomainControllerDefPtr controller;
7031
    virDomainFSDefPtr fs;
7032

7033
    switch (dev->type) {
7034 7035
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
7036
        if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
7037 7038
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("target %s already exists"), disk->dst);
7039 7040
            return -1;
        }
7041 7042
        if (qemuCheckDiskConfig(disk) < 0)
            return -1;
7043
        if (virDomainDiskInsert(vmdef, disk))
7044 7045 7046 7047 7048 7049
            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;
7050
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
7051 7052 7053
            return -1;
        break;

7054 7055
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
7056
        if (virDomainNetInsert(vmdef, net))
7057 7058
            return -1;
        dev->data.net = NULL;
7059
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
7060 7061
            return -1;
        break;
7062

7063 7064 7065
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        hostdev = dev->data.hostdev;
        if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
7066
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
7067
                           _("device is already in the domain configuration"));
7068 7069
            return -1;
        }
7070
        if (virDomainHostdevInsert(vmdef, hostdev))
7071 7072
            return -1;
        dev->data.hostdev = NULL;
7073
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
7074 7075 7076
            return -1;
        break;

7077 7078 7079
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
        if (virDomainLeaseIndex(vmdef, lease) >= 0) {
7080
            virReportError(VIR_ERR_OPERATION_INVALID,
7081 7082
                           _("Lease %s in lockspace %s already exists"),
                           lease->key, NULLSTR(lease->lockspace));
7083 7084 7085 7086 7087 7088 7089 7090 7091
            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;

7092 7093 7094
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        controller = dev->data.controller;
        if (virDomainControllerFind(vmdef, controller->type,
7095
                                    controller->idx) >= 0) {
7096
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
7097 7098 7099 7100 7101 7102 7103 7104
                           _("Target already exists"));
            return -1;
        }

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

7105
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
7106 7107 7108
            return -1;
        break;

7109 7110 7111 7112 7113 7114
    case VIR_DOMAIN_DEVICE_CHR:
        if (qemuDomainChrInsert(vmdef, dev->data.chr) < 0)
            return -1;
        dev->data.chr = NULL;
        break;

7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127
    case VIR_DOMAIN_DEVICE_FS:
        fs = dev->data.fs;
        if (virDomainFSIndexByName(vmdef, fs->dst) >= 0) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("Target already exists"));
            return -1;
        }

        if (virDomainFSInsert(vmdef, fs) < 0)
            return -1;
        dev->data.fs = NULL;
        break;

7128
    default:
7129 7130 7131
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("persistent attach of device '%s' is not supported"),
                        virDomainDeviceTypeToString(dev->type));
7132 7133 7134 7135 7136 7137 7138
         return -1;
    }
    return 0;
}


static int
7139
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
7140 7141
                             virDomainDeviceDefPtr dev)
{
7142
    virDomainDiskDefPtr disk, det_disk;
7143
    virDomainNetDefPtr net;
7144
    virDomainHostdevDefPtr hostdev, det_hostdev;
7145
    virDomainLeaseDefPtr lease, det_lease;
7146
    virDomainControllerDefPtr cont, det_cont;
7147
    virDomainChrDefPtr chr;
7148
    virDomainFSDefPtr fs;
7149
    int idx;
7150

7151
    switch (dev->type) {
7152 7153
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
7154
        if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
7155 7156
            virReportError(VIR_ERR_INVALID_ARG,
                           _("no target device %s"), disk->dst);
7157 7158
            return -1;
        }
7159
        virDomainDiskDefFree(det_disk);
7160
        break;
7161

7162 7163
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
7164
        if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
7165
            return -1;
7166

7167 7168
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
7169
        break;
7170

7171 7172 7173
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        hostdev = dev->data.hostdev;
        if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
7174 7175
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device not present in domain configuration"));
7176 7177 7178 7179 7180 7181 7182
            return -1;
        }
        virDomainHostdevRemove(vmdef, idx);
        virDomainHostdevDefFree(det_hostdev);
        break;
    }

7183 7184
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
7185
        if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) {
7186 7187 7188
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Lease %s in lockspace %s does not exist"),
                           lease->key, NULLSTR(lease->lockspace));
7189 7190
            return -1;
        }
7191
        virDomainLeaseDefFree(det_lease);
7192 7193
        break;

7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206
    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;

7207 7208 7209 7210 7211 7212 7213 7214 7215
    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;

7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228
    case VIR_DOMAIN_DEVICE_FS:
        fs = dev->data.fs;
        idx = virDomainFSIndexByName(vmdef, fs->dst);
        if (idx < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("no matching filesystem device was found"));
            return -1;
        }

        fs = virDomainFSRemove(vmdef, idx);
        virDomainFSDefFree(fs);
        break;

7229
    default:
7230 7231 7232
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("persistent detach of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
7233 7234 7235 7236 7237 7238
        return -1;
    }
    return 0;
}

static int
7239
qemuDomainUpdateDeviceConfig(virQEMUCapsPtr qemuCaps,
7240
                             virDomainDefPtr vmdef,
7241 7242
                             virDomainDeviceDefPtr dev)
{
7243
    virDomainDiskDefPtr orig, disk;
7244
    virDomainNetDefPtr net;
7245
    int pos;
7246

7247

7248
    switch (dev->type) {
7249 7250
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
7251
        pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
7252
        if (pos < 0) {
7253 7254
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s doesn't exist."), disk->dst);
7255 7256 7257 7258 7259
            return -1;
        }
        orig = vmdef->disks[pos];
        if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
            !(orig->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)) {
7260 7261
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("this disk doesn't support update"));
7262 7263 7264 7265 7266 7267
            return -1;
        }
        /*
         * Update 'orig'
         * We allow updating src/type//driverType/cachemode/
         */
7268 7269 7270
        VIR_FREE(orig->src->path);
        orig->src->path = disk->src->path;
        orig->src->type = disk->src->type;
7271
        orig->cachemode = disk->cachemode;
7272 7273 7274 7275 7276 7277 7278 7279
        if (disk->src->driverName) {
            VIR_FREE(orig->src->driverName);
            orig->src->driverName = disk->src->driverName;
            disk->src->driverName = NULL;
        }
        if (disk->src->format)
            orig->src->format = disk->src->format;
        disk->src->path = NULL;
7280
        break;
7281 7282 7283

    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
7284
        if ((pos = virDomainNetFindIdx(vmdef, net)) < 0)
7285 7286
            return -1;

7287
        virDomainNetDefFree(vmdef->nets[pos]);
7288 7289 7290 7291

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

7292
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
7293 7294 7295
            return -1;
        break;

7296
    default:
7297 7298 7299
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("persistent update of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
7300 7301 7302 7303 7304
        return -1;
    }
    return 0;
}

7305

7306 7307
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
7308
{
7309
    virQEMUDriverPtr driver = dom->conn->privateData;
7310
    virDomainObjPtr vm = NULL;
7311
    virDomainDefPtr vmdef = NULL;
7312
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
7313
    int ret = -1;
7314
    unsigned int affect, parse_flags = VIR_DOMAIN_XML_INACTIVE;
7315
    virQEMUCapsPtr qemuCaps = NULL;
7316
    qemuDomainObjPrivatePtr priv;
7317
    virQEMUDriverConfigPtr cfg = NULL;
7318
    virCapsPtr caps = NULL;
7319

7320
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7321
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7322

7323 7324
    cfg = virQEMUDriverGetConfig(driver);

7325 7326
    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

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

7330
    if (!(vm = qemuDomObjFromDomain(dom)))
7331
        goto cleanup;
7332

7333
    priv = vm->privateData;
7334

7335 7336 7337
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

7341
    if (virDomainObjIsActive(vm)) {
7342
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
7343
            flags |= VIR_DOMAIN_AFFECT_LIVE;
7344
    } else {
7345
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
7346
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
7347
        /* check consistency between flags and the vm state */
7348
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7349
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
7350 7351
                           _("cannot do live update a device on "
                             "inactive domain"));
7352 7353
            goto endjob;
        }
7354
    }
7355

7356
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
7357 7358
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
7359 7360
         goto endjob;
    }
7361

7362 7363
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                             caps, driver->xmlopt,
7364
                                             parse_flags);
7365 7366 7367 7368 7369 7370 7371 7372 7373
    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.
         */
7374
        dev_copy = virDomainDeviceDefCopy(dev, vm->def, caps, driver->xmlopt);
7375
        if (!dev_copy)
7376
            goto endjob;
7377
    }
7378

7379 7380 7381
    if (priv->qemuCaps)
        qemuCaps = virObjectRef(priv->qemuCaps);
    else if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, vm->def->emulator)))
7382 7383
        goto cleanup;

7384
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7385
        /* Make a copy for updated domain. */
7386
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
7387 7388
        if (!vmdef)
            goto endjob;
7389

7390 7391
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH) < 0)
7392 7393
            goto endjob;

7394
        if ((ret = qemuDomainAttachDeviceConfig(qemuCaps, vmdef, dev)) < 0)
7395 7396 7397 7398
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7399 7400
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_ATTACH) < 0)
7401 7402
            goto endjob;

7403
        if ((ret = qemuDomainAttachDeviceLive(vm, dev_copy, dom)) < 0)
7404
            goto endjob;
7405 7406
        /*
         * update domain status forcibly because the domain status may be
7407 7408
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
7409
         */
7410
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
7411
            ret = -1;
7412 7413
            goto endjob;
        }
7414
    }
7415

7416
    /* Finally, if no error until here, we can save config. */
7417
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7418
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
7419
        if (!ret) {
7420
            virDomainObjAssignDef(vm, vmdef, false, NULL);
7421 7422 7423
            vmdef = NULL;
        }
    }
7424

7425
 endjob:
E
Eric Blake 已提交
7426
    if (!qemuDomainObjEndJob(driver, vm))
7427 7428
        vm = NULL;

7429
 cleanup:
7430
    virObjectUnref(qemuCaps);
7431
    virDomainDefFree(vmdef);
7432 7433
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
7434 7435
    virDomainDeviceDefFree(dev);
    if (vm)
7436
        virObjectUnlock(vm);
7437
    virObjectUnref(caps);
7438
    virObjectUnref(cfg);
7439 7440 7441
    return ret;
}

7442 7443 7444
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
7445
                                       VIR_DOMAIN_AFFECT_LIVE);
7446
}
7447

7448

7449 7450 7451 7452
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480
    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;

7481 7482 7483
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535
    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) {
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
        if (!vmdef)
            goto endjob;

7536 7537
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE) < 0)
7538 7539
            goto endjob;

7540 7541 7542 7543 7544
        if ((ret = qemuDomainUpdateDeviceConfig(qemuCaps, vmdef, dev)) < 0)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7545 7546
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_UPDATE) < 0)
7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570
            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;
        }
    }

7571
 endjob:
E
Eric Blake 已提交
7572
    if (!qemuDomainObjEndJob(driver, vm))
7573 7574
        vm = NULL;

7575
 cleanup:
7576 7577 7578 7579 7580 7581 7582 7583 7584 7585
    virObjectUnref(qemuCaps);
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
7586 7587
}

7588

7589 7590 7591
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
7592 7593 7594 7595 7596
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
7597
    unsigned int affect, parse_flags = 0;
7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617
    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;

7618 7619 7620
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644
    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;
    }

7645 7646 7647 7648
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
        !(flags & VIR_DOMAIN_AFFECT_LIVE))
        parse_flags |= VIR_DOMAIN_XML_INACTIVE;

7649 7650
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                             caps, driver->xmlopt,
7651
                                             parse_flags);
7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675
    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) {
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
        if (!vmdef)
            goto endjob;
7676

7677 7678
        if (virDomainDefCompatibleDevice(vmdef, dev,
                                         VIR_DOMAIN_DEVICE_ACTION_DETACH) < 0)
7679 7680
            goto endjob;

7681 7682 7683 7684 7685
        if ((ret = qemuDomainDetachDeviceConfig(vmdef, dev)) < 0)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7686 7687
        if (virDomainDefCompatibleDevice(vm->def, dev_copy,
                                         VIR_DOMAIN_DEVICE_ACTION_DETACH) < 0)
7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711
            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;
        }
    }

7712
 endjob:
E
Eric Blake 已提交
7713
    if (!qemuDomainObjEndJob(driver, vm))
7714 7715
        vm = NULL;

7716
 cleanup:
7717 7718 7719 7720 7721 7722 7723 7724 7725 7726
    virObjectUnref(qemuCaps);
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
7727 7728
}

7729 7730 7731
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
7732
                                       VIR_DOMAIN_AFFECT_LIVE);
7733 7734
}

7735
static int qemuDomainGetAutostart(virDomainPtr dom,
7736 7737
                                  int *autostart)
{
7738 7739
    virDomainObjPtr vm;
    int ret = -1;
7740

7741
    if (!(vm = qemuDomObjFromDomain(dom)))
7742
        goto cleanup;
7743

7744 7745 7746
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7747
    *autostart = vm->autostart;
7748
    ret = 0;
7749

7750
 cleanup:
7751
    if (vm)
7752
        virObjectUnlock(vm);
7753
    return ret;
7754 7755
}

7756
static int qemuDomainSetAutostart(virDomainPtr dom,
7757 7758
                                  int autostart)
{
7759
    virQEMUDriverPtr driver = dom->conn->privateData;
7760
    virDomainObjPtr vm;
7761 7762
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
7763
    virQEMUDriverConfigPtr cfg = NULL;
7764

7765 7766 7767
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

7768
    cfg = virQEMUDriverGetConfig(driver);
7769

7770 7771 7772
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7773
    if (!vm->persistent) {
7774 7775
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
7776
        goto cleanup;
7777 7778
    }

7779 7780
    autostart = (autostart != 0);

7781
    if (vm->autostart != autostart) {
7782
        if ((configFile = virDomainConfigFile(cfg->configDir, vm->def->name)) == NULL)
7783
            goto cleanup;
7784
        if ((autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)) == NULL)
7785
            goto cleanup;
7786

7787
        if (autostart) {
7788
            if (virFileMakePath(cfg->autostartDir) < 0) {
7789
                virReportSystemError(errno,
7790
                                     _("cannot create autostart directory %s"),
7791
                                     cfg->autostartDir);
7792 7793
                goto cleanup;
            }
7794

7795
            if (symlink(configFile, autostartLink) < 0) {
7796
                virReportSystemError(errno,
7797 7798
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
7799 7800 7801 7802
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
7803
                virReportSystemError(errno,
7804 7805
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
7806 7807
                goto cleanup;
            }
7808 7809
        }

7810
        vm->autostart = autostart;
7811
    }
7812
    ret = 0;
7813

7814
 cleanup:
7815 7816
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
7817
    if (vm)
7818
        virObjectUnlock(vm);
7819
    virObjectUnref(cfg);
7820
    return ret;
7821 7822
}

7823

7824 7825
static char *qemuDomainGetSchedulerType(virDomainPtr dom,
                                        int *nparams)
7826
{
7827
    char *ret = NULL;
7828 7829
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
7830 7831
    virQEMUDriverPtr driver = dom->conn->privateData;
    virQEMUDriverConfigPtr cfg = NULL;
7832

7833
    if (!(vm = qemuDomObjFromDomain(dom)))
7834
        goto cleanup;
7835

7836
    priv = vm->privateData;
7837

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

7841 7842 7843 7844 7845 7846 7847
    cfg = virQEMUDriverGetConfig(driver);
    if (!cfg->privileged) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("CPU tuning is not available in session mode"));
        goto cleanup;
    }

7848 7849 7850 7851 7852 7853 7854 7855
    /* Domain not running, thus no cgroups - return defaults */
    if (!virDomainObjIsActive(vm)) {
        if (nparams)
            *nparams = 5;
        ignore_value(VIR_STRDUP(ret, "posix"));
        goto cleanup;
    }

7856
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
7857 7858
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
7859
        goto cleanup;
7860 7861
    }

7862
    if (nparams) {
7863
        if (virCgroupSupportsCpuBW(priv->cgroup))
7864
            *nparams = 5;
7865 7866
        else
            *nparams = 1;
7867
    }
7868

7869
    ignore_value(VIR_STRDUP(ret, "posix"));
7870

7871
 cleanup:
7872 7873
    if (vm)
        virObjectUnlock(vm);
7874
    virObjectUnref(cfg);
7875 7876 7877
    return ret;
}

7878
/* blkioDeviceStr in the form of /device/path,weight,/device/path,weight
7879 7880 7881
 * for example, /dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0,800
 */
static int
7882 7883
qemuDomainParseBlkioDeviceStr(char *blkioDeviceStr, const char *type,
                              virBlkioDevicePtr *dev, size_t *size)
7884 7885 7886 7887
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
7888
    size_t i;
7889
    virBlkioDevicePtr result = NULL;
7890

7891
    *dev = NULL;
7892 7893
    *size = 0;

7894
    if (STREQ(blkioDeviceStr, ""))
7895 7896
        return 0;

7897
    temp = blkioDeviceStr;
7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912
    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;

7913
    if (VIR_ALLOC_N(result, ndevices) < 0)
7914 7915 7916
        return -1;

    i = 0;
7917
    temp = blkioDeviceStr;
7918 7919 7920 7921 7922 7923 7924 7925
    while (temp) {
        char *p = temp;

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

7926
        if (VIR_STRNDUP(result[i].path, temp, p - temp) < 0)
7927 7928
            goto cleanup;

7929
        /* value */
7930 7931
        temp = p + 1;

7932
        if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
7933
            if (virStrToLong_uip(temp, &p, 10, &result[i].weight) < 0)
7934 7935
                goto error;
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
7936
            if (virStrToLong_uip(temp, &p, 10, &result[i].riops) < 0)
7937 7938
                goto error;
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
7939
            if (virStrToLong_uip(temp, &p, 10, &result[i].wiops) < 0)
7940 7941
                goto error;
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
7942
            if (virStrToLong_ullp(temp, &p, 10, &result[i].rbps) < 0)
7943 7944
                goto error;
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
7945
            if (virStrToLong_ullp(temp, &p, 10, &result[i].wbps) < 0)
7946 7947
                goto error;
        } else {
7948
            goto error;
7949
        }
7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962

        i++;

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

    if (!i)
        VIR_FREE(result);

7963
    *dev = result;
7964 7965 7966 7967
    *size = i;

    return 0;

7968
 error:
7969
    virReportError(VIR_ERR_INVALID_ARG,
7970 7971
                   _("unable to parse blkio device '%s' '%s'"),
                   type, blkioDeviceStr);
7972
 cleanup:
7973 7974 7975 7976
    if (result) {
        virBlkioDeviceArrayClear(result, ndevices);
        VIR_FREE(result);
    }
7977 7978 7979
    return -1;
}

7980
/* Modify dest_array to reflect all blkio device changes described in
7981
 * src_array.  */
7982
static int
7983 7984 7985 7986 7987
qemuDomainMergeBlkioDevice(virBlkioDevicePtr *dest_array,
                           size_t *dest_size,
                           virBlkioDevicePtr src_array,
                           size_t src_size,
                           const char *type)
7988
{
7989
    size_t i, j;
7990
    virBlkioDevicePtr dest, src;
7991

7992
    for (i = 0; i < src_size; i++) {
7993 7994
        bool found = false;

7995 7996 7997 7998
        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
7999
                found = true;
8000

8001
                if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
8002
                    dest->weight = src->weight;
8003
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
8004
                    dest->riops = src->riops;
8005
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
8006
                    dest->wiops = src->wiops;
8007
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
8008
                    dest->rbps = src->rbps;
8009
                } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
8010
                    dest->wbps = src->wbps;
8011
                } else {
8012 8013 8014 8015
                    virReportError(VIR_ERR_INVALID_ARG, _("Unknown parameter %s"),
                                   type);
                    return -1;
                }
8016 8017 8018 8019
                break;
            }
        }
        if (!found) {
8020
            if (!src->weight && !src->riops && !src->wiops && !src->rbps && !src->wbps)
8021
                continue;
8022
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0)
8023
                return -1;
8024
            dest = &(*dest_array)[*dest_size - 1];
8025

8026
            if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
8027
                dest->weight = src->weight;
8028
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
8029
                dest->riops = src->riops;
8030
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
8031
                dest->wiops = src->wiops;
8032
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
8033
                dest->rbps = src->rbps;
8034
            } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
8035
                dest->wbps = src->wbps;
8036
            } else {
8037 8038 8039 8040
                *dest_size = *dest_size - 1;
                return -1;
            }

8041 8042
            dest->path = src->path;
            src->path = NULL;
8043 8044 8045 8046 8047 8048
        }
    }

    return 0;
}

8049 8050 8051 8052 8053
static int
qemuDomainSetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
8054
{
8055
    virQEMUDriverPtr driver = dom->conn->privateData;
8056
    size_t i;
8057
    virDomainObjPtr vm = NULL;
8058
    virDomainDefPtr persistentDef = NULL;
8059
    int ret = -1;
8060
    virQEMUDriverConfigPtr cfg = NULL;
8061
    virCapsPtr caps = NULL;
8062
    qemuDomainObjPrivatePtr priv;
8063

8064 8065
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8066 8067 8068 8069 8070
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLKIO_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                               VIR_TYPED_PARAM_STRING,
8071 8072 8073 8074 8075 8076 8077 8078
                               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,
8079
                               NULL) < 0)
8080
        return -1;
8081

8082 8083 8084
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

8085
    priv = vm->privateData;
8086
    cfg = virQEMUDriverGetConfig(driver);
8087 8088 8089 8090

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

8091 8092 8093 8094 8095 8096
    if (!cfg->privileged) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Block I/O tuning is not available in session mode"));
        goto cleanup;
    }

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

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

8103
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8104
                                        &persistentDef) < 0)
8105
        goto endjob;
8106

8107
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8108
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
8109 8110
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
8111
            goto endjob;
8112 8113 8114
        }
    }

8115
    ret = 0;
8116 8117 8118 8119 8120
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
8121
                if (virCgroupSetBlkioWeight(priv->cgroup, param->value.ui) < 0)
8122
                    ret = -1;
8123 8124 8125 8126 8127
            } 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)) {
8128
                size_t ndevices;
8129
                virBlkioDevicePtr devices = NULL;
8130
                size_t j;
8131

8132
                if (qemuDomainParseBlkioDeviceStr(param->value.s,
8133 8134 8135
                                                  param->field,
                                                  &devices,
                                                  &ndevices) < 0) {
8136 8137 8138
                    ret = -1;
                    continue;
                }
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

                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;
                        }
                    }
8176
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
8177 8178 8179 8180 8181 8182 8183
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
                                                            devices[j].wbps) < 0) {
                            ret = -1;
                            break;
                        }
8184
                    }
8185 8186 8187 8188 8189 8190 8191 8192
                } else {
                    virReportError(VIR_ERR_INVALID_ARG, _("Unknown blkio parameter %s"),
                                   param->field);
                    ret = -1;
                    virBlkioDeviceArrayClear(devices, ndevices);
                    VIR_FREE(devices);

                    continue;
8193
                }
8194

8195
                if (j != ndevices ||
8196 8197 8198
                    qemuDomainMergeBlkioDevice(&vm->def->blkio.devices,
                                               &vm->def->blkio.ndevices,
                                               devices, ndevices, param->field) < 0)
8199
                    ret = -1;
8200
                virBlkioDeviceArrayClear(devices, ndevices);
8201
                VIR_FREE(devices);
8202
            }
8203
        }
8204 8205 8206

        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
            goto endjob;
E
Eric Blake 已提交
8207 8208
    }
    if (ret < 0)
8209
        goto endjob;
E
Eric Blake 已提交
8210
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
8211 8212 8213
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

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

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
8218
                persistentDef->blkio.weight = param->value.ui;
8219 8220 8221 8222 8223
            } 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)) {
8224
                virBlkioDevicePtr devices = NULL;
8225
                size_t ndevices;
8226

8227 8228
                if (qemuDomainParseBlkioDeviceStr(param->value.s,
                                                  param->field,
8229 8230
                                                  &devices,
                                                  &ndevices) < 0) {
8231 8232 8233
                    ret = -1;
                    continue;
                }
8234 8235 8236
                if (qemuDomainMergeBlkioDevice(&persistentDef->blkio.devices,
                                               &persistentDef->blkio.ndevices,
                                               devices, ndevices, param->field) < 0)
8237
                    ret = -1;
8238
                virBlkioDeviceArrayClear(devices, ndevices);
8239
                VIR_FREE(devices);
8240 8241
            }
        }
A
Alex Jia 已提交
8242

8243
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
A
Alex Jia 已提交
8244
            ret = -1;
8245 8246
    }

8247 8248 8249 8250
 endjob:
    if (!qemuDomainObjEndJob(driver, vm))
        vm = NULL;

8251
 cleanup:
8252
    if (vm)
8253
        virObjectUnlock(vm);
8254
    virObjectUnref(caps);
8255
    virObjectUnref(cfg);
8256 8257 8258
    return ret;
}

8259 8260 8261 8262 8263
static int
qemuDomainGetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
8264
{
8265
    virQEMUDriverPtr driver = dom->conn->privateData;
8266
    size_t i, j;
8267
    virDomainObjPtr vm = NULL;
8268
    virDomainDefPtr persistentDef = NULL;
8269 8270
    unsigned int val;
    int ret = -1;
8271
    virCapsPtr caps = NULL;
8272
    qemuDomainObjPrivatePtr priv;
8273
    virQEMUDriverConfigPtr cfg = NULL;
8274

8275
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
8276 8277
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
8278

8279 8280 8281
    /* 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.  */
8282 8283
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

8284 8285
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8286

8287 8288
    priv = vm->privateData;

8289 8290 8291
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

8292 8293 8294 8295 8296 8297 8298
    cfg = virQEMUDriverGetConfig(driver);
    if (!cfg->privileged) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Block I/O tuning is not available in session mode"));
        goto cleanup;
    }

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

8302 8303 8304 8305 8306 8307 8308
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

8309
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8310 8311
                                        &persistentDef) < 0)
        goto cleanup;
8312

8313
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8314
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
8315 8316
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
8317 8318 8319 8320 8321
            goto cleanup;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8322
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
8323 8324 8325 8326 8327
            virTypedParameterPtr param = &params[i];
            val = 0;

            switch (i) {
            case 0: /* fill blkio weight here */
8328
                if (virCgroupGetBlkioWeight(priv->cgroup, &val) < 0)
8329
                    goto cleanup;
8330 8331
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
8332 8333
                    goto cleanup;
                break;
8334

8335 8336 8337 8338
            case 1: /* blkiotune.device_weight */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;
8339

8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350
                    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);
                    }
8351
                    if (virBufferCheckError(&buf) < 0)
8352 8353 8354
                        goto cleanup;
                    param->value.s = virBufferContentAndReset(&buf);
                }
8355 8356 8357 8358
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
8359 8360
                    goto cleanup;
                break;
8361

8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377
            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);
                    }
8378
                    if (virBufferCheckError(&buf) < 0)
8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404
                        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);
                    }
8405
                    if (virBufferCheckError(&buf) < 0)
8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431
                        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);
                    }
8432
                    if (virBufferCheckError(&buf) < 0)
8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458
                        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);
                    }
8459
                    if (virBufferCheckError(&buf) < 0)
8460 8461 8462 8463 8464 8465 8466 8467 8468 8469
                        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;

8470
            /* coverity[dead_error_begin] */
8471 8472 8473
            default:
                break;
                /* should not hit here */
8474
            }
8475 8476
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8477
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
8478 8479 8480 8481 8482 8483 8484 8485
            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) {
8486 8487 8488
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_WEIGHT);
8489 8490 8491 8492
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
8493

8494 8495 8496
            case 1: /* blkiotune.device_weight */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
8497 8498
                    bool comma = false;

8499
                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
8500 8501 8502
                        if (!persistentDef->blkio.devices[j].weight)
                            continue;
                        if (comma)
8503
                            virBufferAddChar(&buf, ',');
8504 8505
                        else
                            comma = true;
8506 8507 8508 8509
                        virBufferAsprintf(&buf, "%s,%u",
                                          persistentDef->blkio.devices[j].path,
                                          persistentDef->blkio.devices[j].weight);
                    }
8510
                    if (virBufferCheckError(&buf) < 0)
8511 8512
                        goto cleanup;
                    param->value.s = virBufferContentAndReset(&buf);
8513
                }
8514 8515
                if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
                    goto cleanup;
8516 8517 8518
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) == NULL) {
8519 8520 8521
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
8522 8523 8524 8525
                    goto cleanup;
                }
                break;

8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541
            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);
                    }
8542
                    if (virBufferCheckError(&buf) < 0)
8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572
                        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);
                    }
8573
                    if (virBufferCheckError(&buf) < 0)
8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603
                        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);
                    }
8604
                    if (virBufferCheckError(&buf) < 0)
8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635
                        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);
                    }
8636
                    if (virBufferCheckError(&buf) < 0)
8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652
                        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;


8653
            /* coverity[dead_error_begin] */
8654 8655 8656 8657
            default:
                break;
                /* should not hit here */
            }
8658 8659 8660
        }
    }

8661 8662
    if (QEMU_NB_BLKIO_PARAM < *nparams)
        *nparams = QEMU_NB_BLKIO_PARAM;
8663 8664
    ret = 0;

8665
 cleanup:
8666
    if (vm)
8667
        virObjectUnlock(vm);
8668
    virObjectUnref(caps);
8669
    virObjectUnref(cfg);
8670 8671
    return ret;
}
8672

8673 8674 8675 8676 8677
static int
qemuDomainSetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              unsigned int flags)
8678
{
8679
    virQEMUDriverPtr driver = dom->conn->privateData;
8680
    virDomainDefPtr persistentDef = NULL;
8681
    virDomainObjPtr vm = NULL;
8682
    unsigned long long swap_hard_limit;
8683 8684
    unsigned long long hard_limit = 0;
    unsigned long long soft_limit = 0;
8685
    bool set_swap_hard_limit = false;
8686 8687
    bool set_hard_limit = false;
    bool set_soft_limit = false;
8688
    virQEMUDriverConfigPtr cfg = NULL;
8689
    int rc;
8690
    int ret = -1;
8691
    virCapsPtr caps = NULL;
8692
    qemuDomainObjPrivatePtr priv;
8693

8694 8695
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8696

8697 8698 8699 8700 8701 8702 8703 8704
    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)
8705
        return -1;
8706 8707


8708 8709
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8710

8711
    priv = vm->privateData;
8712 8713
    cfg = virQEMUDriverGetConfig(driver);

8714 8715 8716
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

8717 8718 8719 8720 8721 8722
    if (!cfg->privileged) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Memory tuning is not available in session mode"));
        goto cleanup;
    }

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

8726
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8727 8728
                                        &persistentDef) < 0)
        goto cleanup;
8729

8730
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8731
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
8732 8733
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
8734 8735 8736 8737
            goto cleanup;
        }
    }

8738
#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE)                                \
8739
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0)  \
8740 8741 8742 8743 8744 8745
        goto cleanup;                                                        \
                                                                             \
    if (rc == 1)                                                             \
        set_ ## VALUE = true;

    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, swap_hard_limit)
8746 8747
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_HARD_LIMIT, hard_limit)
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SOFT_LIMIT, soft_limit)
8748 8749 8750

#undef VIR_GET_LIMIT_PARAMETER

8751 8752 8753 8754 8755
    /* 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;
8756

8757 8758
        if (set_swap_hard_limit)
            swap_limit = swap_hard_limit;
8759

8760 8761 8762 8763 8764 8765
        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 "
8766
                             "than or equal to swap_hard_limit"));
8767
            goto cleanup;
8768
        }
8769
    }
8770

8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784
#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;                                   \
8785 8786
    }

8787 8788
    /* Soft limit doesn't clash with the others */
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);
8789

8790 8791 8792 8793 8794
    /* 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;
8795
    }
8796

8797
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);
8798

8799 8800 8801 8802
    /* otherwise increase it after swap hard limit */
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);

#undef QEMU_SET_MEM_PARAMETER
8803

8804 8805 8806 8807 8808 8809
    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
        goto cleanup;

    ret = 0;

8810
 cleanup:
8811
    virObjectUnlock(vm);
8812
    virObjectUnref(caps);
8813
    virObjectUnref(cfg);
8814 8815 8816
    return ret;
}

8817 8818 8819 8820 8821
static int
qemuDomainGetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int *nparams,
                              unsigned int flags)
8822
{
8823
    virQEMUDriverPtr driver = dom->conn->privateData;
8824
    size_t i;
8825
    virDomainObjPtr vm = NULL;
8826
    virDomainDefPtr persistentDef = NULL;
8827
    int ret = -1;
8828
    virCapsPtr caps = NULL;
8829
    qemuDomainObjPrivatePtr priv;
8830
    virQEMUDriverConfigPtr cfg = NULL;
8831

8832
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
8833 8834
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
8835

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

8839 8840
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8841

8842
    priv = vm->privateData;
8843 8844 8845 8846

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

8847 8848 8849 8850 8851 8852 8853
    cfg = virQEMUDriverGetConfig(driver);
    if (!cfg->privileged) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Memory tuning is not available in session mode"));
        goto cleanup;
    }

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

8857
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8858 8859
                                        &persistentDef) < 0)
        goto cleanup;
8860

8861
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8862
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
8863 8864
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
8865 8866 8867 8868
            goto cleanup;
        }
    }

8869 8870 8871 8872 8873 8874 8875
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

8876
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8877
        for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
8878
            virMemoryParameterPtr param = &params[i];
8879
            unsigned long long value;
8880 8881 8882

            switch (i) {
            case 0: /* fill memory hard limit here */
8883 8884 8885 8886
                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)
8887 8888 8889 8890
                    goto cleanup;
                break;

            case 1: /* fill memory soft limit here */
8891 8892 8893 8894
                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)
8895 8896 8897 8898
                    goto cleanup;
                break;

            case 2: /* fill swap hard limit here */
8899 8900 8901 8902
                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)
8903 8904 8905
                    goto cleanup;
                break;

8906
            /* coverity[dead_error_begin] */
8907 8908 8909 8910 8911 8912
            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
8913 8914
    }

8915
    for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
8916
        virTypedParameterPtr param = &params[i];
8917
        unsigned long long val = 0;
8918

8919
        switch (i) {
8920
        case 0: /* fill memory hard limit here */
8921
            if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0)
8922
                goto cleanup;
8923 8924 8925
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8926
                goto cleanup;
8927 8928 8929
            break;

        case 1: /* fill memory soft limit here */
8930
            if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0)
8931
                goto cleanup;
8932 8933 8934
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8935
                goto cleanup;
8936 8937 8938
            break;

        case 2: /* fill swap hard limit here */
8939 8940 8941
            if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0) {
                if (!virLastErrorIsSystemErrno(ENOENT) &&
                    !virLastErrorIsSystemErrno(EOPNOTSUPP))
8942 8943
                    goto cleanup;
                val = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
8944
            }
8945 8946 8947
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8948
                goto cleanup;
8949 8950
            break;

8951
        /* coverity[dead_error_begin] */
8952 8953 8954 8955 8956 8957
        default:
            break;
            /* should not hit here */
        }
    }

8958
 out:
8959 8960
    if (QEMU_NB_MEM_PARAM < *nparams)
        *nparams = QEMU_NB_MEM_PARAM;
8961 8962
    ret = 0;

8963
 cleanup:
8964
    if (vm)
8965
        virObjectUnlock(vm);
8966
    virObjectUnref(caps);
8967
    virObjectUnref(cfg);
8968 8969 8970
    return ret;
}

8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982
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;

8983
    if (virDomainNumatuneGetMode(vm->def->numatune, -1) !=
8984
        VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
8985 8986 8987 8988 8989 8990
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("change of nodeset for running domain "
                         "requires strict numa mode"));
        goto cleanup;
    }

8991
    /* Get existing nodeset values */
8992 8993 8994 8995 8996 8997 8998 8999
    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;
9000 9001
        virCapsHostNUMACellPtr cell = caps->host.numaCell[i];
        if (virBitmapGetBit(nodeset, cell->num, &result) < 0) {
9002 9003 9004 9005
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to get cpuset bit values"));
            goto cleanup;
        }
9006
        if (result && (virBitmapSetBit(temp_nodeset, cell->num) < 0)) {
9007 9008 9009 9010 9011 9012
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to set temporary cpuset bit values"));
            goto cleanup;
        }
    }

9013
    if (!(nodeset_str = virBitmapFormat(temp_nodeset)))
9014 9015 9016 9017 9018 9019
        goto cleanup;

    if (virCgroupSetCpusetMems(priv->cgroup, nodeset_str) < 0)
        goto cleanup;
    VIR_FREE(nodeset_str);

9020
    /* Ensure the cpuset string is formatted before passing to cgroup */
9021
    if (!(nodeset_str = virBitmapFormat(nodeset)))
9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035
        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;

9036
    for (i = 0; i < priv->niothreadpids; i++) {
9037 9038
        if (virCgroupNewIOThread(priv->cgroup, i + 1, false,
                                 &cgroup_temp) < 0 ||
9039 9040 9041 9042 9043 9044
            virCgroupSetCpusetMems(cgroup_temp, nodeset_str) < 0)
            goto cleanup;
        virCgroupFree(&cgroup_temp);
    }


9045 9046 9047 9048 9049 9050 9051 9052 9053
    ret = 0;
 cleanup:
    VIR_FREE(nodeset_str);
    virBitmapFree(temp_nodeset);
    virCgroupFree(&cgroup_temp);

    return ret;
}

9054 9055 9056 9057 9058 9059
static int
qemuDomainSetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
9060
    virQEMUDriverPtr driver = dom->conn->privateData;
9061
    size_t i;
9062 9063 9064
    virDomainDefPtr persistentDef = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
9065
    virQEMUDriverConfigPtr cfg = NULL;
9066
    virCapsPtr caps = NULL;
9067
    qemuDomainObjPrivatePtr priv;
9068 9069
    virBitmapPtr nodeset = NULL;
    int mode = -1;
9070 9071 9072

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
9073

9074 9075 9076 9077 9078 9079
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_NUMA_MODE,
                               VIR_TYPED_PARAM_INT,
                               VIR_DOMAIN_NUMA_NODESET,
                               VIR_TYPED_PARAM_STRING,
                               NULL) < 0)
9080
        return -1;
9081

9082 9083
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
9084

9085
    priv = vm->privateData;
9086
    cfg = virQEMUDriverGetConfig(driver);
9087

9088 9089 9090
    if (virDomainSetNumaParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

9094
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9095 9096 9097 9098
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
9099
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
9100 9101
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cgroup cpuset controller is not mounted"));
9102 9103 9104 9105 9106 9107 9108 9109
            goto cleanup;
        }
    }

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

        if (STREQ(param->field, VIR_DOMAIN_NUMA_MODE)) {
9110
            mode = param->value.i;
9111

9112
            if (mode < 0 || mode >= VIR_DOMAIN_NUMATUNE_MEM_LAST) {
9113
                virReportError(VIR_ERR_INVALID_ARG,
9114
                               _("unsupported numatune mode: '%d'"), mode);
9115 9116 9117
                goto cleanup;
            }

9118
        } else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) {
9119
            if (virBitmapParse(param->value.s, 0, &nodeset,
9120
                               VIR_DOMAIN_CPUMASK_LEN) < 0)
9121
                goto cleanup;
9122

9123 9124 9125 9126
            if (virBitmapIsAllClear(nodeset)) {
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Invalid nodeset for numatune"));
                goto cleanup;
9127
            }
9128 9129
        }
    }
9130

9131 9132
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (mode != -1 &&
9133
            virDomainNumatuneGetMode(vm->def->numatune, -1) != mode) {
9134 9135 9136
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("can't change numatune mode for running domain"));
            goto cleanup;
9137
        }
9138 9139 9140 9141 9142

        if (nodeset &&
            qemuDomainSetNumaParamsLive(vm, caps, nodeset) < 0)
            goto cleanup;

9143 9144 9145 9146
        if (virDomainNumatuneSet(&vm->def->numatune,
                                 vm->def->placement_mode ==
                                 VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
                                 -1, mode, nodeset) < 0)
9147
            goto cleanup;
9148 9149 9150
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9151 9152 9153 9154
        if (virDomainNumatuneSet(&persistentDef->numatune,
                                 persistentDef->placement_mode ==
                                 VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
                                 -1, mode, nodeset) < 0)
9155 9156
            goto cleanup;

9157
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
9158
            goto cleanup;
9159 9160
    }

9161 9162
    ret = 0;

9163
 cleanup:
9164
    virBitmapFree(nodeset);
9165
    if (vm)
9166
        virObjectUnlock(vm);
9167
    virObjectUnref(caps);
9168
    virObjectUnref(cfg);
9169 9170 9171 9172 9173 9174 9175 9176 9177
    return ret;
}

static int
qemuDomainGetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
9178
    virQEMUDriverPtr driver = dom->conn->privateData;
9179
    size_t i;
9180 9181 9182 9183
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    char *nodeset = NULL;
    int ret = -1;
9184
    virCapsPtr caps = NULL;
9185
    qemuDomainObjPrivatePtr priv;
9186 9187 9188 9189 9190 9191 9192 9193 9194 9195

    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;

9196 9197
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
9198

9199 9200
    priv = vm->privateData;

9201 9202 9203
    if (virDomainGetNumaParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

9207
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9208 9209 9210 9211 9212 9213 9214 9215 9216 9217
                                        &persistentDef) < 0)
        goto cleanup;

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
9218
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
9219 9220
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
9221 9222 9223 9224 9225 9226 9227 9228 9229
            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 */
9230 9231
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
9232
                goto cleanup;
9233

9234
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
9235
                param->value.i = virDomainNumatuneGetMode(persistentDef->numatune, -1);
9236
            else
9237
                param->value.i = virDomainNumatuneGetMode(vm->def->numatune, -1);
9238 9239 9240 9241
            break;

        case 1: /* fill numa nodeset here */
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9242
                nodeset = virDomainNumatuneFormatNodeset(persistentDef->numatune,
9243
                                                         NULL, -1);
9244
                if (!nodeset)
9245
                    goto cleanup;
9246
            } else {
9247
                if (virCgroupGetCpusetMems(priv->cgroup, &nodeset) < 0)
9248 9249
                    goto cleanup;
            }
9250 9251
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
9252
                goto cleanup;
S
Stefan Berger 已提交
9253 9254 9255

            nodeset = NULL;

9256 9257
            break;

9258
        /* coverity[dead_error_begin] */
9259 9260 9261 9262 9263 9264 9265 9266 9267 9268
        default:
            break;
            /* should not hit here */
        }
    }

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

9269
 cleanup:
S
Stefan Berger 已提交
9270
    VIR_FREE(nodeset);
9271
    if (vm)
9272
        virObjectUnlock(vm);
9273
    virObjectUnref(caps);
9274 9275 9276
    return ret;
}

9277 9278 9279 9280
static int
qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                   unsigned long long period, long long quota)
{
9281
    size_t i;
9282 9283 9284 9285 9286 9287
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virCgroupPtr cgroup_vcpu = NULL;

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

W
Wen Congyang 已提交
9288 9289 9290 9291 9292 9293
    /* 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++) {
9294
            if (virCgroupNewVcpu(cgroup, i, false, &cgroup_vcpu) < 0)
W
Wen Congyang 已提交
9295 9296 9297 9298 9299 9300 9301
                goto cleanup;

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

            virCgroupFree(&cgroup_vcpu);
        }
9302 9303 9304 9305
    }

    return 0;

9306
 cleanup:
9307 9308 9309 9310
    virCgroupFree(&cgroup_vcpu);
    return -1;
}

9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324
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;
    }

9325
    if (virCgroupNewEmulator(cgroup, false, &cgroup_emulator) < 0)
9326 9327 9328 9329 9330 9331 9332 9333
        goto cleanup;

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

    virCgroupFree(&cgroup_emulator);
    return 0;

9334
 cleanup:
9335 9336 9337 9338
    virCgroupFree(&cgroup_emulator);
    return -1;
}

9339 9340 9341 9342 9343 9344 9345 9346 9347
#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;                                                       \
    }

9348
static int
9349 9350 9351 9352
qemuDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                      virTypedParameterPtr params,
                                      int nparams,
                                      unsigned int flags)
9353
{
9354
    virQEMUDriverPtr driver = dom->conn->privateData;
9355
    size_t i;
9356
    virDomainObjPtr vm = NULL;
9357
    virDomainDefPtr vmdef = NULL;
9358 9359
    unsigned long long value_ul;
    long long value_l;
9360
    int ret = -1;
9361
    int rc;
9362
    virQEMUDriverConfigPtr cfg = NULL;
9363
    virCapsPtr caps = NULL;
9364
    qemuDomainObjPrivatePtr priv;
9365 9366 9367 9368
    virObjectEventPtr event = NULL;
    virTypedParameterPtr eventParams = NULL;
    int eventNparams = 0;
    int eventMaxNparams = 0;
9369

9370 9371
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383
    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)
9384
        return -1;
9385

9386 9387
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
9388

9389
    priv = vm->privateData;
9390 9391
    cfg = virQEMUDriverGetConfig(driver);

9392 9393 9394
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

9395 9396 9397 9398 9399 9400
    if (!cfg->privileged) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("CPU tuning is not available in session mode"));
        goto cleanup;
    }

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

9404
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9405 9406
                                        &vmdef) < 0)
        goto cleanup;
9407

9408 9409
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
9410
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
9411 9412
        if (!vmdef)
            goto cleanup;
9413 9414
    }

9415
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
9416
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
9417 9418
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
9419 9420 9421 9422
            goto cleanup;
        }
    }

9423
    for (i = 0; i < nparams; i++) {
9424
        virTypedParameterPtr param = &params[i];
9425 9426
        value_ul = param->value.ul;
        value_l = param->value.l;
9427

9428
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
9429
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
9430
                unsigned long long val;
9431
                if (virCgroupSetCpuShares(priv->cgroup, value_ul) < 0)
9432
                    goto cleanup;
9433 9434 9435 9436 9437

                if (virCgroupGetCpuShares(priv->cgroup, &val) < 0)
                    goto cleanup;

                vm->def->cputune.shares = val;
9438
                vm->def->cputune.sharesSpecified = true;
9439 9440 9441

                if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                            &eventMaxNparams,
9442
                                            VIR_DOMAIN_TUNABLE_CPU_CPU_SHARES,
9443 9444
                                            val) < 0)
                    goto cleanup;
9445
            }
9446

9447
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9448
                vmdef->cputune.shares = value_ul;
9449 9450 9451
                vmdef->cputune.sharesSpecified = true;
            }

9452

9453
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
9454 9455 9456
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

9457
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
9458
                if ((rc = qemuSetVcpusBWLive(vm, priv->cgroup, value_ul, 0)))
9459
                    goto cleanup;
9460

9461
                vm->def->cputune.period = value_ul;
9462 9463 9464

                if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                            &eventMaxNparams,
9465
                                            VIR_DOMAIN_TUNABLE_CPU_VCPU_PERIOD,
9466 9467
                                            value_ul) < 0)
                    goto cleanup;
9468 9469
            }

9470
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
9471
                vmdef->cputune.period = params[i].value.ul;
9472

9473
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
9474 9475 9476
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

9477
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
9478
                if ((rc = qemuSetVcpusBWLive(vm, priv->cgroup, 0, value_l)))
9479
                    goto cleanup;
9480

9481
                vm->def->cputune.quota = value_l;
9482 9483 9484

                if (virTypedParamsAddLLong(&eventParams, &eventNparams,
                                           &eventMaxNparams,
9485
                                           VIR_DOMAIN_TUNABLE_CPU_VCPU_QUOTA,
9486 9487
                                           value_l) < 0)
                    goto cleanup;
9488 9489
            }

9490 9491 9492
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.quota = value_l;

9493
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD)) {
9494 9495 9496
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

9497
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
9498 9499
                if ((rc = qemuSetEmulatorBandwidthLive(vm, priv->cgroup,
                                                       value_ul, 0)))
9500 9501
                    goto cleanup;

9502
                vm->def->cputune.emulator_period = value_ul;
9503 9504 9505

                if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                            &eventMaxNparams,
9506
                                            VIR_DOMAIN_TUNABLE_CPU_EMULATOR_PERIOD,
9507 9508
                                            value_ul) < 0)
                    goto cleanup;
9509 9510
            }

9511 9512 9513
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_period = value_ul;

9514
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA)) {
9515 9516 9517
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

9518
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
9519 9520
                if ((rc = qemuSetEmulatorBandwidthLive(vm, priv->cgroup,
                                                       0, value_l)))
9521 9522
                    goto cleanup;

9523
                vm->def->cputune.emulator_quota = value_l;
9524 9525 9526

                if (virTypedParamsAddLLong(&eventParams, &eventNparams,
                                           &eventMaxNparams,
9527
                                           VIR_DOMAIN_TUNABLE_CPU_EMULATOR_QUOTA,
9528 9529
                                           value_l) < 0)
                    goto cleanup;
9530 9531
            }

9532 9533
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_quota = value_l;
9534 9535
        }
    }
9536

9537
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
9538 9539
        goto cleanup;

9540 9541 9542 9543 9544 9545
    if (eventNparams) {
        event = virDomainEventTunableNewFromDom(dom, eventParams, eventNparams);
        eventNparams = 0;
        if (event)
            qemuDomainEventQueue(driver, event);
    }
9546 9547

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9548
        rc = virDomainSaveConfig(cfg->configDir, vmdef);
9549 9550 9551
        if (rc < 0)
            goto cleanup;

9552
        virDomainObjAssignDef(vm, vmdef, false, NULL);
9553 9554 9555
        vmdef = NULL;
    }

9556 9557
    ret = 0;

9558
 cleanup:
9559
    virDomainDefFree(vmdef);
9560
    if (vm)
9561
        virObjectUnlock(vm);
9562 9563
    if (eventNparams)
        virTypedParamsFree(eventParams, eventNparams);
9564
    virObjectUnref(caps);
9565
    virObjectUnref(cfg);
9566 9567
    return ret;
}
9568
#undef SCHED_RANGE_CHECK
9569

9570
static int
9571 9572 9573
qemuDomainSetSchedulerParameters(virDomainPtr dom,
                                 virTypedParameterPtr params,
                                 int nparams)
9574
{
9575 9576 9577 9578
    return qemuDomainSetSchedulerParametersFlags(dom,
                                                 params,
                                                 nparams,
                                                 VIR_DOMAIN_AFFECT_CURRENT);
9579 9580
}

9581 9582 9583 9584
static int
qemuGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                  long long *quota)
{
9585
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
9586 9587
        return -1;

9588
    if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
9589 9590 9591 9592 9593 9594
        return -1;

    return 0;
}

static int
9595
qemuGetVcpusBWLive(virDomainObjPtr vm,
9596 9597 9598 9599 9600 9601 9602 9603 9604 9605
                   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 */
9606
        rc = qemuGetVcpuBWLive(priv->cgroup, period, quota);
9607 9608 9609 9610 9611 9612 9613 9614 9615
        if (rc < 0)
            goto cleanup;

        if (*quota > 0)
            *quota /= vm->def->vcpus;
        goto out;
    }

    /* get period and quota for vcpu0 */
9616
    if (virCgroupNewVcpu(priv->cgroup, 0, false, &cgroup_vcpu) < 0)
9617 9618 9619 9620 9621 9622
        goto cleanup;

    rc = qemuGetVcpuBWLive(cgroup_vcpu, period, quota);
    if (rc < 0)
        goto cleanup;

9623
 out:
9624 9625
    ret = 0;

9626
 cleanup:
9627 9628 9629 9630
    virCgroupFree(&cgroup_vcpu);
    return ret;
}

9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648
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 */
9649
    if (virCgroupNewEmulator(cgroup, false, &cgroup_emulator) < 0)
9650 9651 9652 9653 9654 9655 9656 9657
        goto cleanup;

    rc = qemuGetVcpuBWLive(cgroup_emulator, period, quota);
    if (rc < 0)
        goto cleanup;

    ret = 0;

9658
 cleanup:
9659 9660 9661 9662
    virCgroupFree(&cgroup_emulator);
    return ret;
}

9663
static int
9664 9665 9666 9667
qemuDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                      virTypedParameterPtr params,
                                      int *nparams,
                                      unsigned int flags)
9668
{
9669
    virQEMUDriverPtr driver = dom->conn->privateData;
9670
    virDomainObjPtr vm = NULL;
9671 9672 9673
    unsigned long long shares;
    unsigned long long period;
    long long quota;
9674 9675
    unsigned long long emulator_period;
    long long emulator_quota;
9676 9677
    int ret = -1;
    int rc;
9678
    bool cpu_bw_status = false;
9679
    int saved_nparams = 0;
9680
    virDomainDefPtr persistentDef;
9681
    virCapsPtr caps = NULL;
9682
    qemuDomainObjPrivatePtr priv;
9683
    virQEMUDriverConfigPtr cfg = NULL;
9684

9685
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
9686 9687
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
9688

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

9692 9693 9694 9695 9696
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;

    priv = vm->privateData;

9697 9698 9699
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9700 9701 9702 9703 9704 9705 9706
    cfg = virQEMUDriverGetConfig(driver);
    if (!cfg->privileged) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("CPU tuning is not available in session mode"));
        goto cleanup;
    }

9707 9708
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
9709

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

9713
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9714 9715
                                        &persistentDef) < 0)
        goto cleanup;
9716

9717
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9718
        shares = persistentDef->cputune.shares;
9719
        if (*nparams > 1) {
9720 9721
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
9722 9723
            emulator_period = persistentDef->cputune.emulator_period;
            emulator_quota = persistentDef->cputune.emulator_quota;
9724
            cpu_bw_status = true; /* Allow copy of data to params[] */
9725
        }
9726
        goto out;
9727 9728
    }

9729
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
9730 9731
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
9732 9733 9734
        goto cleanup;
    }

9735
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
9736
        goto cleanup;
9737 9738

    if (*nparams > 1 && cpu_bw_status) {
9739
        rc = qemuGetVcpusBWLive(vm, &period, &quota);
9740 9741 9742
        if (rc != 0)
            goto cleanup;
    }
9743 9744

    if (*nparams > 3 && cpu_bw_status) {
9745
        rc = qemuGetEmulatorBandwidthLive(vm, priv->cgroup, &emulator_period,
9746 9747 9748 9749 9750
                                          &emulator_quota);
        if (rc != 0)
            goto cleanup;
    }

9751
 out:
9752 9753
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
9754
        goto cleanup;
9755 9756 9757 9758
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
9759 9760 9761
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
9762 9763 9764 9765 9766
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
9767 9768 9769
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
9770 9771 9772
                goto cleanup;
            saved_nparams++;
        }
9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790

        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++;
        }
9791 9792 9793 9794
    }

    *nparams = saved_nparams;

9795 9796
    ret = 0;

9797
 cleanup:
9798
    if (vm)
9799
        virObjectUnlock(vm);
9800
    virObjectUnref(caps);
9801
    virObjectUnref(cfg);
9802 9803 9804
    return ret;
}

9805
static int
9806 9807 9808
qemuDomainGetSchedulerParameters(virDomainPtr dom,
                                 virTypedParameterPtr params,
                                 int *nparams)
9809
{
9810 9811
    return qemuDomainGetSchedulerParametersFlags(dom, params, nparams,
                                                 VIR_DOMAIN_AFFECT_CURRENT);
9812
}
9813

9814 9815 9816 9817 9818 9819 9820
/**
 * 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 已提交
9821 9822 9823 9824
qemuDomainBlockResize(virDomainPtr dom,
                      const char *path,
                      unsigned long long size,
                      unsigned int flags)
9825
{
9826
    virQEMUDriverPtr driver = dom->conn->privateData;
9827 9828
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
9829
    int ret = -1, idx;
9830 9831 9832
    char *device = NULL;
    virDomainDiskDefPtr disk = NULL;

E
Eric Blake 已提交
9833
    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
9834 9835

    if (path[0] == '\0') {
9836 9837
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("empty path"));
9838 9839 9840
        return -1;
    }

E
Eric Blake 已提交
9841 9842 9843
    /* We prefer operating on bytes.  */
    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
        if (size > ULLONG_MAX / 1024) {
9844 9845 9846
            virReportError(VIR_ERR_OVERFLOW,
                           _("size must be less than %llu"),
                           ULLONG_MAX / 1024);
E
Eric Blake 已提交
9847 9848 9849
            return -1;
        }
        size *= 1024;
9850 9851
    }

9852
    if (!(vm = qemuDomObjFromDomain(dom)))
9853 9854 9855 9856
        goto cleanup;

    priv = vm->privateData;

9857 9858 9859
    if (virDomainBlockResizeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9860 9861 9862 9863
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

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

9869
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9870 9871
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
9872
        goto endjob;
9873
    }
9874
    disk = vm->def->disks[idx];
9875

9876 9877 9878
    /* qcow2 and qed must be sized on 512 byte blocks/sectors,
     * so adjust size if necessary to round up.
     */
9879 9880
    if (disk->src->format == VIR_STORAGE_FILE_QCOW2 ||
        disk->src->format == VIR_STORAGE_FILE_QED)
9881 9882
        size = VIR_ROUND_UP(size, 512);

9883
    if (virAsprintf(&device, "%s%s", QEMU_DRIVE_HOST_PREFIX,
9884
                    disk->info.alias) < 0)
9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895
        goto endjob;

    qemuDomainObjEnterMonitor(driver, vm);
    if (qemuMonitorBlockResize(priv->mon, device, size) < 0) {
        qemuDomainObjExitMonitor(driver, vm);
        goto endjob;
    }
    qemuDomainObjExitMonitor(driver, vm);

    ret = 0;

9896
 endjob:
E
Eric Blake 已提交
9897
    if (!qemuDomainObjEndJob(driver, vm))
9898 9899
        vm = NULL;

9900
 cleanup:
9901 9902
    VIR_FREE(device);
    if (vm)
9903
        virObjectUnlock(vm);
9904 9905 9906
    return ret;
}

9907 9908 9909 9910 9911
/* 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
9912 9913
qemuDomainBlockStats(virDomainPtr dom,
                     const char *path,
9914
                     virDomainBlockStatsPtr stats)
9915
{
9916
    virQEMUDriverPtr driver = dom->conn->privateData;
9917 9918
    int idx;
    int ret = -1;
9919
    virDomainObjPtr vm;
9920
    virDomainDiskDefPtr disk = NULL;
9921
    qemuDomainObjPrivatePtr priv;
9922

9923 9924 9925 9926 9927 9928
    if (!*path) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("summary statistics are not supported yet"));
        return ret;
    }

9929
    if (!(vm = qemuDomObjFromDomain(dom)))
9930
        goto cleanup;
9931

9932 9933 9934
    if (virDomainBlockStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

9938
    if (!virDomainObjIsActive(vm)) {
9939 9940
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9941
        goto endjob;
9942 9943
    }

9944
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9945 9946
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
9947
        goto endjob;
9948
    }
9949
    disk = vm->def->disks[idx];
9950

9951
    if (!disk->info.alias) {
9952 9953
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
9954
        goto endjob;
9955
    }
9956

9957
    priv = vm->privateData;
9958

9959
    qemuDomainObjEnterMonitor(driver, vm);
9960 9961 9962 9963
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
9964
                                       NULL,
9965 9966
                                       &stats->wr_req,
                                       &stats->wr_bytes,
9967 9968 9969
                                       NULL,
                                       NULL,
                                       NULL,
9970 9971
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
9972

9973
 endjob:
E
Eric Blake 已提交
9974
    if (!qemuDomainObjEndJob(driver, vm))
9975
        vm = NULL;
9976

9977
 cleanup:
9978
    if (vm)
9979
        virObjectUnlock(vm);
9980
    return ret;
9981 9982
}

9983

9984
static int
9985 9986 9987 9988 9989
qemuDomainBlockStatsFlags(virDomainPtr dom,
                          const char *path,
                          virTypedParameterPtr params,
                          int *nparams,
                          unsigned int flags)
9990
{
9991
    virQEMUDriverPtr driver = dom->conn->privateData;
9992 9993
    int idx;
    int tmp, ret = -1;
9994 9995 9996 9997 9998
    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;
9999
    virTypedParameterPtr param;
10000

10001 10002
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

10003 10004 10005 10006 10007 10008
    if (!*path) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("summary statistics are not supported yet"));
        return ret;
    }

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

10012
    if (!(vm = qemuDomObjFromDomain(dom)))
10013 10014
        goto cleanup;

10015 10016 10017
    if (virDomainBlockStatsFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

10021
    if (!virDomainObjIsActive(vm)) {
10022 10023
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10024
        goto endjob;
10025 10026 10027
    }

    if (*nparams != 0) {
10028
        if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
10029 10030
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
10031
            goto endjob;
10032
        }
10033
        disk = vm->def->disks[idx];
10034 10035

        if (!disk->info.alias) {
10036 10037 10038
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("missing disk device alias name for %s"),
                            disk->dst);
10039
             goto endjob;
10040 10041 10042 10043 10044 10045 10046 10047 10048 10049
        }
    }

    priv = vm->privateData;
    VIR_DEBUG("priv=%p, params=%p, flags=%x", priv, params, flags);

    qemuDomainObjEnterMonitor(driver, vm);
    tmp = *nparams;
    ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);

10050
    if (tmp == 0 || ret < 0) {
10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071
        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;

10072 10073
    tmp = 0;
    ret = -1;
10074

10075 10076
    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
10077 10078
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
10079 10080 10081
            goto endjob;
        tmp++;
    }
10082

10083
    if (tmp < *nparams && wr_req != -1) {
10084
        param = &params[tmp];
10085 10086
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
10087 10088 10089
            goto endjob;
        tmp++;
    }
10090

10091
    if (tmp < *nparams && rd_bytes != -1) {
10092
        param = &params[tmp];
10093 10094
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
10095 10096 10097
            goto endjob;
        tmp++;
    }
10098

10099
    if (tmp < *nparams && rd_req != -1) {
10100
        param = &params[tmp];
10101 10102
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
10103 10104 10105
            goto endjob;
        tmp++;
    }
10106

10107
    if (tmp < *nparams && flush_req != -1) {
10108
        param = &params[tmp];
10109 10110
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ,
                                    VIR_TYPED_PARAM_LLONG, flush_req) < 0)
10111 10112 10113
            goto endjob;
        tmp++;
    }
10114

10115
    if (tmp < *nparams && wr_total_times != -1) {
10116
        param = &params[tmp];
10117 10118 10119
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, wr_total_times) < 0)
10120 10121 10122
            goto endjob;
        tmp++;
    }
10123

10124
    if (tmp < *nparams && rd_total_times != -1) {
10125
        param = &params[tmp];
10126 10127 10128
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, rd_total_times) < 0)
10129 10130 10131
            goto endjob;
        tmp++;
    }
10132

10133
    if (tmp < *nparams && flush_total_times != -1) {
10134
        param = &params[tmp];
10135 10136 10137 10138
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG,
                                    flush_total_times) < 0)
10139 10140
            goto endjob;
        tmp++;
10141 10142
    }

10143 10144 10145 10146 10147
    /* Field 'errs' is meaningless for QEMU, won't set it. */

    ret = 0;
    *nparams = tmp;

10148
 endjob:
E
Eric Blake 已提交
10149
    if (!qemuDomainObjEndJob(driver, vm))
10150 10151
        vm = NULL;

10152
 cleanup:
10153
    if (vm)
10154
        virObjectUnlock(vm);
10155 10156 10157
    return ret;
}

10158
static int
10159 10160
qemuDomainInterfaceStats(virDomainPtr dom,
                         const char *path,
10161
                         virDomainInterfaceStatsPtr stats)
10162
{
10163
    virDomainObjPtr vm;
10164
    size_t i;
10165
    int ret = -1;
10166

10167
    if (!(vm = qemuDomObjFromDomain(dom)))
10168
        goto cleanup;
10169

10170 10171 10172
    if (virDomainInterfaceStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
10173
    if (!virDomainObjIsActive(vm)) {
10174 10175
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10176
        goto cleanup;
10177 10178 10179
    }

    /* Check the path is one of the domain's network interfaces. */
10180
    for (i = 0; i < vm->def->nnets; i++) {
10181
        if (vm->def->nets[i]->ifname &&
10182
            STREQ(vm->def->nets[i]->ifname, path)) {
10183 10184 10185
            ret = 0;
            break;
        }
10186 10187
    }

10188
    if (ret == 0)
10189
        ret = virNetInterfaceStats(path, stats);
10190
    else
10191 10192
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path, '%s' is not a known interface"), path);
10193

10194
 cleanup:
10195
    if (vm)
10196
        virObjectUnlock(vm);
10197 10198
    return ret;
}
10199

10200 10201 10202 10203 10204 10205 10206
static int
qemuDomainSetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 unsigned int flags)
{
10207
    virQEMUDriverPtr driver = dom->conn->privateData;
10208
    size_t i;
10209 10210 10211 10212
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    virDomainNetDefPtr net = NULL, persistentNet = NULL;
10213
    virNetDevBandwidthPtr bandwidth = NULL, newBandwidth = NULL;
10214
    virQEMUDriverConfigPtr cfg = NULL;
10215
    virCapsPtr caps = NULL;
10216
    bool inboundSpecified = false, outboundSpecified = false;
10217 10218 10219

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233
    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)
10234
        return -1;
10235

10236 10237
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
10238

10239 10240
    cfg = virQEMUDriverGetConfig(driver);

10241 10242 10243
    if (virDomainSetInterfaceParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

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

10250
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
10251
                                        &persistentDef) < 0)
10252
        goto endjob;
10253 10254 10255 10256

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        net = virDomainNetFind(vm->def, device);
        if (!net) {
10257 10258
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
10259
            goto endjob;
10260 10261 10262 10263 10264
        }
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        persistentNet = virDomainNetFind(persistentDef, device);
        if (!persistentNet) {
10265 10266
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
10267
            goto endjob;
10268 10269 10270
        }
    }

10271 10272
    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
10273
        (VIR_ALLOC(bandwidth->out) < 0))
10274
        goto endjob;
10275 10276 10277 10278 10279 10280

    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;
10281
            inboundSpecified = true;
10282 10283 10284 10285 10286 10287
        } 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;
10288
            outboundSpecified = true;
10289 10290 10291 10292 10293 10294 10295
        } 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;
        }
    }

10296
    /* average is mandatory, peak and burst are optional. So if no
10297
     * average is given, we free inbound/outbound here which causes
10298
     * inbound/outbound to not be set. */
10299 10300 10301 10302 10303 10304 10305 10306
    if (!bandwidth->in->average) {
        VIR_FREE(bandwidth->in);
    }
    if (!bandwidth->out->average) {
        VIR_FREE(bandwidth->out);
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
10307
        if (VIR_ALLOC(newBandwidth) < 0)
10308
            goto endjob;
10309 10310 10311

        /* virNetDevBandwidthSet() will clear any previous value of
         * bandwidth parameters, so merge with old bandwidth parameters
10312
         * here to prevent them from being lost. */
10313
        if (bandwidth->in ||
10314
            (!inboundSpecified && net->bandwidth && net->bandwidth->in)) {
10315
            if (VIR_ALLOC(newBandwidth->in) < 0)
10316
                goto endjob;
10317 10318 10319 10320 10321 10322

            memcpy(newBandwidth->in,
                   bandwidth->in ? bandwidth->in : net->bandwidth->in,
                   sizeof(*newBandwidth->in));
        }
        if (bandwidth->out ||
10323
            (!outboundSpecified && net->bandwidth && net->bandwidth->out)) {
10324
            if (VIR_ALLOC(newBandwidth->out) < 0)
10325
                goto endjob;
10326 10327 10328 10329

            memcpy(newBandwidth->out,
                   bandwidth->out ? bandwidth->out : net->bandwidth->out,
                   sizeof(*newBandwidth->out));
10330 10331
        }

10332
        if (virNetDevBandwidthSet(net->ifname, newBandwidth, false) < 0)
10333
            goto endjob;
10334 10335

        virNetDevBandwidthFree(net->bandwidth);
10336 10337 10338 10339 10340 10341
        if (newBandwidth->in || newBandwidth->out) {
            net->bandwidth = newBandwidth;
            newBandwidth = NULL;
        } else {
            net->bandwidth = NULL;
        }
10342 10343 10344 10345 10346

        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            virNetDevBandwidthFree(net->data.network.actual->bandwidth);
            if (virNetDevBandwidthCopy(&net->data.network.actual->bandwidth,
                                       net->bandwidth) < 0)
10347
                goto endjob;
10348 10349 10350
        }

        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
10351
            goto endjob;
10352
    }
10353

10354 10355 10356 10357 10358 10359 10360 10361 10362
    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;
10363 10364
            } else  if (inboundSpecified) {
                VIR_FREE(persistentNet->bandwidth->in);
10365 10366 10367 10368 10369
            }
            if (bandwidth->out) {
                VIR_FREE(persistentNet->bandwidth->out);
                persistentNet->bandwidth->out = bandwidth->out;
                bandwidth->out = NULL;
10370 10371
            } else if (outboundSpecified) {
                VIR_FREE(persistentNet->bandwidth->out);
10372 10373 10374
            }
        }

10375
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
10376
            goto endjob;
10377 10378 10379
    }

    ret = 0;
10380 10381 10382 10383 10384

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

10385
 cleanup:
10386
    virNetDevBandwidthFree(bandwidth);
10387
    virNetDevBandwidthFree(newBandwidth);
10388
    if (vm)
10389
        virObjectUnlock(vm);
10390
    virObjectUnref(caps);
10391
    virObjectUnref(cfg);
10392 10393 10394 10395 10396 10397 10398 10399 10400 10401
    return ret;
}

static int
qemuDomainGetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int *nparams,
                                 unsigned int flags)
{
10402
    virQEMUDriverPtr driver = dom->conn->privateData;
10403
    size_t i;
10404 10405 10406 10407 10408
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainDefPtr persistentDef = NULL;
    virDomainNetDefPtr net = NULL;
    int ret = -1;
10409
    virCapsPtr caps = NULL;
10410 10411 10412 10413 10414 10415 10416

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

10417 10418
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
10419

10420 10421 10422
    if (virDomainGetInterfaceParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

10426
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441
                                        &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) {
10442 10443
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Can't find device %s"), device);
10444 10445 10446 10447
        goto cleanup;
    }

    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
10448
        switch (i) {
10449
        case 0: /* inbound.average */
10450 10451 10452
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
10453 10454 10455 10456 10457
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->average;
            break;
        case 1: /* inbound.peak */
10458 10459 10460
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
10461 10462 10463 10464 10465
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->peak;
            break;
        case 2: /* inbound.burst */
10466 10467 10468
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
10469 10470 10471 10472 10473
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->burst;
            break;
        case 3: /* outbound.average */
10474 10475 10476
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
10477 10478 10479 10480 10481
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->average;
            break;
        case 4: /* outbound.peak */
10482 10483 10484
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
10485 10486 10487 10488 10489
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->peak;
            break;
        case 5: /* outbound.burst */
10490 10491 10492
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
10493 10494 10495 10496
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->burst;
            break;
10497
        /* coverity[dead_error_begin] */
10498 10499 10500 10501 10502 10503 10504 10505 10506 10507
        default:
            break;
            /* should not hit here */
        }
    }

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

10508
 cleanup:
10509
    if (vm)
10510
        virObjectUnlock(vm);
10511
    virObjectUnref(caps);
10512 10513 10514
    return ret;
}

10515
static int
10516
qemuDomainMemoryStats(virDomainPtr dom,
10517
                      virDomainMemoryStatPtr stats,
10518 10519
                      unsigned int nr_stats,
                      unsigned int flags)
10520
{
10521
    virQEMUDriverPtr driver = dom->conn->privateData;
10522
    virDomainObjPtr vm;
M
Martin Kletzander 已提交
10523
    int ret = -1;
10524

10525 10526
    virCheckFlags(0, -1);

10527
    if (!(vm = qemuDomObjFromDomain(dom)))
10528 10529
        goto cleanup;

10530 10531 10532
    if (virDomainMemoryStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

M
Martin Kletzander 已提交
10536
    if (!virDomainObjIsActive(vm)) {
10537 10538
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
M
Martin Kletzander 已提交
10539
    } else {
10540
        qemuDomainObjPrivatePtr priv = vm->privateData;
10541
        qemuDomainObjEnterMonitor(driver, vm);
10542
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
10543
        qemuDomainObjExitMonitor(driver, vm);
M
Martin Kletzander 已提交
10544 10545 10546

        if (ret >= 0 && ret < nr_stats) {
            long rss;
10547
            if (qemuGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) {
10548 10549
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("cannot get RSS for domain"));
M
Martin Kletzander 已提交
10550 10551 10552 10553 10554 10555 10556
            } else {
                stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
                stats[ret].val = rss;
                ret++;
            }

        }
10557 10558
    }

E
Eric Blake 已提交
10559
    if (!qemuDomainObjEndJob(driver, vm))
10560 10561
        vm = NULL;

10562
 cleanup:
10563
    if (vm)
10564
        virObjectUnlock(vm);
10565 10566 10567
    return ret;
}

10568
static int
10569 10570 10571 10572 10573
qemuDomainBlockPeek(virDomainPtr dom,
                    const char *path,
                    unsigned long long offset, size_t size,
                    void *buffer,
                    unsigned int flags)
10574
{
10575
    virQEMUDriverPtr driver = dom->conn->privateData;
10576
    virDomainObjPtr vm;
10577 10578
    int fd = -1, ret = -1;
    const char *actual;
10579

E
Eric Blake 已提交
10580 10581
    virCheckFlags(0, -1);

10582
    if (!(vm = qemuDomObjFromDomain(dom)))
10583
        goto cleanup;
10584

10585 10586 10587
    if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10588
    if (!path || path[0] == '\0') {
10589 10590
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
10591
        goto cleanup;
10592 10593
    }

10594 10595
    /* Check the path belongs to this domain.  */
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
10596 10597
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path '%s'"), path);
10598
        goto cleanup;
10599
    }
10600
    path = actual;
10601

10602 10603
    fd = qemuOpenFile(driver, vm, path, O_RDONLY, NULL, NULL);
    if (fd == -1)
10604
        goto cleanup;
10605

10606 10607 10608 10609 10610 10611 10612 10613 10614
    /* 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;
10615 10616
    }

10617 10618
    ret = 0;

10619
 cleanup:
10620
    VIR_FORCE_CLOSE(fd);
10621
    if (vm)
10622
        virObjectUnlock(vm);
10623 10624 10625
    return ret;
}

R
Richard W.M. Jones 已提交
10626
static int
10627 10628 10629 10630
qemuDomainMemoryPeek(virDomainPtr dom,
                     unsigned long long offset, size_t size,
                     void *buffer,
                     unsigned int flags)
R
Richard W.M. Jones 已提交
10631
{
10632
    virQEMUDriverPtr driver = dom->conn->privateData;
10633
    virDomainObjPtr vm;
10634
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
10635
    int fd = -1, ret = -1;
10636
    qemuDomainObjPrivatePtr priv;
10637
    virQEMUDriverConfigPtr cfg = NULL;
R
Richard W.M. Jones 已提交
10638

10639 10640
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

10641
    if (!(vm = qemuDomObjFromDomain(dom)))
10642 10643
        goto cleanup;

10644 10645
    cfg = virQEMUDriverGetConfig(driver);

10646 10647 10648
    if (virDomainMemoryPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10649
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
10650 10651
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
10652
        goto cleanup;
R
Richard W.M. Jones 已提交
10653 10654
    }

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

D
Daniel P. Berrange 已提交
10658
    if (!virDomainObjIsActive(vm)) {
10659 10660
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10661
        goto endjob;
R
Richard W.M. Jones 已提交
10662 10663
    }

10664
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", cfg->cacheDir) < 0)
10665
        goto endjob;
10666

R
Richard W.M. Jones 已提交
10667
    /* Create a temporary filename. */
10668
    if ((fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
10669
        virReportSystemError(errno,
10670
                             _("mkostemp(\"%s\") failed"), tmp);
10671
        goto endjob;
R
Richard W.M. Jones 已提交
10672 10673
    }

10674
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
10675

10676
    priv = vm->privateData;
10677
    qemuDomainObjEnterMonitor(driver, vm);
10678
    if (flags == VIR_MEMORY_VIRTUAL) {
10679
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
10680
            qemuDomainObjExitMonitor(driver, vm);
10681
            goto endjob;
10682
        }
10683
    } else {
10684
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
10685
            qemuDomainObjExitMonitor(driver, vm);
10686
            goto endjob;
10687
        }
R
Richard W.M. Jones 已提交
10688
    }
10689
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
10690 10691

    /* Read the memory file into buffer. */
10692
    if (saferead(fd, buffer, size) == (ssize_t) -1) {
10693 10694 10695
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
10696
        goto endjob;
R
Richard W.M. Jones 已提交
10697 10698 10699
    }

    ret = 0;
10700

10701
 endjob:
E
Eric Blake 已提交
10702
    if (!qemuDomainObjEndJob(driver, vm))
10703
        vm = NULL;
10704

10705
 cleanup:
10706
    VIR_FORCE_CLOSE(fd);
10707 10708
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
10709
    VIR_FREE(tmp);
10710
    if (vm)
10711
        virObjectUnlock(vm);
10712
    virObjectUnref(cfg);
R
Richard W.M. Jones 已提交
10713 10714 10715
    return ret;
}

10716

10717 10718 10719 10720 10721 10722
static int
qemuDomainGetBlockInfo(virDomainPtr dom,
                       const char *path,
                       virDomainBlockInfoPtr info,
                       unsigned int flags)
{
10723
    virQEMUDriverPtr driver = dom->conn->privateData;
10724 10725 10726 10727
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
10728
    virStorageSourcePtr meta = NULL;
10729
    virDomainDiskDefPtr disk = NULL;
10730
    struct stat sb;
10731
    int idx;
10732
    int format;
10733
    int activeFail = false;
10734
    virQEMUDriverConfigPtr cfg = NULL;
10735
    char *alias = NULL;
10736 10737
    char *buf = NULL;
    ssize_t len;
10738 10739 10740

    virCheckFlags(0, -1);

10741
    if (!(vm = qemuDomObjFromDomain(dom)))
10742
        return -1;
10743

10744 10745
    cfg = virQEMUDriverGetConfig(driver);

10746 10747 10748
    if (virDomainGetBlockInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10749
    if (!path || path[0] == '\0') {
10750
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("NULL or empty path"));
10751 10752 10753 10754
        goto cleanup;
    }

    /* Check the path belongs to this domain. */
10755
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
10756 10757
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path %s not assigned to domain"), path);
10758 10759
        goto cleanup;
    }
10760

10761
    disk = vm->def->disks[idx];
10762

10763 10764 10765 10766 10767 10768 10769 10770
    if (virStorageSourceIsLocalStorage(disk->src)) {
        if (!disk->src->path) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("disk '%s' does not currently have a source assigned"),
                           path);
            goto cleanup;
        }

10771 10772
        if ((fd = qemuOpenFile(driver, vm, disk->src->path, O_RDONLY,
                               NULL, NULL)) == -1)
10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799
            goto cleanup;

        if (fstat(fd, &sb) < 0) {
            virReportSystemError(errno,
                                 _("cannot stat file '%s'"), disk->src->path);
            goto cleanup;
        }

        if ((len = virFileReadHeaderFD(fd, VIR_STORAGE_MAX_HEADER, &buf)) < 0) {
            virReportSystemError(errno, _("cannot read header '%s'"),
                                 disk->src->path);
            goto cleanup;
        }
    } else {
        if (virStorageFileInitAs(disk->src, cfg->user, cfg->group) < 0)
            goto cleanup;

        if ((len = virStorageFileReadHeader(disk->src, VIR_STORAGE_MAX_HEADER,
                                            &buf)) < 0)
            goto cleanup;

        if (virStorageFileStat(disk->src, &sb) < 0) {
            virReportSystemError(errno, _("failed to stat remote file '%s'"),
                                 NULLSTR(disk->src->path));
            goto cleanup;
        }
    }
10800 10801

    /* Probe for magic formats */
10802 10803
    if (virDomainDiskGetFormat(disk)) {
        format = virDomainDiskGetFormat(disk);
10804
    } else {
10805
        if (!cfg->allowDiskFormatProbing) {
10806 10807
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no disk format for %s and probing is disabled"),
10808
                           path);
10809
            goto cleanup;
10810
        }
10811 10812 10813 10814

        if ((format = virStorageFileProbeFormatFromBuf(disk->src->path,
                                                       buf, len)) < 0)
            goto cleanup;
10815 10816
    }

10817 10818
    if (!(meta = virStorageFileGetMetadataFromBuf(disk->src->path, buf, len,
                                                  format, NULL)))
10819 10820 10821
        goto cleanup;

    /* Get info for normal formats */
10822
    if (S_ISREG(sb.st_mode) || fd == -1) {
10823
#ifndef WIN32
10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836
        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.
         */
10837
        end = lseek(fd, 0, SEEK_END);
10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848
        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 */
10849 10850
    if (meta->capacity)
        info->capacity = meta->capacity;
10851

10852
    /* Set default value .. */
10853 10854
    info->allocation = info->physical;

10855 10856 10857
    /* ..but if guest is not using raw disk format and on a block device,
     * then query highest allocated extent from QEMU
     */
10858
    if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_BLOCK &&
10859
        format != VIR_STORAGE_FILE_RAW &&
10860
        S_ISBLK(sb.st_mode)) {
10861
        qemuDomainObjPrivatePtr priv = vm->privateData;
10862

10863 10864 10865 10866 10867 10868 10869 10870 10871
        /* 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;
        }

10872 10873 10874
        if (VIR_STRDUP(alias, disk->info.alias) < 0)
            goto cleanup;

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

10878
        if (virDomainObjIsActive(vm)) {
10879
            qemuDomainObjEnterMonitor(driver, vm);
10880
            ret = qemuMonitorGetBlockExtent(priv->mon,
10881
                                            alias,
10882 10883
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
10884
        } else {
10885
            activeFail = true;
10886
            ret = 0;
10887
        }
10888

E
Eric Blake 已提交
10889
        if (!qemuDomainObjEndJob(driver, vm))
10890
            vm = NULL;
10891 10892 10893
    } else {
        ret = 0;
    }
10894

10895
 cleanup:
10896
    VIR_FREE(buf);
10897
    VIR_FREE(alias);
10898
    virStorageSourceFree(meta);
10899
    VIR_FORCE_CLOSE(fd);
10900 10901
    if (disk)
        virStorageFileDeinit(disk->src);
10902 10903 10904 10905 10906 10907 10908 10909 10910

    /* 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;
    }
10911
    virObjectUnlock(vm);
10912
    virObjectUnref(cfg);
10913 10914 10915 10916
    return ret;
}


10917
static int
10918 10919 10920 10921
qemuConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
10922
{
10923
    virQEMUDriverPtr driver = conn->privateData;
10924
    int ret = -1;
10925

10926 10927 10928 10929 10930 10931 10932
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        goto cleanup;

    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        goto cleanup;
10933

10934 10935
    ret = 0;

10936
 cleanup:
10937
    return ret;
10938 10939
}

10940

10941
static int
10942 10943
qemuConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
10944
{
10945
    virQEMUDriverPtr driver = conn->privateData;
10946
    int ret = -1;
10947

10948 10949 10950 10951 10952 10953 10954 10955 10956
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        goto cleanup;

    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        goto cleanup;

    ret = 0;
10957

10958
 cleanup:
10959
    return ret;
10960 10961
}

10962 10963

static int
10964 10965 10966 10967 10968 10969
qemuConnectDomainEventRegisterAny(virConnectPtr conn,
                                  virDomainPtr dom,
                                  int eventID,
                                  virConnectDomainEventGenericCallback callback,
                                  void *opaque,
                                  virFreeCallback freecb)
10970
{
10971
    virQEMUDriverPtr driver = conn->privateData;
10972 10973 10974 10975
    int ret = -1;

    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        goto cleanup;
10976

10977 10978 10979 10980
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
10981
        ret = -1;
10982

10983
 cleanup:
10984 10985 10986 10987 10988
    return ret;
}


static int
10989 10990
qemuConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
10991
{
10992
    virQEMUDriverPtr driver = conn->privateData;
10993
    int ret = -1;
10994

10995 10996
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        goto cleanup;
10997

10998
    if (virObjectEventStateDeregisterID(conn,
10999 11000 11001 11002 11003 11004
                                        driver->domainEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;

11005
 cleanup:
11006 11007 11008 11009
    return ret;
}


11010 11011 11012
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
11013

C
Chris Lalancette 已提交
11014 11015 11016 11017 11018 11019
/* 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
11020 11021 11022 11023 11024 11025
qemuDomainMigratePrepareTunnel(virConnectPtr dconn,
                               virStreamPtr st,
                               unsigned long flags,
                               const char *dname,
                               unsigned long resource ATTRIBUTE_UNUSED,
                               const char *dom_xml)
C
Chris Lalancette 已提交
11026
{
11027
    virQEMUDriverPtr driver = dconn->privateData;
11028
    virDomainDefPtr def = NULL;
11029
    char *origname = NULL;
C
Chris Lalancette 已提交
11030
    int ret = -1;
11031

11032
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
11033

C
Chris Lalancette 已提交
11034
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
11035 11036
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("PrepareTunnel called but no TUNNELLED flag set"));
C
Chris Lalancette 已提交
11037 11038 11039
        goto cleanup;
    }

11040
    if (virLockManagerPluginUsesState(driver->lockManager)) {
11041 11042 11043
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
11044 11045 11046
        goto cleanup;
    }

11047
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
11048 11049
        goto cleanup;

11050 11051 11052
    if (virDomainMigratePrepareTunnelEnsureACL(dconn, def) < 0)
        goto cleanup;

11053 11054
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
11055
                                     st, &def, origname, flags);
11056

11057
 cleanup:
11058
    VIR_FREE(origname);
11059
    virDomainDefFree(def);
C
Chris Lalancette 已提交
11060 11061 11062
    return ret;
}

D
Daniel Veillard 已提交
11063 11064 11065 11066
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
11067
static int ATTRIBUTE_NONNULL(5)
11068 11069 11070 11071 11072 11073 11074 11075 11076
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 已提交
11077
{
11078
    virQEMUDriverPtr driver = dconn->privateData;
11079
    virDomainDefPtr def = NULL;
11080
    char *origname = NULL;
11081
    int ret = -1;
11082

11083
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
11084

C
Chris Lalancette 已提交
11085 11086 11087 11088
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
11089 11090 11091
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Tunnelled migration requested but invalid "
                         "RPC method called"));
C
Chris Lalancette 已提交
11092 11093 11094
        goto cleanup;
    }

11095
    if (virLockManagerPluginUsesState(driver->lockManager)) {
11096
        virReportError(VIR_ERR_INTERNAL_ERROR,
11097 11098
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
11099
        goto cleanup;
D
Daniel Veillard 已提交
11100 11101
    }

11102
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
11103 11104
        goto cleanup;

11105 11106 11107
    if (virDomainMigratePrepare2EnsureACL(dconn, def) < 0)
        goto cleanup;

11108 11109 11110 11111
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
11112
    ret = qemuMigrationPrepareDirect(driver, dconn,
11113
                                     NULL, 0, NULL, NULL, /* No cookies */
11114
                                     uri_in, uri_out,
11115
                                     &def, origname, NULL, flags);
D
Daniel Veillard 已提交
11116

11117
 cleanup:
11118
    VIR_FREE(origname);
11119
    virDomainDefFree(def);
11120 11121
    return ret;
}
C
Chris Lalancette 已提交
11122

D
Daniel Veillard 已提交
11123

11124 11125
/* Perform is the second step, and it runs on the source host. */
static int
11126 11127 11128 11129 11130 11131 11132
qemuDomainMigratePerform(virDomainPtr dom,
                         const char *cookie,
                         int cookielen,
                         const char *uri,
                         unsigned long flags,
                         const char *dname,
                         unsigned long resource)
11133
{
11134
    virQEMUDriverPtr driver = dom->conn->privateData;
11135 11136
    virDomainObjPtr vm;
    int ret = -1;
11137
    const char *dconnuri = NULL;
11138

11139
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
11140

11141
    if (virLockManagerPluginUsesState(driver->lockManager)) {
11142 11143 11144
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
11145 11146 11147
        goto cleanup;
    }

11148
    if (!(vm = qemuDomObjFromDomain(dom)))
11149
        goto cleanup;
D
Daniel Veillard 已提交
11150

11151 11152 11153
    if (virDomainMigratePerformEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11154 11155 11156 11157 11158
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

11159 11160 11161 11162 11163 11164
    /* 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
     */
11165
    ret = qemuMigrationPerform(driver, dom->conn, vm,
11166 11167
                               NULL, dconnuri, uri, NULL, NULL,
                               cookie, cookielen,
11168
                               NULL, NULL, /* No output cookies in v2 */
11169
                               flags, dname, resource, false);
11170

11171
 cleanup:
11172
    return ret;
D
Daniel Veillard 已提交
11173 11174
}

11175

D
Daniel Veillard 已提交
11176 11177
/* Finish is the third and final step, and it runs on the destination host. */
static virDomainPtr
11178 11179 11180 11181 11182 11183 11184
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 已提交
11185
{
11186
    virQEMUDriverPtr driver = dconn->privateData;
11187 11188
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
11189

11190
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
11191

11192
    vm = virDomainObjListFindByName(driver->domains, dname);
D
Daniel Veillard 已提交
11193
    if (!vm) {
11194 11195
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
11196
        goto cleanup;
D
Daniel Veillard 已提交
11197 11198
    }

11199 11200 11201
    if (virDomainMigrateFinish2EnsureACL(dconn, vm->def) < 0)
        goto cleanup;

11202 11203 11204 11205
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
11206
    dom = qemuMigrationFinish(driver, dconn, vm,
11207
                              NULL, 0, NULL, NULL, /* No cookies */
11208
                              flags, retcode, false);
11209

11210
 cleanup:
11211
    return dom;
D
Daniel Veillard 已提交
11212 11213
}

11214

11215 11216 11217 11218 11219 11220
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
11221
                        const char *xmlin,
11222 11223 11224
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
11225
                        const char *dname,
11226 11227 11228 11229
                        unsigned long resource ATTRIBUTE_UNUSED)
{
    virDomainObjPtr vm;

11230
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
11231

11232 11233
    if (!(vm = qemuDomObjFromDomain(domain)))
        return NULL;
11234

11235
    if (virDomainMigrateBegin3EnsureACL(domain->conn, vm->def) < 0) {
11236
        virObjectUnlock(vm);
11237
        return NULL;
11238
    }
11239 11240 11241

    return qemuMigrationBegin(domain->conn, vm, xmlin, dname,
                              cookieout, cookieoutlen, flags);
11242 11243
}

11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280
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);
}


11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293
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)
{
11294
    virQEMUDriverPtr driver = dconn->privateData;
11295
    virDomainDefPtr def = NULL;
11296
    char *origname = NULL;
11297 11298
    int ret = -1;

11299
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
11300 11301 11302 11303 11304

    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
11305 11306 11307
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Tunnelled migration requested but invalid "
                         "RPC method called"));
11308 11309 11310
        goto cleanup;
    }

11311
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
11312 11313
        goto cleanup;

11314 11315 11316
    if (virDomainMigratePrepare3EnsureACL(dconn, def) < 0)
        goto cleanup;

11317 11318 11319 11320
    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
11321
                                     &def, origname, NULL, flags);
11322

11323
 cleanup:
11324
    VIR_FREE(origname);
11325
    virDomainDefFree(def);
11326 11327 11328
    return ret;
}

11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340
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;
11341
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
11342 11343 11344 11345
    virDomainDefPtr def = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri_in = NULL;
11346
    const char *listenAddress = cfg->migrationAddress;
11347
    char *origname = NULL;
11348 11349
    int ret = -1;

11350
    virCheckFlagsGoto(QEMU_MIGRATION_FLAGS, cleanup);
11351
    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
11352
        goto cleanup;
11353 11354 11355 11356 11357 11358 11359 11360 11361

    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,
11362 11363 11364 11365
                                &uri_in) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
                                &listenAddress) < 0)
11366
        goto cleanup;
11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377

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

11378
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
11379 11380 11381 11382 11383 11384 11385 11386 11387
        goto cleanup;

    if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0)
        goto cleanup;

    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
11388
                                     &def, origname, listenAddress, flags);
11389

11390
 cleanup:
11391
    VIR_FREE(origname);
11392
    virDomainDefFree(def);
11393
    virObjectUnref(cfg);
11394 11395 11396
    return ret;
}

11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409

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)
{
11410
    virQEMUDriverPtr driver = dconn->privateData;
11411
    virDomainDefPtr def = NULL;
11412
    char *origname = NULL;
11413 11414
    int ret = -1;

11415
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
11416 11417

    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
11418 11419
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("PrepareTunnel called but no TUNNELLED flag set"));
11420 11421 11422
        goto cleanup;
    }

11423
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
11424 11425
        goto cleanup;

11426 11427 11428
    if (virDomainMigratePrepareTunnel3EnsureACL(dconn, def) < 0)
        goto cleanup;

11429 11430 11431
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
11432
                                     st, &def, origname, flags);
11433

11434
 cleanup:
11435
    VIR_FREE(origname);
11436
    virDomainDefFree(def);
11437 11438 11439
    return ret;
}

11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454
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;
11455
    char *origname = NULL;
11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475
    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;
    }

11476
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
11477 11478 11479 11480 11481 11482 11483 11484
        goto cleanup;

    if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0)
        goto cleanup;

    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
11485
                                     st, &def, origname, flags);
11486

11487
 cleanup:
11488
    VIR_FREE(origname);
11489 11490 11491 11492
    virDomainDefFree(def);
    return ret;
}

11493 11494 11495

static int
qemuDomainMigratePerform3(virDomainPtr dom,
11496
                          const char *xmlin,
11497 11498 11499 11500
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
11501
                          const char *dconnuri,
11502 11503 11504 11505 11506
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
11507
    virQEMUDriverPtr driver = dom->conn->privateData;
11508 11509
    virDomainObjPtr vm;

11510
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
11511

11512 11513
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
11514

11515 11516 11517 11518 11519
    if (virDomainMigratePerform3EnsureACL(dom->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

11520
    return qemuMigrationPerform(driver, dom->conn, vm, xmlin,
11521 11522
                                dconnuri, uri, NULL, NULL,
                                cookiein, cookieinlen,
11523 11524
                                cookieout, cookieoutlen,
                                flags, dname, resource, true);
11525 11526
}

11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542
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;
11543
    const char *graphicsuri = NULL;
11544
    const char *listenAddress = NULL;
11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561
    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,
11562 11563 11564
                                &bandwidth) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_GRAPHICS_URI,
11565 11566 11567 11568
                                &graphicsuri) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
                                &listenAddress) < 0)
11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579
        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,
11580
                                dconnuri, uri, graphicsuri, listenAddress,
11581
                                cookiein, cookieinlen, cookieout, cookieoutlen,
11582 11583 11584
                                flags, dname, bandwidth, true);
}

11585

11586
static virDomainPtr
11587 11588 11589 11590 11591 11592
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
11593
                         const char *dconnuri ATTRIBUTE_UNUSED,
11594 11595
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
11596
                         int cancelled)
11597
{
11598
    virQEMUDriverPtr driver = dconn->privateData;
11599 11600
    virDomainObjPtr vm;

11601
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
11602

11603 11604
    if (!dname ||
        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
11605
        virReportError(VIR_ERR_NO_DOMAIN,
11606 11607 11608
                       _("no domain with matching name '%s'"),
                       NULLSTR(dname));
        return NULL;
11609 11610
    }

11611 11612 11613 11614
    if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0) {
        virObjectUnlock(vm);
        return NULL;
    }
11615

11616 11617 11618 11619 11620
    return qemuMigrationFinish(driver, dconn, vm,
                               cookiein, cookieinlen,
                               cookieout, cookieoutlen,
                               flags, cancelled, true);
}
11621

11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662
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);
11663 11664
}

11665

11666 11667 11668 11669 11670 11671 11672 11673 11674
static int
qemuDomainMigrateConfirm3(virDomainPtr domain,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned long flags,
                          int cancelled)
{
    virDomainObjPtr vm;

11675
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
11676

11677 11678
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
11679

11680 11681 11682
    if (virDomainMigrateConfirm3EnsureACL(domain->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
11683 11684
    }

11685 11686
    return qemuMigrationConfirm(domain->conn, vm, cookiein, cookieinlen,
                                flags, cancelled);
11687 11688
}

11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716
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);
}

11717

11718
static int
11719
qemuNodeDeviceGetPCIInfo(virNodeDeviceDefPtr def,
11720 11721 11722 11723
                         unsigned *domain,
                         unsigned *bus,
                         unsigned *slot,
                         unsigned *function)
11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741
{
    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) {
11742
        virReportError(VIR_ERR_INVALID_ARG,
11743
                       _("device %s is not a PCI device"), def->name);
11744 11745 11746 11747
        goto out;
    }

    ret = 0;
11748
 out:
11749 11750 11751 11752
    return ret;
}

static int
11753 11754 11755
qemuNodeDeviceDetachFlags(virNodeDevicePtr dev,
                          const char *driverName,
                          unsigned int flags)
11756
{
11757
    virQEMUDriverPtr driver = dev->conn->privateData;
11758
    virPCIDevicePtr pci = NULL;
11759
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
11760
    int ret = -1;
11761 11762
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
11763 11764
    bool legacy = qemuHostdevHostSupportsPassthroughLegacy();
    bool vfio = qemuHostdevHostSupportsPassthroughVFIO();
11765
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
11766

11767 11768
    virCheckFlags(0, -1);

11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779
    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;

11780
    if (qemuNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
11781
        goto cleanup;
11782

11783
    pci = virPCIDeviceNew(domain, bus, slot, function);
11784
    if (!pci)
11785
        goto cleanup;
11786

11787
    if (!driverName) {
11788
        if (vfio) {
11789
            driverName = "vfio";
11790
        } else if (legacy) {
11791
            driverName = "kvm";
11792 11793 11794 11795 11796 11797
        } else {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("neither VFIO nor KVM device assignment is "
                             "currently supported on this system"));
            goto cleanup;
        }
11798 11799
    }

11800 11801 11802 11803 11804 11805 11806
    if (STREQ(driverName, "vfio")) {
        if (!vfio) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("VFIO device assignment is currently not "
                             "supported on this system"));
            goto cleanup;
        }
11807 11808
        if (virPCIDeviceSetStubDriver(pci, "vfio-pci") < 0)
            goto cleanup;
11809
    } else if (STREQ(driverName, "kvm")) {
11810 11811 11812 11813 11814 11815
        if (!legacy) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("KVM device assignment is currently not "
                             "supported on this system"));
            goto cleanup;
        }
11816 11817
        if (virPCIDeviceSetStubDriver(pci, "pci-stub") < 0)
            goto cleanup;
11818 11819 11820
    } else {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown driver name '%s'"), driverName);
11821
        goto cleanup;
11822 11823
    }

11824
    ret = virHostdevPCINodeDeviceDetach(hostdev_mgr, pci);
11825
 cleanup:
11826
    virPCIDeviceFree(pci);
11827 11828
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11829 11830 11831
    return ret;
}

11832 11833 11834 11835 11836 11837
static int
qemuNodeDeviceDettach(virNodeDevicePtr dev)
{
    return qemuNodeDeviceDetachFlags(dev, NULL, 0);
}

11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859
static int
qemuNodeDeviceReAttach(virNodeDevicePtr dev)
{
    virQEMUDriverPtr driver = dev->conn->privateData;
    virPCIDevicePtr pci = NULL;
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
    int ret = -1;
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
    if (!def)
        goto cleanup;

    if (virNodeDeviceReAttachEnsureACL(dev->conn, def) < 0)
        goto cleanup;

11860
    if (qemuNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
11861 11862 11863 11864 11865 11866
        goto cleanup;

    pci = virPCIDeviceNew(domain, bus, slot, function);
    if (!pci)
        goto cleanup;

11867
    ret = virHostdevPCINodeDeviceReAttach(hostdev_mgr, pci);
11868

11869
    virPCIDeviceFree(pci);
11870
 cleanup:
11871 11872
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11873 11874 11875 11876
    return ret;
}

static int
11877
qemuNodeDeviceReset(virNodeDevicePtr dev)
11878
{
11879
    virQEMUDriverPtr driver = dev->conn->privateData;
11880
    virPCIDevicePtr pci;
11881
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
11882
    int ret = -1;
11883 11884
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
11885
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
11886

11887 11888 11889 11890 11891 11892 11893 11894 11895 11896 11897
    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;

11898
    if (qemuNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
11899
        goto cleanup;
11900

11901
    pci = virPCIDeviceNew(domain, bus, slot, function);
11902
    if (!pci)
11903
        goto cleanup;
11904

11905
    ret = virHostdevPCINodeDeviceReset(hostdev_mgr, pci);
11906

11907
    virPCIDeviceFree(pci);
11908
 cleanup:
11909 11910
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11911 11912 11913
    return ret;
}

11914
static int
11915 11916 11917
qemuConnectCompareCPU(virConnectPtr conn,
                      const char *xmlDesc,
                      unsigned int flags)
11918
{
11919
    virQEMUDriverPtr driver = conn->privateData;
11920
    int ret = VIR_CPU_COMPARE_ERROR;
11921
    virCapsPtr caps = NULL;
11922
    bool failIncomaptible;
11923

11924 11925
    virCheckFlags(VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE,
                  VIR_CPU_COMPARE_ERROR);
E
Eric Blake 已提交
11926

11927 11928 11929
    if (virConnectCompareCPUEnsureACL(conn) < 0)
        goto cleanup;

11930 11931
    failIncomaptible = !!(flags & VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE);

11932 11933 11934 11935 11936
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!caps->host.cpu ||
        !caps->host.cpu->model) {
11937 11938 11939 11940 11941 11942 11943
        if (failIncomaptible) {
            virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s",
                           _("cannot get host CPU capabilities"));
        } else {
            VIR_WARN("cannot get host CPU capabilities");
            ret = VIR_CPU_COMPARE_INCOMPATIBLE;
        }
E
Eric Blake 已提交
11944
    } else {
11945
        ret = cpuCompareXML(caps->host.cpu, xmlDesc, failIncomaptible);
E
Eric Blake 已提交
11946
    }
11947

11948
 cleanup:
11949
    virObjectUnref(caps);
11950 11951 11952
    return ret;
}

11953

11954
static char *
11955 11956 11957 11958
qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
                       const char **xmlCPUs,
                       unsigned int ncpus,
                       unsigned int flags)
11959
{
11960
    char *cpu = NULL;
11961

11962
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
E
Eric Blake 已提交
11963

11964 11965 11966
    if (virConnectBaselineCPUEnsureACL(conn) < 0)
        goto cleanup;

11967
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
11968

11969
 cleanup:
11970 11971 11972
    return cpu;
}

11973 11974

static int qemuDomainGetJobInfo(virDomainPtr dom,
11975 11976
                                virDomainJobInfoPtr info)
{
11977 11978 11979 11980
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

11981
    if (!(vm = qemuDomObjFromDomain(dom)))
11982 11983 11984 11985
        goto cleanup;

    priv = vm->privateData;

11986 11987 11988
    if (virDomainGetJobInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11989
    if (virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
11990
        if (priv->job.current) {
11991 11992 11993 11994 11995
            /* 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
             */
J
Jiri Denemark 已提交
11996 11997
            if (qemuDomainJobInfoUpdateTime(priv->job.current) < 0 ||
                qemuDomainJobInfoToInfo(priv->job.current, info) < 0)
11998
                goto cleanup;
11999 12000 12001 12002 12003
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
12004 12005
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
12006 12007 12008 12009 12010
        goto cleanup;
    }

    ret = 0;

12011
 cleanup:
12012
    if (vm)
12013
        virObjectUnlock(vm);
12014 12015 12016 12017
    return ret;
}


12018 12019 12020 12021 12022 12023 12024 12025 12026
static int
qemuDomainGetJobStats(virDomainPtr dom,
                      int *type,
                      virTypedParameterPtr *params,
                      int *nparams,
                      unsigned int flags)
{
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
12027
    qemuDomainJobInfoPtr jobInfo;
12028 12029
    int ret = -1;

12030
    virCheckFlags(VIR_DOMAIN_JOB_STATS_COMPLETED, -1);
12031 12032 12033 12034 12035 12036

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

    priv = vm->privateData;

12037 12038 12039
    if (virDomainGetJobStatsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

12040 12041
    if (!(flags & VIR_DOMAIN_JOB_STATS_COMPLETED) &&
        !virDomainObjIsActive(vm)) {
12042 12043 12044 12045 12046
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

12047 12048 12049 12050 12051 12052
    if (flags & VIR_DOMAIN_JOB_STATS_COMPLETED)
        jobInfo = priv->job.completed;
    else
        jobInfo = priv->job.current;

    if (!jobInfo) {
12053 12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064
        *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
     */
12065 12066 12067 12068 12069 12070
    if ((jobInfo->type == VIR_DOMAIN_JOB_BOUNDED ||
         jobInfo->type == VIR_DOMAIN_JOB_UNBOUNDED) &&
        qemuDomainJobInfoUpdateTime(jobInfo) < 0)
        goto cleanup;

    if (qemuDomainJobInfoToParams(jobInfo, type, params, nparams) < 0)
J
Jiri Denemark 已提交
12071
        goto cleanup;
12072

12073 12074 12075
    if (flags & VIR_DOMAIN_JOB_STATS_COMPLETED)
        VIR_FREE(priv->job.completed);

12076 12077
    ret = 0;

12078
 cleanup:
12079 12080 12081 12082 12083 12084
    if (vm)
        virObjectUnlock(vm);
    return ret;
}


12085 12086
static int qemuDomainAbortJob(virDomainPtr dom)
{
12087
    virQEMUDriverPtr driver = dom->conn->privateData;
12088 12089 12090 12091
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

12092
    if (!(vm = qemuDomObjFromDomain(dom)))
12093 12094
        goto cleanup;

12095 12096 12097
    if (virDomainAbortJobEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

12098 12099
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
12100

12101
    if (!virDomainObjIsActive(vm)) {
12102 12103
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
12104
        goto endjob;
12105 12106
    }

12107 12108
    priv = vm->privateData;

12109
    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
12110 12111
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no job is active on the domain"));
12112 12113
        goto endjob;
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
12114 12115 12116
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot abort incoming migration;"
                         " use virDomainDestroy instead"));
12117 12118 12119 12120
        goto endjob;
    }

    VIR_DEBUG("Cancelling job at client request");
12121
    qemuDomainObjAbortAsyncJob(vm);
12122
    qemuDomainObjEnterMonitor(driver, vm);
12123 12124 12125
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

12126
 endjob:
E
Eric Blake 已提交
12127
    if (!qemuDomainObjEndJob(driver, vm))
12128
        vm = NULL;
12129

12130
 cleanup:
12131
    if (vm)
12132
        virObjectUnlock(vm);
12133 12134 12135 12136
    return ret;
}


12137 12138 12139 12140 12141
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
12142
    virQEMUDriverPtr driver = dom->conn->privateData;
12143 12144 12145 12146
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

12147
    virCheckFlags(0, -1);
12148

12149 12150
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
12151

12152 12153 12154
    if (virDomainMigrateSetMaxDowntimeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

12155 12156 12157
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

12158
    if (!virDomainObjIsActive(vm)) {
12159 12160
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
12161
        goto endjob;
12162 12163 12164 12165
    }

    priv = vm->privateData;

12166
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
12167
    qemuDomainObjEnterMonitor(driver, vm);
12168 12169 12170
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

12171
 endjob:
E
Eric Blake 已提交
12172
    if (!qemuDomainObjEndJob(driver, vm))
12173
        vm = NULL;
12174

12175
 cleanup:
12176
    if (vm)
12177
        virObjectUnlock(vm);
12178 12179 12180
    return ret;
}

12181 12182 12183 12184 12185 12186 12187 12188 12189 12190 12191 12192 12193 12194 12195
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;

12196 12197 12198
    if (virDomainMigrateGetCompressionCacheEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

12199 12200 12201 12202 12203 12204 12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225
    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);

12226
 endjob:
E
Eric Blake 已提交
12227
    if (!qemuDomainObjEndJob(driver, vm))
12228 12229
        vm = NULL;

12230
 cleanup:
12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250
    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;

12251 12252 12253
    if (virDomainMigrateSetCompressionCacheEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 12279 12280 12281
    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);

12282
 endjob:
E
Eric Blake 已提交
12283
    if (!qemuDomainObjEndJob(driver, vm))
12284 12285
        vm = NULL;

12286
 cleanup:
12287 12288 12289 12290 12291
    if (vm)
        virObjectUnlock(vm);
    return ret;
}

12292 12293 12294 12295 12296
static int
qemuDomainMigrateSetMaxSpeed(virDomainPtr dom,
                             unsigned long bandwidth,
                             unsigned int flags)
{
12297
    virQEMUDriverPtr driver = dom->conn->privateData;
12298 12299 12300 12301 12302 12303
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

12304 12305
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
12306 12307

    priv = vm->privateData;
12308 12309 12310 12311

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

12312 12313 12314 12315 12316 12317 12318
    if (bandwidth > QEMU_DOMAIN_MIG_BANDWIDTH_MAX) {
        virReportError(VIR_ERR_OVERFLOW,
                       _("bandwidth must be less than %llu"),
                       QEMU_DOMAIN_MIG_BANDWIDTH_MAX + 1ULL);
        goto cleanup;
    }

12319 12320 12321
    if (virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
            goto cleanup;
12322

12323
        if (!virDomainObjIsActive(vm)) {
12324 12325
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is not running"));
12326 12327 12328
            goto endjob;
        }

12329 12330 12331 12332
        VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
        qemuDomainObjExitMonitor(driver, vm);
12333

12334 12335
        if (ret == 0)
            priv->migMaxBandwidth = bandwidth;
12336

12337
 endjob:
E
Eric Blake 已提交
12338
        if (!qemuDomainObjEndJob(driver, vm))
12339 12340 12341 12342 12343
            vm = NULL;
    } else {
        priv->migMaxBandwidth = bandwidth;
        ret = 0;
    }
12344

12345
 cleanup:
12346
    if (vm)
12347
        virObjectUnlock(vm);
12348 12349 12350
    return ret;
}

12351 12352 12353 12354 12355 12356
static int
qemuDomainMigrateGetMaxSpeed(virDomainPtr dom,
                             unsigned long *bandwidth,
                             unsigned int flags)
{
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
12357
    qemuDomainObjPrivatePtr priv;
12358 12359 12360 12361
    int ret = -1;

    virCheckFlags(0, -1);

12362
    if (!(vm = qemuDomObjFromDomain(dom)))
12363 12364
        goto cleanup;

J
Jim Fehlig 已提交
12365
    priv = vm->privateData;
12366 12367 12368 12369

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

J
Jim Fehlig 已提交
12370
    *bandwidth = priv->migMaxBandwidth;
12371 12372
    ret = 0;

12373
 cleanup:
12374
    if (vm)
12375
        virObjectUnlock(vm);
12376 12377 12378
    return ret;
}

12379

12380 12381 12382 12383 12384 12385
typedef enum {
    VIR_DISK_CHAIN_NO_ACCESS,
    VIR_DISK_CHAIN_READ_ONLY,
    VIR_DISK_CHAIN_READ_WRITE,
} qemuDomainDiskChainMode;

12386 12387 12388 12389 12390
/* 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.  */
12391
static int
12392
qemuDomainPrepareDiskChainElement(virQEMUDriverPtr driver,
12393
                                  virDomainObjPtr vm,
12394
                                  virStorageSourcePtr elem,
12395 12396
                                  qemuDomainDiskChainMode mode)
{
12397
    bool readonly = elem->readonly;
12398
    virQEMUDriverConfigPtr cfg = NULL;
12399 12400
    int ret = -1;

12401 12402
    cfg = virQEMUDriverGetConfig(driver);

12403
    elem->readonly = mode == VIR_DISK_CHAIN_READ_ONLY;
12404 12405

    if (mode == VIR_DISK_CHAIN_NO_ACCESS) {
12406 12407 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 12423 12424 12425
        if (virSecurityManagerRestoreImageLabel(driver->securityManager,
                                                vm->def, elem) < 0)
            VIR_WARN("Unable to restore security label on %s", elem->path);

        if (qemuSetImageCgroup(vm, elem, true) < 0)
            VIR_WARN("Failed to teardown cgroup for disk path %s", elem->path);

        if (virDomainLockImageDetach(driver->lockManager, vm, elem) < 0)
            VIR_WARN("Unable to release lock on %s", elem->path);
    } else {
        if (virDomainLockImageAttach(driver->lockManager, cfg->uri,
                                     vm, elem) < 0)
            goto cleanup;

        if (qemuSetImageCgroup(vm, elem, false) < 0)
            goto cleanup;

        if (virSecurityManagerSetImageLabel(driver->securityManager,
                                            vm->def, elem) < 0)
            goto cleanup;
12426 12427 12428 12429
    }

    ret = 0;

12430
 cleanup:
12431
    elem->readonly = readonly;
12432
    virObjectUnref(cfg);
12433 12434 12435 12436
    return ret;
}


12437 12438 12439
/* Return -1 if request is not sent to agent due to misconfig, -2 if request
 * is sent but failed, and number of frozen filesystems on success. If -2 is
 * returned, FSThaw should be called revert the quiesced status. */
12440
static int
12441
qemuDomainSnapshotFSFreeze(virQEMUDriverPtr driver,
12442 12443 12444
                           virDomainObjPtr vm,
                           const char **mountpoints,
                           unsigned int nmountpoints)
12445
{
12446
    qemuDomainObjPrivatePtr priv = vm->privateData;
12447
    virQEMUDriverConfigPtr cfg;
12448
    int frozen;
12449

12450 12451 12452 12453 12454 12455
    if (priv->quiesced) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is already quiesced"));
        return -1;
    }

12456
    if (!qemuDomainAgentAvailable(priv, true))
12457 12458
        return -1;

12459 12460 12461 12462 12463 12464 12465 12466 12467 12468
    priv->quiesced = true;

    cfg = virQEMUDriverGetConfig(driver);
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
        priv->quiesced = false;
        virObjectUnref(cfg);
        return -1;
    }
    virObjectUnref(cfg);

12469
    qemuDomainObjEnterAgent(vm);
12470
    frozen = qemuAgentFSFreeze(priv->agent, mountpoints, nmountpoints);
12471
    qemuDomainObjExitAgent(vm);
12472
    return frozen < 0 ? -2 : frozen;
12473 12474
}

12475

12476
/* Return -1 on error, otherwise number of thawed filesystems. */
12477
static int
12478 12479 12480
qemuDomainSnapshotFSThaw(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         bool report)
E
Eric Blake 已提交
12481
{
12482
    qemuDomainObjPrivatePtr priv = vm->privateData;
12483
    virQEMUDriverConfigPtr cfg;
12484
    int thawed;
E
Eric Blake 已提交
12485
    virErrorPtr err = NULL;
12486

12487
    if (!qemuDomainAgentAvailable(priv, report))
12488 12489
        return -1;

12490 12491 12492 12493 12494 12495
    if (!priv->quiesced && report) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not quiesced"));
        return -1;
    }

12496
    qemuDomainObjEnterAgent(vm);
E
Eric Blake 已提交
12497
    if (!report)
12498
        err = virSaveLastError();
12499
    thawed = qemuAgentFSThaw(priv->agent);
12500 12501
    if (!report)
        virSetError(err);
12502
    qemuDomainObjExitAgent(vm);
12503

12504
    virFreeError(err);
12505 12506 12507 12508 12509 12510 12511 12512 12513 12514 12515 12516 12517

    if (!report || thawed >= 0) {
        priv->quiesced = false;

        cfg = virQEMUDriverGetConfig(driver);
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
            /* Revert the statuses when we failed to save them. */
            priv->quiesced = true;
            thawed = -1;
        }
        virObjectUnref(cfg);
    }

12518 12519 12520
    return thawed;
}

12521

12522 12523
/* The domain is expected to be locked and inactive. */
static int
12524
qemuDomainSnapshotCreateInactiveInternal(virQEMUDriverPtr driver,
12525 12526
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap)
12527
{
E
Eric Blake 已提交
12528
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
12529 12530
}

12531

12532 12533
/* The domain is expected to be locked and inactive. */
static int
12534
qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
12535 12536 12537 12538
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap,
                                         bool reuse)
{
12539
    size_t i;
12540 12541 12542 12543
    virDomainSnapshotDiskDefPtr snapdisk;
    virDomainDiskDefPtr defdisk;
    virCommandPtr cmd = NULL;
    const char *qemuImgPath;
12544 12545
    virBitmapPtr created = NULL;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
12546 12547 12548
    int ret = -1;

    if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
12549
        goto cleanup;
12550

12551
    if (!(created = virBitmapNew(snap->def->ndisks)))
12552
        goto cleanup;
12553 12554 12555 12556 12557 12558 12559 12560 12561 12562

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

12563 12564
        if (!snapdisk->src->format)
            snapdisk->src->format = VIR_STORAGE_FILE_QCOW2;
12565 12566 12567 12568 12569

        /* creates cmd line args: qemu-img create -f qcow2 -o */
        if (!(cmd = virCommandNewArgList(qemuImgPath,
                                         "create",
                                         "-f",
12570
                                         virStorageFileFormatTypeToString(snapdisk->src->format),
12571 12572 12573 12574
                                         "-o",
                                         NULL)))
            goto cleanup;

12575
        if (defdisk->src->format > 0) {
12576 12577
            /* adds cmd line arg: backing_file=/path/to/backing/file,backing_fmd=format */
            virCommandAddArgFormat(cmd, "backing_file=%s,backing_fmt=%s",
12578 12579
                                   defdisk->src->path,
                                   virStorageFileFormatTypeToString(defdisk->src->format));
12580
        } else {
12581
            if (!cfg->allowDiskFormatProbing) {
12582 12583 12584
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown image format of '%s' and "
                                 "format probing is disabled"),
12585
                               defdisk->src->path);
12586 12587 12588 12589
                goto cleanup;
            }

            /* adds cmd line arg: backing_file=/path/to/backing/file */
12590
            virCommandAddArgFormat(cmd, "backing_file=%s", defdisk->src->path);
12591 12592 12593
        }

        /* adds cmd line args: /path/to/target/file */
12594
        virCommandAddArg(cmd, snapdisk->src->path);
12595 12596

        /* If the target does not exist, we're going to create it possibly */
12597
        if (!virFileExists(snapdisk->src->path))
12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610 12611 12612
            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) {
12613 12614
            VIR_FREE(defdisk->src->path);
            if (VIR_STRDUP(defdisk->src->path, snapdisk->src->path) < 0) {
12615 12616 12617
                /* we cannot rollback here in a sane way */
                goto cleanup;
            }
12618
            defdisk->src->format = snapdisk->src->format;
12619 12620 12621 12622 12623
        }
    }

    ret = 0;

12624
 cleanup:
12625 12626 12627
    virCommandFree(cmd);

    /* unlink images if creation has failed */
12628
    if (ret < 0 && created) {
12629 12630 12631
        ssize_t bit = -1;
        while ((bit = virBitmapNextSetBit(created, bit)) >= 0) {
            snapdisk = &(snap->def->disks[bit]);
12632
            if (unlink(snapdisk->src->path) < 0)
12633
                VIR_WARN("Failed to remove snapshot image '%s'",
12634
                         snapdisk->src->path);
12635 12636 12637
        }
    }
    virBitmapFree(created);
12638
    virObjectUnref(cfg);
12639 12640 12641 12642

    return ret;
}

12643

12644 12645
/* The domain is expected to be locked and active. */
static int
12646
qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
12647
                                       virQEMUDriverPtr driver,
12648
                                       virDomainObjPtr vm,
12649 12650
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
12651 12652
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
12653
    virObjectEventPtr event = NULL;
12654 12655
    bool resume = false;
    int ret = -1;
12656

J
Jiri Denemark 已提交
12657
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
12658 12659 12660 12661
        /* 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.
         */
12662
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
12663
                                QEMU_ASYNC_JOB_SNAPSHOT) < 0)
12664 12665 12666 12667
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
12668 12669
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
12670 12671 12672 12673
            goto cleanup;
        }
    }

12674 12675 12676 12677 12678 12679
    if (qemuDomainObjEnterMonitorAsync(driver, vm,
                                       QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
        resume = false;
        goto cleanup;
    }

12680
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
12681
    qemuDomainObjExitMonitor(driver, vm);
12682 12683 12684 12685
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
12686
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
12687
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
12688
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12689 12690 12691
        virDomainAuditStop(vm, "from-snapshot");
        resume = false;
    }
12692

12693
 cleanup:
12694
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
12695
        qemuProcessStartCPUs(driver, vm, conn,
12696
                             VIR_DOMAIN_RUNNING_UNPAUSED,
12697
                             QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
12698
        event = virDomainEventLifecycleNewFromObj(vm,
12699 12700 12701 12702 12703 12704
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after snapshot failed"));
        }
12705 12706
    }

12707 12708 12709
    if (event)
        qemuDomainEventQueue(driver, event);

12710 12711 12712
    return ret;
}

12713

12714
static int
12715
qemuDomainSnapshotPrepareDiskExternalBackingInactive(virDomainDiskDefPtr disk)
12716
{
12717
    int actualType = virStorageSourceGetActualType(disk->src);
12718

12719
    switch ((virStorageType) actualType) {
E
Eric Blake 已提交
12720 12721
    case VIR_STORAGE_TYPE_BLOCK:
    case VIR_STORAGE_TYPE_FILE:
12722 12723
        return 0;

E
Eric Blake 已提交
12724
    case VIR_STORAGE_TYPE_NETWORK:
12725
        switch ((virStorageNetProtocol) disk->src->protocol) {
12726
        case VIR_STORAGE_NET_PROTOCOL_NONE:
12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737
        case VIR_STORAGE_NET_PROTOCOL_NBD:
        case VIR_STORAGE_NET_PROTOCOL_RBD:
        case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
        case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
        case VIR_STORAGE_NET_PROTOCOL_ISCSI:
        case VIR_STORAGE_NET_PROTOCOL_HTTP:
        case VIR_STORAGE_NET_PROTOCOL_HTTPS:
        case VIR_STORAGE_NET_PROTOCOL_FTP:
        case VIR_STORAGE_NET_PROTOCOL_FTPS:
        case VIR_STORAGE_NET_PROTOCOL_TFTP:
        case VIR_STORAGE_NET_PROTOCOL_LAST:
12738 12739 12740
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("external inactive snapshots are not supported on "
                             "'network' disks using '%s' protocol"),
12741
                           virStorageNetProtocolTypeToString(disk->src->protocol));
12742 12743 12744 12745
            return -1;
        }
        break;

E
Eric Blake 已提交
12746 12747
    case VIR_STORAGE_TYPE_DIR:
    case VIR_STORAGE_TYPE_VOLUME:
12748
    case VIR_STORAGE_TYPE_NONE:
E
Eric Blake 已提交
12749
    case VIR_STORAGE_TYPE_LAST:
12750 12751
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("external inactive snapshots are not supported on "
E
Eric Blake 已提交
12752
                         "'%s' disks"), virStorageTypeToString(actualType));
12753 12754 12755 12756 12757 12758 12759
        return -1;
    }

    return 0;
}


12760 12761 12762
static int
qemuDomainSnapshotPrepareDiskExternalBackingActive(virDomainDiskDefPtr disk)
{
12763
    if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
12764 12765 12766 12767 12768 12769 12770 12771 12772 12773
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("external active snapshots are not supported on scsi "
                         "passthrough devices"));
        return -1;
    }

    return 0;
}


12774 12775 12776
static int
qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr disk)
{
12777
    int actualType = virStorageSourceGetActualType(disk->src);
12778

12779
    switch ((virStorageType) actualType) {
E
Eric Blake 已提交
12780 12781
    case VIR_STORAGE_TYPE_BLOCK:
    case VIR_STORAGE_TYPE_FILE:
12782 12783
        return 0;

E
Eric Blake 已提交
12784
    case VIR_STORAGE_TYPE_NETWORK:
12785
        switch ((virStorageNetProtocol) disk->src->protocol) {
12786
        case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
12787 12788
            return 0;

12789
        case VIR_STORAGE_NET_PROTOCOL_NONE:
12790 12791 12792 12793 12794 12795 12796 12797 12798 12799
        case VIR_STORAGE_NET_PROTOCOL_NBD:
        case VIR_STORAGE_NET_PROTOCOL_RBD:
        case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
        case VIR_STORAGE_NET_PROTOCOL_ISCSI:
        case VIR_STORAGE_NET_PROTOCOL_HTTP:
        case VIR_STORAGE_NET_PROTOCOL_HTTPS:
        case VIR_STORAGE_NET_PROTOCOL_FTP:
        case VIR_STORAGE_NET_PROTOCOL_FTPS:
        case VIR_STORAGE_NET_PROTOCOL_TFTP:
        case VIR_STORAGE_NET_PROTOCOL_LAST:
12800 12801 12802
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("external active snapshots are not supported on "
                             "'network' disks using '%s' protocol"),
12803
                           virStorageNetProtocolTypeToString(disk->src->protocol));
12804 12805 12806 12807 12808
            return -1;

        }
        break;

E
Eric Blake 已提交
12809 12810
    case VIR_STORAGE_TYPE_DIR:
    case VIR_STORAGE_TYPE_VOLUME:
12811
    case VIR_STORAGE_TYPE_NONE:
E
Eric Blake 已提交
12812
    case VIR_STORAGE_TYPE_LAST:
12813 12814
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("external active snapshots are not supported on "
E
Eric Blake 已提交
12815
                         "'%s' disks"), virStorageTypeToString(actualType));
12816 12817 12818 12819 12820 12821 12822 12823 12824 12825
        return -1;
    }

    return 0;
}


static int
qemuDomainSnapshotPrepareDiskExternalOverlayInactive(virDomainSnapshotDiskDefPtr disk)
{
12826
    int actualType = virStorageSourceGetActualType(disk->src);
12827

12828
    switch ((virStorageType) actualType) {
E
Eric Blake 已提交
12829 12830
    case VIR_STORAGE_TYPE_BLOCK:
    case VIR_STORAGE_TYPE_FILE:
12831 12832
        return 0;

E
Eric Blake 已提交
12833 12834 12835
    case VIR_STORAGE_TYPE_NETWORK:
    case VIR_STORAGE_TYPE_DIR:
    case VIR_STORAGE_TYPE_VOLUME:
12836
    case VIR_STORAGE_TYPE_NONE:
E
Eric Blake 已提交
12837
    case VIR_STORAGE_TYPE_LAST:
12838 12839
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("external inactive snapshots are not supported on "
E
Eric Blake 已提交
12840
                         "'%s' disks"), virStorageTypeToString(actualType));
12841 12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 12852 12853 12854
        return -1;
    }

    return 0;
}


static int
qemuDomainSnapshotPrepareDiskExternal(virConnectPtr conn,
                                      virDomainDiskDefPtr disk,
                                      virDomainSnapshotDiskDefPtr snapdisk,
                                      bool active,
                                      bool reuse)
{
12855
    int ret = -1;
12856 12857 12858 12859 12860 12861
    struct stat st;

    if (qemuTranslateSnapshotDiskSourcePool(conn, snapdisk) < 0)
        return -1;

    if (!active) {
12862
        if (virStorageTranslateDiskSourcePool(conn, disk) < 0)
12863 12864
            return -1;

12865
        if (qemuDomainSnapshotPrepareDiskExternalBackingInactive(disk) < 0)
12866 12867 12868 12869 12870
            return -1;

        if (qemuDomainSnapshotPrepareDiskExternalOverlayInactive(snapdisk) < 0)
            return -1;
    } else {
12871 12872 12873
        if (qemuDomainSnapshotPrepareDiskExternalBackingActive(disk) < 0)
            return -1;

12874 12875 12876 12877
        if (qemuDomainSnapshotPrepareDiskExternalOverlayActive(snapdisk) < 0)
            return -1;
    }

12878
    if (virStorageFileInit(snapdisk->src) < 0)
12879
        return -1;
12880

12881
    if (virStorageFileStat(snapdisk->src, &st) < 0) {
12882 12883 12884
        if (errno != ENOENT) {
            virReportSystemError(errno,
                                 _("unable to stat for disk %s: %s"),
12885
                                 snapdisk->name, snapdisk->src->path);
12886 12887 12888 12889
            goto cleanup;
        } else if (reuse) {
            virReportSystemError(errno,
                                 _("missing existing file for disk %s: %s"),
12890
                                 snapdisk->name, snapdisk->src->path);
12891
            goto cleanup;
12892
        }
12893 12894 12895 12896
    } 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"),
12897
                       snapdisk->name, snapdisk->src->path);
12898
        goto cleanup;
12899 12900
    }

12901 12902
    ret = 0;

12903
 cleanup:
12904
    virStorageFileDeinit(snapdisk->src);
12905
    return ret;
12906 12907 12908 12909 12910 12911 12912 12913 12914 12915
}


static int
qemuDomainSnapshotPrepareDiskInternal(virConnectPtr conn,
                                      virDomainDiskDefPtr disk,
                                      bool active)
{
    int actualType;

N
Nehal J Wani 已提交
12916
    /* active disks are handled by qemu itself so no need to worry about those */
12917 12918 12919
    if (active)
        return 0;

12920
    if (virStorageTranslateDiskSourcePool(conn, disk) < 0)
12921 12922
        return -1;

12923
    actualType = virStorageSourceGetActualType(disk->src);
12924

12925
    switch ((virStorageType) actualType) {
E
Eric Blake 已提交
12926 12927
    case VIR_STORAGE_TYPE_BLOCK:
    case VIR_STORAGE_TYPE_FILE:
12928 12929
        return 0;

E
Eric Blake 已提交
12930
    case VIR_STORAGE_TYPE_NETWORK:
12931
        switch ((virStorageNetProtocol) disk->src->protocol) {
12932
        case VIR_STORAGE_NET_PROTOCOL_NONE:
12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 12943
        case VIR_STORAGE_NET_PROTOCOL_NBD:
        case VIR_STORAGE_NET_PROTOCOL_RBD:
        case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
        case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
        case VIR_STORAGE_NET_PROTOCOL_ISCSI:
        case VIR_STORAGE_NET_PROTOCOL_HTTP:
        case VIR_STORAGE_NET_PROTOCOL_HTTPS:
        case VIR_STORAGE_NET_PROTOCOL_FTP:
        case VIR_STORAGE_NET_PROTOCOL_FTPS:
        case VIR_STORAGE_NET_PROTOCOL_TFTP:
        case VIR_STORAGE_NET_PROTOCOL_LAST:
12944 12945 12946
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("internal inactive snapshots are not supported on "
                             "'network' disks using '%s' protocol"),
12947
                           virStorageNetProtocolTypeToString(disk->src->protocol));
12948 12949 12950 12951
            return -1;
        }
        break;

E
Eric Blake 已提交
12952 12953
    case VIR_STORAGE_TYPE_DIR:
    case VIR_STORAGE_TYPE_VOLUME:
12954
    case VIR_STORAGE_TYPE_NONE:
E
Eric Blake 已提交
12955
    case VIR_STORAGE_TYPE_LAST:
12956 12957
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("internal inactive snapshots are not supported on "
E
Eric Blake 已提交
12958
                         "'%s' disks"), virStorageTypeToString(actualType));
12959 12960 12961 12962 12963 12964 12965 12966 12967 12968 12969
        return -1;
    }

    return 0;
}


static int
qemuDomainSnapshotPrepare(virConnectPtr conn,
                          virDomainObjPtr vm,
                          virDomainSnapshotDefPtr def,
E
Eric Blake 已提交
12970
                          unsigned int *flags)
12971 12972
{
    int ret = -1;
12973
    size_t i;
12974
    bool active = virDomainObjIsActive(vm);
12975
    bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
12976
    bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
12977
    bool found_internal = false;
12978
    bool forbid_internal = false;
12979 12980
    int external = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
12981

E
Eric Blake 已提交
12982
    if (def->state == VIR_DOMAIN_DISK_SNAPSHOT &&
12983
        reuse && !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
12984 12985
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("reuse is not supported with this QEMU binary"));
12986 12987 12988
        goto cleanup;
    }

12989 12990
    for (i = 0; i < def->ndisks; i++) {
        virDomainSnapshotDiskDefPtr disk = &def->disks[i];
E
Eric Blake 已提交
12991
        virDomainDiskDefPtr dom_disk = vm->def->disks[i];
12992

12993
        switch ((virDomainSnapshotLocation) disk->snapshot) {
E
Eric Blake 已提交
12994
        case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
12995 12996
            found_internal = true;

12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008
            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;

13009 13010 13011
            if (dom_disk->src->type == VIR_STORAGE_TYPE_NETWORK &&
                (dom_disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_SHEEPDOG ||
                 dom_disk->src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)) {
E
Eric Blake 已提交
13012
                break;
13013
            }
13014 13015
            if (vm->def->disks[i]->src->format > 0 &&
                vm->def->disks[i]->src->format != VIR_STORAGE_FILE_QCOW2) {
13016 13017 13018 13019
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("internal snapshot for disk %s unsupported "
                                 "for storage type %s"),
                               disk->name,
13020
                               virStorageFileFormatTypeToString(
13021
                                   vm->def->disks[i]->src->format));
13022 13023 13024 13025
                goto cleanup;
            }
            break;

E
Eric Blake 已提交
13026
        case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
13027 13028 13029 13030
            if (!disk->src->format) {
                disk->src->format = VIR_STORAGE_FILE_QCOW2;
            } else if (disk->src->format != VIR_STORAGE_FILE_QCOW2 &&
                       disk->src->format != VIR_STORAGE_FILE_QED) {
13031 13032 13033
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot format for disk %s "
                                 "is unsupported: %s"),
13034
                               disk->name,
13035
                               virStorageFileFormatTypeToString(disk->src->format));
13036 13037
                goto cleanup;
            }
13038 13039 13040

            if (qemuDomainSnapshotPrepareDiskExternal(conn, dom_disk, disk,
                                                      active, reuse) < 0)
13041
                goto cleanup;
13042

13043
            external++;
13044 13045
            break;

E
Eric Blake 已提交
13046
        case VIR_DOMAIN_SNAPSHOT_LOCATION_NONE:
13047
            /* Remember seeing a disk that has snapshot disabled */
13048
            if (!dom_disk->src->readonly)
13049
                forbid_internal = true;
13050 13051
            break;

E
Eric Blake 已提交
13052
        case VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT:
13053
        case VIR_DOMAIN_SNAPSHOT_LOCATION_LAST:
13054 13055
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unexpected code path"));
13056 13057 13058 13059
            goto cleanup;
        }
    }

13060 13061 13062 13063 13064 13065 13066
    if (!found_internal && !external &&
        def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("nothing selected for snapshot"));
        goto cleanup;
    }

13067 13068 13069 13070
    /* internal snapshot requires a disk image to store the memory image to, and
     * also disks can't be excluded from an internal snapshot*/
    if ((def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL && !found_internal) ||
        (found_internal && forbid_internal)) {
13071
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
13072 13073
                       _("internal snapshots and checkpoints require all "
                         "disks to be selected for snapshot"));
13074 13075
        goto cleanup;
    }
13076

13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087
    /* 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 */
13088 13089 13090
    if ((found_internal && external) ||
         (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL && external) ||
         (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL && found_internal)) {
13091
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
13092 13093
                       _("mixing internal and external targets for a snapshot "
                         "is not yet supported"));
13094 13095 13096 13097 13098 13099 13100
        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 已提交
13101
    if (def->state != VIR_DOMAIN_DISK_SNAPSHOT && active) {
13102
        if (external == 1 ||
13103
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
13104 13105
            *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC;
        } else if (atomic && external > 1) {
13106 13107 13108
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("atomic live snapshot of multiple disks "
                             "is unsupported"));
13109 13110 13111
            goto cleanup;
        }
    }
13112 13113 13114

    ret = 0;

13115
 cleanup:
13116 13117 13118
    return ret;
}

13119

13120 13121
/* The domain is expected to hold monitor lock.  */
static int
13122
qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
13123
                                         virDomainObjPtr vm,
13124
                                         virDomainSnapshotDiskDefPtr snap,
13125
                                         virDomainDiskDefPtr disk,
13126
                                         virDomainDiskDefPtr persistDisk,
13127
                                         virJSONValuePtr actions,
13128
                                         bool reuse,
13129
                                         qemuDomainAsyncJob asyncJob)
13130 13131
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
13132 13133
    virStorageSourcePtr newDiskSrc = NULL;
    virStorageSourcePtr persistDiskSrc = NULL;
13134 13135
    char *device = NULL;
    char *source = NULL;
13136
    const char *formatStr = NULL;
13137
    int ret = -1;
13138
    bool need_unlink = false;
13139

E
Eric Blake 已提交
13140
    if (snap->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
13141 13142
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected code path"));
13143 13144 13145
        return -1;
    }

13146
    if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0)
13147 13148
        goto cleanup;

13149
    if (!(newDiskSrc = virStorageSourceCopy(snap->src, false)))
13150 13151
        goto cleanup;

13152
    if (virStorageSourceInitChainElement(newDiskSrc, disk->src, false) < 0)
13153 13154
        goto cleanup;

13155
    if (qemuDomainStorageFileInit(driver, vm, newDiskSrc) < 0)
13156 13157
        goto cleanup;

13158
    if (qemuGetDriveSourceString(newDiskSrc, NULL, &source) < 0)
13159 13160
        goto cleanup;

13161 13162 13163 13164 13165 13166 13167 13168 13169
    if (persistDisk) {
        if (!(persistDiskSrc = virStorageSourceCopy(snap->src, false)))
            goto cleanup;

        if (virStorageSourceInitChainElement(persistDiskSrc, persistDisk->src,
                                             false) < 0)
            goto cleanup;
    }

13170
    /* pre-create the image file so that we can label it before handing it to qemu */
13171 13172 13173 13174 13175
    if (!reuse && newDiskSrc->type != VIR_STORAGE_TYPE_BLOCK) {
        if (virStorageFileCreate(newDiskSrc) < 0) {
            virReportSystemError(errno, _("failed to create image file '%s'"),
                                 source);
            goto cleanup;
13176
        }
13177
        need_unlink = true;
13178
    }
13179

13180 13181 13182 13183 13184
    /* set correct security, cgroup and locking options on the new image */
    if (qemuDomainPrepareDiskChainElement(driver, vm, newDiskSrc,
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
        qemuDomainPrepareDiskChainElement(driver, vm, newDiskSrc,
                                          VIR_DISK_CHAIN_NO_ACCESS);
13185 13186 13187 13188
        goto cleanup;
    }

    /* create the actual snapshot */
13189 13190
    if (newDiskSrc->format)
        formatStr = virStorageFileFormatTypeToString(newDiskSrc->format);
13191 13192 13193 13194 13195 13196 13197 13198

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

13199
    ret = qemuMonitorDiskSnapshot(priv->mon, actions, device, source,
13200
                                  formatStr, reuse);
13201 13202 13203 13204 13205 13206 13207 13208 13209
    if (!actions) {
        qemuDomainObjExitMonitor(driver, vm);
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("domain crashed while taking the snapshot"));
            ret = -1;
        }
    }

13210
    virDomainAuditDisk(vm, disk->src, snap->src, "snapshot", ret >= 0);
13211 13212 13213 13214
    if (ret < 0)
        goto cleanup;

    /* Update vm in place to match changes.  */
13215
    need_unlink = false;
13216

13217 13218 13219
    newDiskSrc->backingStore = disk->src;
    disk->src = newDiskSrc;
    newDiskSrc = NULL;
13220

13221
    if (persistDisk) {
13222 13223 13224
        persistDiskSrc->backingStore = persistDisk->src;
        persistDisk->src = persistDiskSrc;
        persistDiskSrc = NULL;
13225
    }
13226

13227
 cleanup:
13228
    if (need_unlink && virStorageFileUnlink(newDiskSrc))
13229
        VIR_WARN("unable to unlink just-created %s", source);
13230
    virStorageFileDeinit(newDiskSrc);
13231 13232
    virStorageSourceFree(newDiskSrc);
    virStorageSourceFree(persistDiskSrc);
13233 13234 13235 13236 13237
    VIR_FREE(device);
    VIR_FREE(source);
    return ret;
}

13238

13239 13240 13241 13242
/* The domain is expected to hold monitor lock.  This is the
 * counterpart to qemuDomainSnapshotCreateSingleDiskActive, called
 * only on a failed transaction. */
static void
13243
qemuDomainSnapshotUndoSingleDiskActive(virQEMUDriverPtr driver,
13244 13245 13246 13247 13248
                                       virDomainObjPtr vm,
                                       virDomainDiskDefPtr disk,
                                       virDomainDiskDefPtr persistDisk,
                                       bool need_unlink)
{
13249
    virStorageSourcePtr tmp;
13250 13251
    struct stat st;

13252
    ignore_value(virStorageFileInit(disk->src));
13253

13254
    qemuDomainPrepareDiskChainElement(driver, vm, disk->src,
13255
                                      VIR_DISK_CHAIN_NO_ACCESS);
13256
    if (need_unlink &&
13257 13258 13259
        virStorageFileStat(disk->src, &st) == 0 && S_ISREG(st.st_mode) &&
        virStorageFileUnlink(disk->src) < 0)
        VIR_WARN("Unable to remove just-created %s", disk->src->path);
13260

13261 13262 13263 13264 13265 13266 13267 13268
    virStorageFileDeinit(disk->src);

    /* Update vm in place to match changes. */
    tmp = disk->src;
    disk->src = tmp->backingStore;
    tmp->backingStore = NULL;
    virStorageSourceFree(tmp);

13269
    if (persistDisk) {
13270 13271 13272 13273
        tmp = persistDisk->src;
        persistDisk->src = tmp->backingStore;
        tmp->backingStore = NULL;
        virStorageSourceFree(tmp);
13274 13275 13276
    }
}

13277

13278 13279
/* The domain is expected to be locked and active. */
static int
13280
qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
13281
                                   virDomainObjPtr vm,
13282
                                   virDomainSnapshotObjPtr snap,
13283
                                   unsigned int flags,
13284
                                   qemuDomainAsyncJob asyncJob)
13285
{
13286 13287
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virJSONValuePtr actions = NULL;
13288
    int ret = 0;
13289
    size_t i;
13290
    bool persist = false;
13291
    bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
13292
    virQEMUDriverConfigPtr cfg = NULL;
13293
    virErrorPtr orig_err = NULL;
13294

13295
    if (!virDomainObjIsActive(vm)) {
13296 13297
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
13298
        return -1;
13299 13300
    }

13301
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
13302
        if (!(actions = virJSONValueNewArray()))
13303
            return -1;
13304
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DISK_SNAPSHOT)) {
13305 13306 13307
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live disk snapshot not supported with this "
                         "QEMU binary"));
13308
        return -1;
13309
    }
13310

13311 13312
    cfg = virQEMUDriverGetConfig(driver);

13313
    /* No way to roll back if first disk succeeds but later disks
13314
     * fail, unless we have transaction support.
E
Eric Blake 已提交
13315
     * Based on earlier qemuDomainSnapshotPrepare, all
13316 13317 13318
     * 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++) {
13319 13320
        virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
13321
        if (snap->def->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
13322
            continue;
13323 13324 13325 13326
        if (vm->newDef) {
            int indx = virDomainDiskIndexByName(vm->newDef,
                                                vm->def->disks[i]->dst,
                                                false);
13327
            if (indx >= 0) {
13328
                persistDisk = vm->newDef->disks[indx];
13329 13330
                persist = true;
            }
13331
        }
13332

13333
        ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm,
13334
                                                       &snap->def->disks[i],
13335
                                                       vm->def->disks[i],
13336
                                                       persistDisk, actions,
13337
                                                       reuse, asyncJob);
13338 13339 13340
        if (ret < 0)
            break;
    }
13341
    if (actions) {
13342 13343 13344 13345 13346 13347 13348 13349 13350 13351 13352 13353 13354 13355 13356
        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 已提交
13357
        virJSONValueFree(actions);
13358

13359 13360 13361
        if (ret < 0) {
            /* Transaction failed; undo the changes to vm.  */
            bool need_unlink = !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);
13362
            while (i-- > 0) {
13363 13364
                virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
13365 13366
                if (snap->def->disks[i].snapshot ==
                    VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
13367 13368 13369 13370 13371
                    continue;
                if (vm->newDef) {
                    int indx = virDomainDiskIndexByName(vm->newDef,
                                                        vm->def->disks[i]->dst,
                                                        false);
13372
                    if (indx >= 0) {
13373
                        persistDisk = vm->newDef->disks[indx];
13374 13375
                        persist = true;
                    }
13376 13377
                }

13378
                qemuDomainSnapshotUndoSingleDiskActive(driver, vm,
13379 13380 13381 13382 13383 13384
                                                       vm->def->disks[i],
                                                       persistDisk,
                                                       need_unlink);
            }
        }
    }
13385

13386 13387 13388 13389 13390
    /* recheck backing chains of all disks involved in the snapshot */
    orig_err = virSaveLastError();
    for (i = 0; i < snap->def->ndisks; i++) {
        if (snap->def->disks[i].snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
            continue;
13391 13392
        ignore_value(qemuDomainDetermineDiskChain(driver, vm, vm->def->disks[i],
                                                  true, true));
13393 13394 13395 13396 13397
    }
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
13398

13399
    if (ret == 0 || !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
13400
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0 ||
13401
            (persist && virDomainSaveConfig(cfg->configDir, vm->newDef) < 0))
13402 13403
            ret = -1;
    }
13404
    virObjectUnref(cfg);
13405 13406 13407 13408 13409 13410 13411

    return ret;
}


static int
qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
13412
                                       virQEMUDriverPtr driver,
13413
                                       virDomainObjPtr vm,
13414 13415 13416
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
{
13417
    virObjectEventPtr event;
13418 13419 13420 13421 13422
    bool resume = false;
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *xml = NULL;
    bool memory = snap->def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
13423
    bool memory_unlink = false;
13424
    bool atomic = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC);
13425
    bool transaction = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION);
13426
    int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
13427
    bool pmsuspended = false;
13428 13429
    virQEMUDriverConfigPtr cfg = NULL;
    int compressed = QEMU_SAVE_FORMAT_RAW;
13430 13431

    /* If quiesce was requested, then issue a freeze command, and a
13432 13433 13434
     * counterpart thaw command when it is actually sent to agent.
     * The command will fail if the guest is paused or the guest agent
     * is not running, or is already quiesced.  */
13435
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) {
13436
        int freeze = qemuDomainSnapshotFSFreeze(driver, vm, NULL, 0);
13437 13438 13439 13440
        if (freeze < 0) {
            /* the helper reported the error */
            if (freeze == -2)
                thaw = -1; /* the command is sent but agent failed */
13441
            goto cleanup;
13442
        }
13443
        thaw = 1;
13444 13445
    }

13446 13447 13448 13449 13450
    /* 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) {
13451 13452 13453 13454 13455 13456 13457 13458 13459 13460 13461 13462 13463 13464 13465 13466 13467
        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)
13468
                goto cleanup;
13469 13470 13471 13472

            if (!virDomainObjIsActive(vm)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
13473
                goto cleanup;
13474 13475 13476 13477 13478 13479
            }
        }
    }

    /* do the memory snapshot if necessary */
    if (memory) {
13480
        /* check if migration is possible */
13481
        if (!qemuMigrationIsAllowed(driver, vm, vm->def, false, false))
13482
            goto cleanup;
13483

13484
        /* allow the migration job to be cancelled or the domain to be paused */
13485 13486 13487
        qemuDomainObjSetAsyncJobMask(vm, (QEMU_JOB_DEFAULT_MASK |
                                          JOB_MASK(QEMU_JOB_SUSPEND) |
                                          JOB_MASK(QEMU_JOB_MIGRATION_OP)));
13488

13489 13490 13491 13492 13493 13494 13495
        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"));
13496
                goto cleanup;
13497
            }
13498

13499 13500 13501 13502
            if (!qemuCompressProgramAvailable(compressed)) {
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("Compression program for image format "
                                 "in configuration file isn't available"));
13503
                goto cleanup;
13504 13505 13506
            }
        }

13507
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)))
13508
            goto cleanup;
13509 13510

        if ((ret = qemuDomainSaveMemory(driver, vm, snap->def->file,
13511
                                        xml, compressed, resume, 0,
13512
                                        QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
13513
            goto cleanup;
13514

13515 13516 13517
        /* the memory image was created, remove it on errors */
        memory_unlink = true;

13518
        /* forbid any further manipulation */
13519
        qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_DEFAULT_MASK);
13520 13521 13522 13523 13524 13525 13526 13527 13528 13529 13530
    }

    /* 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)
13531
        goto cleanup;
13532 13533

    /* the snapshot is complete now */
13534
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
13535
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
13536
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
13537
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
13538 13539
        virDomainAuditStop(vm, "from-snapshot");
        resume = false;
E
Eric Blake 已提交
13540
        thaw = 0;
13541 13542
        if (event)
            qemuDomainEventQueue(driver, event);
13543 13544 13545 13546 13547 13548
    } 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.  */
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                             VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
13549
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
13550 13551 13552
                                         VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
        if (event)
            qemuDomainEventQueue(driver, event);
13553 13554
    }

13555
    ret = 0;
13556

13557 13558
 cleanup:
    if (resume && virDomainObjIsActive(vm) &&
13559 13560
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
13561
                             QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
13562
        event = virDomainEventLifecycleNewFromObj(vm,
13563 13564 13565 13566 13567 13568 13569 13570
                                         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"));
        }
13571

13572 13573
        ret = -1;
        goto cleanup;
13574
    }
13575 13576

    if (thaw != 0 &&
13577
        qemuDomainSnapshotFSThaw(driver, vm, thaw > 0) < 0) {
E
Eric Blake 已提交
13578 13579 13580 13581
        /* helper reported the error, if it was needed */
        if (thaw > 0)
            ret = -1;
    }
13582

13583
    VIR_FREE(xml);
13584
    virObjectUnref(cfg);
13585 13586
    if (memory_unlink && ret < 0)
        unlink(snap->def->file);
13587

13588 13589 13590
    return ret;
}

13591

13592 13593 13594 13595
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
                            const char *xmlDesc,
                            unsigned int flags)
C
Chris Lalancette 已提交
13596
{
13597
    virConnectPtr conn = domain->conn;
13598
    virQEMUDriverPtr driver = domain->conn->privateData;
C
Chris Lalancette 已提交
13599
    virDomainObjPtr vm = NULL;
13600
    char *xml = NULL;
C
Chris Lalancette 已提交
13601 13602
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
13603
    virDomainSnapshotDefPtr def = NULL;
13604
    bool update_current = true;
13605
    bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
13606
    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
13607
    virDomainSnapshotObjPtr other = NULL;
13608 13609
    int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
    int align_match = true;
13610
    virQEMUDriverConfigPtr cfg = NULL;
13611
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
13612

13613 13614
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
13615
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
13616
                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
13617
                  VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
13618
                  VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
13619
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
13620 13621
                  VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
                  VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
13622 13623 13624

    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
        !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
13625 13626
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("quiesce requires disk-only"));
13627 13628
        return NULL;
    }
13629

13630
    if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
13631 13632
        (flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA))
        update_current = false;
13633
    if (redefine)
13634
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
13635

13636
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13637 13638
        goto cleanup;

13639 13640
    cfg = virQEMUDriverGetConfig(driver);

13641
    if (virDomainSnapshotCreateXMLEnsureACL(domain->conn, vm->def, flags) < 0)
13642 13643
        goto cleanup;

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

13647
    if (qemuProcessAutoDestroyActive(driver, vm)) {
13648 13649
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is marked for auto destroy"));
13650 13651
        goto cleanup;
    }
E
Eric Blake 已提交
13652 13653
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
13654
                       _("domain has active block job"));
E
Eric Blake 已提交
13655 13656 13657
        goto cleanup;
    }

13658
    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
13659 13660
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot halt after transient domain snapshot"));
13661 13662
        goto cleanup;
    }
13663 13664 13665
    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) ||
        !virDomainObjIsActive(vm))
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE;
13666

13667
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, caps, driver->xmlopt,
13668 13669
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
13670 13671
        goto cleanup;

13672 13673 13674 13675 13676 13677 13678 13679 13680 13681 13682 13683 13684 13685 13686 13687 13688 13689
    /* 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;
        }
13690 13691
    }

13692 13693 13694 13695
    /* 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 ||
13696
         redefine)) {
13697 13698 13699 13700 13701 13702
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live snapshot creation is supported only "
                         "with external checkpoints"));
        goto cleanup;
    }

13703 13704 13705 13706 13707 13708 13709 13710 13711 13712
    /* allow snapshots only in certain states */
    switch ((virDomainState) vm->state.state) {
        /* valid states */
    case VIR_DOMAIN_RUNNING:
    case VIR_DOMAIN_PAUSED:
    case VIR_DOMAIN_SHUTDOWN:
    case VIR_DOMAIN_SHUTOFF:
    case VIR_DOMAIN_CRASHED:
        break;

13713 13714 13715 13716 13717 13718
    case VIR_DOMAIN_PMSUSPENDED:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("qemu doesn't support taking snapshots of "
                         "PMSUSPENDED guests"));
        goto cleanup;

13719 13720 13721 13722 13723 13724 13725 13726 13727
        /* invalid states */
    case VIR_DOMAIN_NOSTATE:
    case VIR_DOMAIN_BLOCKED: /* invalid state, unused in qemu */
    case VIR_DOMAIN_LAST:
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid domain state %s"),
                       virDomainStateTypeToString(vm->state.state));
        goto cleanup;
    }

13728 13729 13730 13731 13732 13733 13734 13735 13736
    /* We are going to modify the domain below. Internal snapshots would use
     * a regular job, so we need to set the job mask to disallow query as
     * 'savevm' blocks the monitor. External snapshot will then modify the
     * job mask appropriately. */
    if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_SNAPSHOT) < 0)
        goto cleanup;

    qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_NONE);

13737
    if (redefine) {
13738 13739
        if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
                                          &update_current, flags) < 0)
13740
            goto endjob;
13741 13742 13743
    } else {
        /* Easiest way to clone inactive portion of vm->def is via
         * conversion in and back out of xml.  */
13744
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
13745
            !(def->dom = virDomainDefParseString(xml, caps, driver->xmlopt,
13746 13747
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE)))
13748
            goto endjob;
13749

13750
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
13751 13752
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
13753 13754 13755 13756
            if (virDomainObjIsActive(vm))
                def->state = VIR_DOMAIN_DISK_SNAPSHOT;
            else
                def->state = VIR_DOMAIN_SHUTOFF;
13757
            def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
13758 13759 13760 13761
        } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            def->state = virDomainObjGetState(vm, NULL);
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
13762 13763
        } else {
            def->state = virDomainObjGetState(vm, NULL);
13764 13765 13766 13767 13768 13769

            if (virDomainObjIsActive(vm) &&
                def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE) {
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                               _("internal snapshot of a running VM "
                                 "must include the memory state"));
13770
                goto endjob;
13771 13772
            }

13773 13774 13775
            def->memory = (def->state == VIR_DOMAIN_SHUTOFF ?
                           VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
                           VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL);
13776
        }
E
Eric Blake 已提交
13777 13778
        if (virDomainSnapshotAlignDisks(def, align_location,
                                        align_match) < 0 ||
13779
            qemuDomainSnapshotPrepare(conn, vm, def, &flags) < 0)
13780
            goto endjob;
13781 13782
    }

13783 13784
    if (!snap) {
        if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
13785
            goto endjob;
13786 13787 13788

        def = NULL;
    }
C
Chris Lalancette 已提交
13789

13790 13791
    if (update_current)
        snap->def->current = true;
13792
    if (vm->current_snapshot) {
13793
        if (!redefine &&
13794
            VIR_STRDUP(snap->def->parent, vm->current_snapshot->def->name) < 0)
13795
                goto endjob;
13796
        if (update_current) {
13797 13798
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
13799
                                                cfg->snapshotDir) < 0)
13800
                goto endjob;
13801 13802
            vm->current_snapshot = NULL;
        }
13803
    }
13804

C
Chris Lalancette 已提交
13805
    /* actually do the snapshot */
13806
    if (redefine) {
13807
        /* XXX Should we validate that the redefined snapshot even
13808 13809
         * makes sense, such as checking that qemu-img recognizes the
         * snapshot name in at least one of the domain's disks?  */
13810 13811 13812 13813 13814
    } 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,
13815 13816
                                                       vm, snap, flags) < 0)
                goto endjob;
13817 13818 13819
        } else {
            /* internal checkpoint */
            if (qemuDomainSnapshotCreateActiveInternal(domain->conn, driver,
13820 13821
                                                       vm, snap, flags) < 0)
                goto endjob;
13822
        }
E
Eric Blake 已提交
13823
    } else {
13824 13825 13826 13827 13828 13829 13830 13831
        /* 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)
13832
                goto endjob;
13833 13834
        } else {
            if (qemuDomainSnapshotCreateInactiveInternal(driver, vm, snap) < 0)
13835
                goto endjob;
13836
        }
C
Chris Lalancette 已提交
13837 13838
    }

13839
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
13840 13841 13842 13843 13844
     * 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);

13845 13846 13847 13848 13849 13850 13851 13852 13853 13854 13855
 endjob:
    if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
        if (qemuDomainSnapshotWriteMetadata(vm, snap,
                                            cfg->snapshotDir) < 0) {
            /* 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);
13856
            virDomainSnapshotObjListRemove(vm->snapshots, snap);
13857 13858 13859 13860 13861 13862 13863 13864 13865
        } else {
            if (update_current)
                vm->current_snapshot = snap;
            other = virDomainSnapshotFindByName(vm->snapshots,
                                                snap->def->parent);
            snap->parent = other;
            other->nchildren++;
            snap->sibling = other->first_child;
            other->first_child = snap;
13866
        }
13867 13868
    } else if (snap) {
        virDomainSnapshotObjListRemove(vm->snapshots, snap);
13869
    }
13870 13871 13872 13873 13874 13875 13876

    if (!qemuDomainObjEndAsyncJob(driver, vm))
        vm = NULL;

 cleanup:
    if (vm)
        virObjectUnlock(vm);
13877
    virDomainSnapshotDefFree(def);
13878
    VIR_FREE(xml);
13879
    virObjectUnref(caps);
13880
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
13881 13882 13883
    return snapshot;
}

13884 13885 13886 13887 13888 13889

static int
qemuDomainSnapshotListNames(virDomainPtr domain,
                            char **names,
                            int nameslen,
                            unsigned int flags)
C
Chris Lalancette 已提交
13890 13891 13892 13893
{
    virDomainObjPtr vm = NULL;
    int n = -1;

13894
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
13895
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13896

13897
    if (!(vm = qemuDomObjFromDomain(domain)))
13898
        return -1;
C
Chris Lalancette 已提交
13899

13900 13901 13902
    if (virDomainSnapshotListNamesEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13903
    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
13904
                                         flags);
C
Chris Lalancette 已提交
13905

13906
 cleanup:
13907
    virObjectUnlock(vm);
C
Chris Lalancette 已提交
13908 13909 13910
    return n;
}

13911 13912 13913 13914

static int
qemuDomainSnapshotNum(virDomainPtr domain,
                      unsigned int flags)
C
Chris Lalancette 已提交
13915 13916 13917 13918
{
    virDomainObjPtr vm = NULL;
    int n = -1;

13919
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
13920
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13921

13922
    if (!(vm = qemuDomObjFromDomain(domain)))
13923
        return -1;
C
Chris Lalancette 已提交
13924

13925 13926 13927
    if (virDomainSnapshotNumEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13928
    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
C
Chris Lalancette 已提交
13929

13930
 cleanup:
13931
    virObjectUnlock(vm);
C
Chris Lalancette 已提交
13932 13933 13934
    return n;
}

13935

13936
static int
13937 13938
qemuDomainListAllSnapshots(virDomainPtr domain,
                           virDomainSnapshotPtr **snaps,
13939 13940 13941 13942 13943 13944 13945 13946
                           unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);

13947
    if (!(vm = qemuDomObjFromDomain(domain)))
13948
        return -1;
13949

13950 13951 13952
    if (virDomainListAllSnapshotsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13953
    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
13954

13955
 cleanup:
13956
    virObjectUnlock(vm);
13957 13958 13959
    return n;
}

13960

13961 13962 13963 13964 13965 13966 13967 13968 13969 13970 13971
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 |
13972
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13973

13974
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13975
        return -1;
13976

13977 13978 13979
    if (virDomainSnapshotListChildrenNamesEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13980
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13981 13982
        goto cleanup;

13983
    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
13984
                                         flags);
13985

13986
 cleanup:
13987
    virObjectUnlock(vm);
13988 13989 13990
    return n;
}

13991

13992 13993 13994 13995 13996 13997 13998 13999 14000
static int
qemuDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
14001
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
14002

14003
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
14004
        return -1;
14005

14006 14007 14008
    if (virDomainSnapshotNumChildrenEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14009
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
14010 14011
        goto cleanup;

14012
    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
14013

14014
 cleanup:
14015
    virObjectUnlock(vm);
14016 14017 14018
    return n;
}

14019

14020 14021 14022 14023 14024 14025 14026 14027 14028 14029 14030 14031
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);

14032
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
14033
        return -1;
14034

14035 14036 14037
    if (virDomainSnapshotListAllChildrenEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14038
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
14039 14040
        goto cleanup;

14041
    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
14042 14043
                               flags);

14044
 cleanup:
14045
    virObjectUnlock(vm);
14046 14047 14048
    return n;
}

14049 14050 14051 14052 14053

static virDomainSnapshotPtr
qemuDomainSnapshotLookupByName(virDomainPtr domain,
                               const char *name,
                               unsigned int flags)
C
Chris Lalancette 已提交
14054 14055 14056 14057 14058
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

14059 14060
    virCheckFlags(0, NULL);

14061
    if (!(vm = qemuDomObjFromDomain(domain)))
14062
        return NULL;
C
Chris Lalancette 已提交
14063

14064 14065 14066
    if (virDomainSnapshotLookupByNameEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

14067
    if (!(snap = qemuSnapObjFromName(vm, name)))
C
Chris Lalancette 已提交
14068 14069 14070 14071
        goto cleanup;

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

14072
 cleanup:
14073
    virObjectUnlock(vm);
C
Chris Lalancette 已提交
14074 14075 14076
    return snapshot;
}

14077 14078 14079 14080

static int
qemuDomainHasCurrentSnapshot(virDomainPtr domain,
                             unsigned int flags)
C
Chris Lalancette 已提交
14081 14082 14083 14084
{
    virDomainObjPtr vm;
    int ret = -1;

14085 14086
    virCheckFlags(0, -1);

14087
    if (!(vm = qemuDomObjFromDomain(domain)))
14088
        return -1;
C
Chris Lalancette 已提交
14089

14090 14091 14092
    if (virDomainHasCurrentSnapshotEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

C
Chris Lalancette 已提交
14093 14094
    ret = (vm->current_snapshot != NULL);

14095
 cleanup:
14096
    virObjectUnlock(vm);
C
Chris Lalancette 已提交
14097 14098 14099
    return ret;
}

14100

14101 14102 14103 14104 14105 14106 14107 14108 14109 14110
static virDomainSnapshotPtr
qemuDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

14111
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
14112
        return NULL;
14113

14114 14115 14116
    if (virDomainSnapshotGetParentEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14117
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
14118 14119 14120
        goto cleanup;

    if (!snap->def->parent) {
14121 14122 14123
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snap->def->name);
14124 14125 14126 14127 14128
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);

14129
 cleanup:
14130
    virObjectUnlock(vm);
14131 14132 14133
    return parent;
}

14134 14135 14136 14137

static virDomainSnapshotPtr
qemuDomainSnapshotCurrent(virDomainPtr domain,
                          unsigned int flags)
C
Chris Lalancette 已提交
14138 14139 14140 14141
{
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

14142 14143
    virCheckFlags(0, NULL);

14144
    if (!(vm = qemuDomObjFromDomain(domain)))
14145
        return NULL;
C
Chris Lalancette 已提交
14146

14147 14148 14149
    if (virDomainSnapshotCurrentEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

C
Chris Lalancette 已提交
14150
    if (!vm->current_snapshot) {
14151 14152
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                       _("the domain does not have a current snapshot"));
C
Chris Lalancette 已提交
14153 14154 14155 14156 14157
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);

14158
 cleanup:
14159
    virObjectUnlock(vm);
C
Chris Lalancette 已提交
14160 14161 14162
    return snapshot;
}

14163 14164 14165 14166

static char *
qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
C
Chris Lalancette 已提交
14167 14168 14169 14170 14171 14172
{
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

14173
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
14174

14175
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
14176
        return NULL;
C
Chris Lalancette 已提交
14177

14178 14179 14180
    if (virDomainSnapshotGetXMLDescEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14181
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
14182
        goto cleanup;
14183 14184

    virUUIDFormat(snapshot->domain->uuid, uuidstr);
C
Chris Lalancette 已提交
14185

14186
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
14187

14188
 cleanup:
14189
    virObjectUnlock(vm);
C
Chris Lalancette 已提交
14190 14191 14192
    return xml;
}

14193

14194 14195 14196 14197 14198 14199 14200 14201 14202 14203
static int
qemuDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

14204
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
14205
        return -1;
14206

14207 14208 14209
    if (virDomainSnapshotIsCurrentEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14210
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
14211 14212 14213 14214 14215
        goto cleanup;

    ret = (vm->current_snapshot &&
           STREQ(snapshot->name, vm->current_snapshot->def->name));

14216
 cleanup:
14217
    virObjectUnlock(vm);
14218 14219 14220 14221 14222 14223 14224 14225 14226 14227 14228 14229 14230 14231
    return ret;
}


static int
qemuDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

14232
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
14233
        return -1;
14234

14235 14236 14237
    if (virDomainSnapshotHasMetadataEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14238
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
14239 14240 14241 14242 14243 14244 14245
        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;

14246
 cleanup:
14247
    virObjectUnlock(vm);
14248 14249 14250
    return ret;
}

14251

14252 14253
/* The domain is expected to be locked and inactive. */
static int
14254
qemuDomainSnapshotRevertInactive(virQEMUDriverPtr driver,
E
Eric Blake 已提交
14255
                                 virDomainObjPtr vm,
14256 14257 14258
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
14259
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
14260 14261 14262
    return ret > 0 ? -1 : ret;
}

14263 14264 14265 14266

static int
qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
                           unsigned int flags)
C
Chris Lalancette 已提交
14267
{
14268
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
14269 14270 14271
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
14272 14273
    virObjectEventPtr event = NULL;
    virObjectEventPtr event2 = NULL;
14274
    int detail;
C
Chris Lalancette 已提交
14275 14276
    qemuDomainObjPrivatePtr priv;
    int rc;
14277
    virDomainDefPtr config = NULL;
14278
    virQEMUDriverConfigPtr cfg = NULL;
14279
    virCapsPtr caps = NULL;
14280 14281
    bool was_running = false;
    bool was_stopped = false;
C
Chris Lalancette 已提交
14282

14283
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
14284 14285
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
14286

14287 14288 14289 14290 14291 14292 14293 14294 14295 14296
    /* 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
14297 14298
     * Also, several transitions occur even if we fail partway through,
     * and use of FORCE can cause multiple transitions.
14299 14300
     */

14301 14302
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
        return -1;
14303 14304 14305

    cfg = virQEMUDriverGetConfig(driver);

14306 14307 14308
    if (virDomainRevertToSnapshotEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

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

E
Eric Blake 已提交
14312 14313
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
14314
                       _("domain has active block job"));
E
Eric Blake 已提交
14315 14316
        goto cleanup;
    }
C
Chris Lalancette 已提交
14317

14318
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
14319 14320
        goto cleanup;

14321 14322 14323
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
        goto endjob;

14324 14325 14326 14327 14328
    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) {
14329 14330 14331
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("transient domain needs to request run or pause "
                         "to revert to inactive snapshot"));
14332
        goto endjob;
14333
    }
14334 14335

    if (virDomainSnapshotIsExternal(snap)) {
14336
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
14337
                       _("revert to external snapshot not supported yet"));
14338
        goto endjob;
14339
    }
14340

14341 14342
    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
        if (!snap->def->dom) {
14343 14344 14345
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                           _("snapshot '%s' lacks domain '%s' rollback info"),
                           snap->def->name, vm->def->name);
14346
            goto endjob;
14347 14348 14349 14350 14351 14352
        }
        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))) {
14353 14354
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                           _("must respawn qemu to start inactive snapshot"));
14355
            goto endjob;
14356 14357 14358
        }
    }

14359

14360 14361 14362
    if (vm->current_snapshot) {
        vm->current_snapshot->def->current = false;
        if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
14363
                                            cfg->snapshotDir) < 0)
14364
            goto endjob;
14365 14366 14367 14368 14369
        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?  */
    }

14370
    /* Prepare to copy the snapshot inactive xml as the config of this
14371
     * domain.
14372 14373 14374
     *
     * XXX Should domain snapshots track live xml rather
     * than inactive xml?  */
14375
    snap->def->current = true;
14376
    if (snap->def->dom) {
14377
        config = virDomainDefCopy(snap->def->dom, caps, driver->xmlopt, true);
14378
        if (!config)
14379
            goto endjob;
14380
    }
C
Chris Lalancette 已提交
14381

14382 14383 14384
    switch ((virDomainState) snap->def->state) {
    case VIR_DOMAIN_RUNNING:
    case VIR_DOMAIN_PAUSED:
14385 14386 14387 14388 14389 14390
        /* Transitions 2, 3, 5, 6, 8, 9 */
        /* 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 已提交
14391
        if (virDomainObjIsActive(vm)) {
14392
            /* Transitions 5, 6, 8, 9 */
14393 14394
            /* Check for ABI compatibility. We need to do this check against
             * the migratable XML or it will always fail otherwise */
14395
            if (config && !qemuDomainDefCheckABIStability(driver, vm->def, config)) {
14396 14397 14398 14399 14400
                virErrorPtr err = virGetLastError();

                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
                    /* Re-spawn error using correct category. */
                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
14401 14402
                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                                       err->str2);
14403 14404 14405
                    goto endjob;
                }
                virResetError(err);
14406 14407
                qemuProcessStop(driver, vm,
                                VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
14408 14409
                virDomainAuditStop(vm, "from-snapshot");
                detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
14410
                event = virDomainEventLifecycleNewFromObj(vm,
14411 14412 14413 14414 14415
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 detail);
                if (event)
                    qemuDomainEventQueue(driver, event);
                goto load;
14416 14417
            }

C
Chris Lalancette 已提交
14418
            priv = vm->privateData;
14419 14420 14421 14422 14423 14424 14425 14426 14427 14428 14429
            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;
14430
                event = virDomainEventLifecycleNewFromObj(vm,
14431 14432 14433
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 detail);
                if (!virDomainObjIsActive(vm)) {
14434 14435
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("guest unexpectedly quit"));
14436 14437 14438
                    goto endjob;
                }
            }
14439
            qemuDomainObjEnterMonitor(driver, vm);
C
Chris Lalancette 已提交
14440
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
14441
            qemuDomainObjExitMonitor(driver, vm);
14442 14443 14444
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
14445
                goto endjob;
14446
            }
14447
            if (config)
14448
                virDomainObjAssignDef(vm, config, false, NULL);
E
Eric Blake 已提交
14449
        } else {
14450
            /* Transitions 2, 3 */
14451
        load:
14452
            was_stopped = true;
14453
            if (config)
14454
                virDomainObjAssignDef(vm, config, false, NULL);
14455

14456 14457
            rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
                                  QEMU_ASYNC_JOB_NONE, NULL, -1, NULL, snap,
14458 14459
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  VIR_QEMU_PROCESS_START_PAUSED);
14460
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
14461
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
14462
            event = virDomainEventLifecycleNewFromObj(vm,
14463 14464
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
14465
            if (rc < 0)
14466
                goto endjob;
C
Chris Lalancette 已提交
14467 14468
        }

14469
        /* Touch up domain state.  */
14470 14471 14472
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
14473 14474 14475 14476 14477 14478
            /* 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;
14479
                event2 = virDomainEventLifecycleNewFromObj(vm,
14480 14481 14482 14483 14484 14485
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            } /* else transition 6 and 9 use event as-is */
        } else {
            /* Transitions 2, 5, 8 */
            if (!virDomainObjIsActive(vm)) {
14486 14487
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
14488 14489 14490 14491 14492
                goto endjob;
            }
            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
                                      QEMU_ASYNC_JOB_NONE);
H
Hu Tao 已提交
14493
            if (rc < 0)
14494
                goto endjob;
C
Cédric Bosdonnat 已提交
14495
            virObjectUnref(event);
14496 14497 14498 14499
            event = NULL;
            if (was_stopped) {
                /* Transition 2 */
                detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
14500
                event = virDomainEventLifecycleNewFromObj(vm,
14501 14502 14503 14504 14505
                                                 VIR_DOMAIN_EVENT_STARTED,
                                                 detail);
            } else if (was_running) {
                /* Transition 8 */
                detail = VIR_DOMAIN_EVENT_RESUMED;
14506
                event = virDomainEventLifecycleNewFromObj(vm,
14507 14508 14509
                                                 VIR_DOMAIN_EVENT_RESUMED,
                                                 detail);
            }
C
Chris Lalancette 已提交
14510
        }
14511 14512 14513 14514 14515
        break;

    case VIR_DOMAIN_SHUTDOWN:
    case VIR_DOMAIN_SHUTOFF:
    case VIR_DOMAIN_CRASHED:
14516
        /* Transitions 1, 4, 7 */
14517 14518 14519
        /* 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 已提交
14520 14521 14522
         */

        if (virDomainObjIsActive(vm)) {
14523
            /* Transitions 4, 7 */
14524
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
14525
            virDomainAuditStop(vm, "from-snapshot");
14526
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
14527
            event = virDomainEventLifecycleNewFromObj(vm,
C
Chris Lalancette 已提交
14528
                                             VIR_DOMAIN_EVENT_STOPPED,
14529
                                             detail);
14530 14531
        }

E
Eric Blake 已提交
14532
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
14533
            if (!vm->persistent) {
E
Eric Blake 已提交
14534
                if (qemuDomainObjEndJob(driver, vm))
14535
                    qemuDomainRemoveInactive(driver, vm);
14536
                vm = NULL;
14537
                goto cleanup;
14538
            }
14539
            goto endjob;
C
Chris Lalancette 已提交
14540
        }
14541
        if (config)
14542
            virDomainObjAssignDef(vm, config, false, NULL);
14543

14544 14545 14546 14547
        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;
14548 14549 14550
            unsigned int start_flags = 0;

            start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
14551 14552 14553

            if (event)
                qemuDomainEventQueue(driver, event);
14554 14555
            rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
                                  QEMU_ASYNC_JOB_NONE, NULL, -1, NULL, NULL,
14556 14557
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  start_flags);
14558 14559 14560
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
E
Eric Blake 已提交
14561
                    if (qemuDomainObjEndJob(driver, vm))
14562
                        qemuDomainRemoveInactive(driver, vm);
14563 14564 14565 14566 14567 14568
                    vm = NULL;
                    goto cleanup;
                }
                goto endjob;
            }
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
14569
            event = virDomainEventLifecycleNewFromObj(vm,
14570 14571 14572 14573
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
            if (paused) {
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
14574
                event2 = virDomainEventLifecycleNewFromObj(vm,
14575 14576 14577 14578
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            }
        }
14579
        break;
14580

14581 14582 14583 14584
    case VIR_DOMAIN_PMSUSPENDED:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("qemu doesn't support reversion of snapshot taken in "
                         "PMSUSPENDED state"));
14585
        goto endjob;
14586

14587 14588 14589 14590 14591 14592 14593
    case VIR_DOMAIN_NOSTATE:
    case VIR_DOMAIN_BLOCKED:
    case VIR_DOMAIN_LAST:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid target domain state '%s'. Refusing "
                         "snapshot reversion"),
                       virDomainStateTypeToString(snap->def->state));
14594
        goto endjob;
C
Chris Lalancette 已提交
14595 14596 14597 14598
    }

    ret = 0;

14599
 endjob:
E
Eric Blake 已提交
14600
    if (vm && !qemuDomainObjEndJob(driver, vm))
C
Chris Lalancette 已提交
14601 14602
        vm = NULL;

14603
 cleanup:
14604 14605
    if (vm && ret == 0) {
        if (qemuDomainSnapshotWriteMetadata(vm, snap,
14606
                                            cfg->snapshotDir) < 0)
14607 14608 14609 14610 14611 14612
            ret = -1;
        else
            vm->current_snapshot = snap;
    } else if (snap) {
        snap->def->current = false;
    }
14613
    if (event) {
C
Chris Lalancette 已提交
14614
        qemuDomainEventQueue(driver, event);
14615 14616 14617
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
14618
    if (vm)
14619
        virObjectUnlock(vm);
14620
    virObjectUnref(caps);
14621
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
14622 14623 14624 14625

    return ret;
}

14626 14627 14628 14629

typedef struct _virQEMUSnapReparent virQEMUSnapReparent;
typedef virQEMUSnapReparent *virQEMUSnapReparentPtr;
struct _virQEMUSnapReparent {
14630
    virQEMUDriverConfigPtr cfg;
14631
    virDomainSnapshotObjPtr parent;
14632 14633
    virDomainObjPtr vm;
    int err;
14634
    virDomainSnapshotObjPtr last;
14635 14636
};

14637

14638 14639
static void
qemuDomainSnapshotReparentChildren(void *payload,
14640
                                   const void *name ATTRIBUTE_UNUSED,
14641 14642 14643
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
14644
    virQEMUSnapReparentPtr rep = data;
14645 14646 14647 14648 14649

    if (rep->err < 0) {
        return;
    }

14650
    VIR_FREE(snap->def->parent);
14651
    snap->parent = rep->parent;
14652

14653 14654 14655 14656
    if (rep->parent->def &&
        VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
        rep->err = -1;
        return;
14657
    }
14658

14659 14660 14661
    if (!snap->sibling)
        rep->last = snap;

14662
    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
14663
                                               rep->cfg->snapshotDir);
14664 14665
}

14666

14667 14668 14669
static int
qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
C
Chris Lalancette 已提交
14670
{
14671
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
14672 14673 14674
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
14675 14676
    virQEMUSnapRemove rem;
    virQEMUSnapReparent rep;
14677
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
14678
    int external = 0;
14679
    virQEMUDriverConfigPtr cfg = NULL;
C
Chris Lalancette 已提交
14680

14681
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
14682 14683
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
14684

14685 14686
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
        return -1;
C
Chris Lalancette 已提交
14687

14688
    cfg = virQEMUDriverGetConfig(driver);
14689 14690 14691 14692

    if (virDomainSnapshotDeleteEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14693
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
14694 14695
        goto cleanup;

14696 14697 14698
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
        goto endjob;

14699
    if (!metadata_only) {
14700
        if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
14701
            virDomainSnapshotIsExternal(snap))
14702 14703
            external++;
        if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
E
Eric Blake 已提交
14704
            virDomainSnapshotForEachDescendant(snap,
14705 14706 14707
                                               qemuDomainSnapshotCountExternal,
                                               &external);
        if (external) {
14708 14709 14710
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("deletion of %d external disk snapshots not "
                             "supported yet"), external);
14711
            goto endjob;
14712 14713 14714
        }
    }

14715 14716
    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
C
Chris Lalancette 已提交
14717 14718
        rem.driver = driver;
        rem.vm = vm;
14719
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
14720
        rem.err = 0;
14721
        rem.current = false;
E
Eric Blake 已提交
14722
        virDomainSnapshotForEachDescendant(snap,
E
Eric Blake 已提交
14723
                                           qemuDomainSnapshotDiscardAll,
14724
                                           &rem);
C
Chris Lalancette 已提交
14725
        if (rem.err < 0)
14726
            goto endjob;
14727 14728 14729 14730
        if (rem.current) {
            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
                snap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, snap,
14731
                                                    cfg->snapshotDir) < 0) {
14732 14733 14734
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("failed to set snapshot '%s' as current"),
                                   snap->def->name);
14735 14736 14737 14738
                    snap->def->current = false;
                    goto endjob;
                }
            }
14739
            vm->current_snapshot = snap;
14740
        }
14741
    } else if (snap->nchildren) {
14742
        rep.cfg = cfg;
14743
        rep.parent = snap->parent;
14744 14745
        rep.vm = vm;
        rep.err = 0;
14746
        rep.last = NULL;
E
Eric Blake 已提交
14747
        virDomainSnapshotForEachChild(snap,
14748 14749
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
14750 14751
        if (rep.err < 0)
            goto endjob;
14752
        /* Can't modify siblings during ForEachChild, so do it now.  */
14753 14754 14755
        snap->parent->nchildren += snap->nchildren;
        rep.last->sibling = snap->parent->first_child;
        snap->parent->first_child = snap->first_child;
C
Chris Lalancette 已提交
14756 14757
    }

14758 14759 14760
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
        snap->nchildren = 0;
        snap->first_child = NULL;
14761
        ret = 0;
14762
    } else {
14763
        virDomainSnapshotDropParent(snap);
14764
        ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
14765
    }
C
Chris Lalancette 已提交
14766

14767
 endjob:
E
Eric Blake 已提交
14768
    if (!qemuDomainObjEndJob(driver, vm))
14769 14770
        vm = NULL;

14771
 cleanup:
C
Chris Lalancette 已提交
14772
    if (vm)
14773
        virObjectUnlock(vm);
14774
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
14775 14776
    return ret;
}
14777

14778 14779
static int qemuDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd,
                                        char **result, unsigned int flags)
14780
{
14781
    virQEMUDriverPtr driver = domain->conn->privateData;
14782 14783 14784
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
14785
    bool hmp;
14786

14787
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
14788

14789
    if (!(vm = qemuDomObjFromDomain(domain)))
14790 14791
        goto cleanup;

14792 14793 14794
    if (virDomainQemuMonitorCommandEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

14795
    if (!virDomainObjIsActive(vm)) {
14796 14797
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14798
        goto cleanup;
14799
    }
14800

14801
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
14802 14803 14804
        goto cleanup;

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

14810 14811
    priv = vm->privateData;

14812
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
14813

14814 14815
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

14816
    qemuDomainObjEnterMonitor(driver, vm);
14817
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
14818
    qemuDomainObjExitMonitor(driver, vm);
14819

14820
 endjob:
E
Eric Blake 已提交
14821
    if (!qemuDomainObjEndJob(driver, vm)) {
14822 14823 14824
        vm = NULL;
    }

14825
 cleanup:
14826
    if (vm)
14827
        virObjectUnlock(vm);
14828 14829 14830
    return ret;
}

14831

14832 14833 14834
static virDomainPtr qemuDomainQemuAttach(virConnectPtr conn,
                                         unsigned int pid_value,
                                         unsigned int flags)
14835
{
14836
    virQEMUDriverPtr driver = conn->privateData;
14837 14838 14839 14840 14841
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
14842
    pid_t pid = pid_value;
14843
    char *pidfile = NULL;
14844
    virQEMUCapsPtr qemuCaps = NULL;
14845
    virCapsPtr caps = NULL;
14846 14847 14848

    virCheckFlags(0, NULL);

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

14852
    if (!(def = qemuParseCommandLinePid(caps, driver->xmlopt, pid,
14853 14854 14855
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

14856 14857 14858
    if (virDomainQemuAttachEnsureACL(conn, def) < 0)
        goto cleanup;

14859
    if (!monConfig) {
14860 14861
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("No monitor connection for pid %u"), pid_value);
14862 14863 14864
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
14865 14866 14867 14868 14869
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot connect to monitor connection of type '%s' "
                         "for pid %u"),
                       virDomainChrTypeToString(monConfig->type),
                       pid_value);
14870 14871 14872 14873
        goto cleanup;
    }

    if (!(def->name) &&
14874
        virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0)
14875 14876
        goto cleanup;

14877
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
14878 14879
        goto cleanup;

14880
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
14881 14882
        goto cleanup;

14883
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
14884 14885
        goto cleanup;

14886
    if (!(vm = virDomainObjListAdd(driver->domains, def,
14887
                                   driver->xmlopt,
14888 14889 14890
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
14891 14892 14893 14894
        goto cleanup;

    def = NULL;

E
Eric Blake 已提交
14895 14896 14897
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) {
        qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
14898
        goto cleanup;
E
Eric Blake 已提交
14899
    }
14900 14901 14902

    if (qemuProcessAttach(conn, driver, vm, pid,
                          pidfile, monConfig, monJSON) < 0) {
E
Eric Blake 已提交
14903
        if (qemuDomainObjEndJob(driver, vm))
E
Eric Blake 已提交
14904 14905
            qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
14906
        monConfig = NULL;
E
Eric Blake 已提交
14907
        goto cleanup;
14908 14909 14910 14911 14912
    }

    monConfig = NULL;

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
E
Eric Blake 已提交
14913 14914
    if (dom)
        dom->id = vm->def->id;
14915

E
Eric Blake 已提交
14916
    if (!qemuDomainObjEndJob(driver, vm))
14917 14918
        vm = NULL;

14919
 cleanup:
14920 14921 14922
    virDomainDefFree(def);
    virDomainChrSourceDefFree(monConfig);
    if (vm)
14923
        virObjectUnlock(vm);
14924
    VIR_FREE(pidfile);
14925
    virObjectUnref(caps);
E
Eric Blake 已提交
14926
    virObjectUnref(qemuCaps);
14927 14928 14929 14930
    return dom;
}


14931 14932
static int
qemuDomainOpenConsole(virDomainPtr dom,
14933
                      const char *dev_name,
14934 14935 14936 14937 14938
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
14939
    size_t i;
14940
    virDomainChrDefPtr chr = NULL;
14941
    qemuDomainObjPrivatePtr priv;
14942

14943 14944
    virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE |
                  VIR_DOMAIN_CONSOLE_FORCE, -1);
14945

14946
    if (!(vm = qemuDomObjFromDomain(dom)))
14947 14948
        goto cleanup;

14949 14950 14951
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

14952
    if (!virDomainObjIsActive(vm)) {
14953 14954
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14955 14956 14957
        goto cleanup;
    }

14958 14959
    priv = vm->privateData;

14960
    if (dev_name) {
14961
        for (i = 0; !chr && i < vm->def->nconsoles; i++) {
14962 14963 14964 14965
            if (vm->def->consoles[i]->info.alias &&
                STREQ(dev_name, vm->def->consoles[i]->info.alias))
                chr = vm->def->consoles[i];
        }
14966
        for (i = 0; !chr && i < vm->def->nserials; i++) {
14967
            if (STREQ(dev_name, vm->def->serials[i]->info.alias))
14968 14969
                chr = vm->def->serials[i];
        }
14970
        for (i = 0; !chr && i < vm->def->nparallels; i++) {
14971
            if (STREQ(dev_name, vm->def->parallels[i]->info.alias))
14972 14973 14974
                chr = vm->def->parallels[i];
        }
    } else {
14975 14976
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
14977 14978 14979 14980 14981
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
14982 14983 14984
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find character device %s"),
                       NULLSTR(dev_name));
14985 14986 14987
        goto cleanup;
    }

14988
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
14989 14990 14991
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("character device %s is not using a PTY"),
                       NULLSTR(dev_name));
14992 14993 14994
        goto cleanup;
    }

14995
    /* handle mutually exclusive access to console devices */
14996
    ret = virChrdevOpen(priv->devs,
14997
                        &chr->source,
14998 14999
                        st,
                        (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0);
15000 15001

    if (ret == 1) {
15002 15003
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active console session exists for this domain"));
15004 15005
        ret = -1;
    }
15006

15007
 cleanup:
15008
    if (vm)
15009
        virObjectUnlock(vm);
15010 15011 15012
    return ret;
}

15013 15014 15015 15016 15017 15018 15019 15020
static int
qemuDomainOpenChannel(virDomainPtr dom,
                      const char *name,
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
15021
    size_t i;
15022 15023 15024 15025 15026 15027 15028 15029
    virDomainChrDefPtr chr = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(VIR_DOMAIN_CHANNEL_FORCE, -1);

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

15030 15031 15032
    if (virDomainOpenChannelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15033 15034 15035 15036 15037 15038 15039 15040 15041
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

    priv = vm->privateData;

    if (name) {
15042
        for (i = 0; !chr && i < vm->def->nchannels; i++) {
15043 15044 15045 15046 15047 15048 15049 15050 15051 15052 15053 15054 15055 15056 15057 15058 15059 15060 15061 15062 15063 15064 15065 15066 15067 15068 15069 15070 15071 15072 15073 15074 15075 15076 15077 15078 15079 15080 15081
            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;
    }

15082
 cleanup:
15083
    if (vm)
15084
        virObjectUnlock(vm);
15085 15086 15087
    return ret;
}

E
Eric Blake 已提交
15088
static char *
15089
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path, int *idxret)
E
Eric Blake 已提交
15090
{
15091
    int idx;
15092
    char *ret = NULL;
15093
    virDomainDiskDefPtr disk;
15094

15095 15096
    idx = virDomainDiskIndexByName(vm->def, path, true);
    if (idx < 0)
15097
        goto cleanup;
15098

15099 15100 15101
    disk = vm->def->disks[idx];
    if (idxret)
        *idxret = idx;
15102

15103
    if (virDomainDiskGetSource(disk)) {
15104
        if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0)
15105
            return NULL;
15106 15107
    }

15108
 cleanup:
15109
    if (!ret) {
15110 15111
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("No device found for specified path"));
15112 15113 15114 15115
    }
    return ret;
}

15116 15117 15118 15119
/* 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 已提交
15120
qemuDomainBlockPivot(virConnectPtr conn,
15121
                     virQEMUDriverPtr driver, virDomainObjPtr vm,
15122 15123
                     const char *device, virDomainDiskDefPtr disk)
{
15124
    int ret = -1, rc;
15125 15126
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainBlockJobInfo info;
15127
    const char *format = NULL;
E
Eric Blake 已提交
15128
    bool resume = false;
15129
    virStorageSourcePtr oldsrc = NULL;
15130
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
15131

15132 15133 15134 15135 15136 15137 15138 15139 15140
    if (!disk->mirror) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("pivot of disk '%s' requires an active copy job"),
                       disk->dst);
        goto cleanup;
    }

    format = virStorageFileFormatTypeToString(disk->mirror->format);

15141
    /* Probe the status, if needed.  */
15142
    if (!disk->mirrorState) {
15143
        qemuDomainObjEnterMonitor(driver, vm);
15144
        rc = qemuMonitorBlockJobInfo(priv->mon, device, &info, NULL);
15145
        qemuDomainObjExitMonitor(driver, vm);
15146
        if (rc < 0)
15147 15148 15149 15150 15151 15152
            goto cleanup;
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain is not running"));
            goto cleanup;
        }
15153
        if (rc == 1 && info.cur == info.end &&
15154
            info.type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY)
15155
            disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
15156 15157
    }

15158
    if (disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_READY) {
15159 15160 15161 15162 15163 15164
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' not ready for pivot yet"),
                       disk->dst);
        goto cleanup;
    }

E
Eric Blake 已提交
15165 15166 15167 15168 15169 15170 15171 15172 15173 15174 15175 15176 15177 15178 15179 15180 15181 15182 15183 15184 15185 15186 15187
    /* 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;
        }
    }

15188 15189 15190 15191 15192 15193 15194 15195 15196 15197 15198
    /* For active commit, the mirror is part of the already labeled
     * chain.  For blockcopy, we previously labeled only the top-level
     * image; but if the user is reusing an external image that
     * includes a backing file, the pivot may result in qemu needing
     * to open the entire backing chain, so we need to label the
     * entire chain.  This action is safe even if the backing chain
     * has already been labeled; but only necessary when we know for
     * sure that there is a backing chain.  */
    if (disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
        oldsrc = disk->src;
        disk->src = disk->mirror;
15199

15200
        if (qemuDomainDetermineDiskChain(driver, vm, disk, false, true) < 0)
15201
            goto cleanup;
15202

15203 15204 15205 15206 15207 15208 15209 15210 15211 15212 15213 15214
        if (disk->mirror->format &&
            disk->mirror->format != VIR_STORAGE_FILE_RAW &&
            (virDomainLockDiskAttach(driver->lockManager, cfg->uri, vm,
                                     disk) < 0 ||
             qemuSetupDiskCgroup(vm, disk) < 0 ||
             virSecurityManagerSetDiskLabel(driver->securityManager, vm->def,
                                            disk) < 0))
            goto cleanup;

        disk->src = oldsrc;
        oldsrc = NULL;
    }
15215

15216 15217 15218 15219 15220 15221 15222 15223 15224 15225 15226
    /* Attempt the pivot.  Record the attempt now, to prevent duplicate
     * attempts; but the actual disk change will be made when emitting
     * the event.
     * XXX On libvirtd restarts, if we missed the qemu event, we need
     * to double check what state qemu is in.
     * XXX We should be using qemu's rerror flag to make sure the job
     * remains alive until we know it's final state.
     * XXX If the abort command is synchronous but the qemu event says
     * that pivot failed, we need to reflect that failure into the
     * overall return value.  */
    disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT;
15227
    qemuDomainObjEnterMonitor(driver, vm);
15228
    ret = qemuMonitorDrivePivot(priv->mon, device, disk->mirror->path, format);
15229
    qemuDomainObjExitMonitor(driver, vm);
15230

15231
    if (ret < 0) {
15232 15233 15234 15235 15236 15237
        /* 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
15238 15239 15240 15241 15242 15243 15244
         * before killing the mirroring job?
         * 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); so for now, we leak the access to
         * the original.  */
15245
        virStorageSourceFree(disk->mirror);
15246 15247
        disk->mirror = NULL;
        disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
E
Eric Blake 已提交
15248
        disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
15249
    }
15250 15251
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
        ret = -1;
15252

15253
 cleanup:
15254 15255 15256
    if (oldsrc)
        disk->src = oldsrc;

E
Eric Blake 已提交
15257 15258 15259
    if (resume && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
15260
                             QEMU_ASYNC_JOB_NONE) < 0) {
15261
        virObjectEventPtr event = NULL;
15262
        event = virDomainEventLifecycleNewFromObj(vm,
15263 15264 15265 15266 15267 15268 15269 15270
                                         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 已提交
15271
    }
15272
    virObjectUnref(cfg);
15273 15274 15275
    return ret;
}

15276

15277 15278
/* bandwidth in MiB/s per public API. Caller must lock vm beforehand,
 * and not access it afterwards.  */
15279
static int
15280 15281 15282
qemuDomainBlockJobImpl(virDomainObjPtr vm,
                       virConnectPtr conn,
                       const char *path, const char *base,
15283
                       unsigned long bandwidth,
15284
                       int mode, unsigned int flags)
15285
{
15286
    virQEMUDriverPtr driver = conn->privateData;
15287
    qemuDomainObjPrivatePtr priv;
E
Eric Blake 已提交
15288
    char *device = NULL;
15289
    int ret = -1;
15290
    bool async = false;
15291
    virObjectEventPtr event = NULL;
15292
    virObjectEventPtr event2 = NULL;
15293 15294
    int idx;
    virDomainDiskDefPtr disk;
15295 15296
    virStorageSourcePtr baseSource = NULL;
    unsigned int baseIndex = 0;
15297 15298
    char *basePath = NULL;
    char *backingPath = NULL;
15299 15300
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    bool save = false;
15301
    unsigned long long speed = bandwidth;
15302

15303
    if (!virDomainObjIsActive(vm)) {
15304 15305
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
15306 15307 15308
        goto cleanup;
    }

15309 15310 15311 15312 15313 15314 15315
    if (flags & VIR_DOMAIN_BLOCK_REBASE_RELATIVE && !base) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("flag VIR_DOMAIN_BLOCK_REBASE_RELATIVE is valid only "
                         "with non-null base"));
        goto cleanup;
    }

15316
    priv = vm->privateData;
15317
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC)) {
15318
        async = true;
15319
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC)) {
15320 15321
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block jobs not supported with this QEMU binary"));
15322 15323
        goto cleanup;
    } else if (base) {
15324 15325 15326
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("partial block pull not supported with this "
                         "QEMU binary"));
15327
        goto cleanup;
15328
    } else if (mode == BLOCK_JOB_PULL && bandwidth) {
15329 15330 15331
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("setting bandwidth at start of block pull not "
                         "supported with this QEMU binary"));
15332
        goto cleanup;
15333
    }
15334

15335 15336 15337 15338 15339 15340 15341 15342 15343
    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;
    }

15344 15345
    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
15346
        goto endjob;
15347
    disk = vm->def->disks[idx];
15348

E
Eric Blake 已提交
15349 15350
    if (mode == BLOCK_JOB_PULL && disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
15351
                       _("disk '%s' already in active block job"),
E
Eric Blake 已提交
15352
                       disk->dst);
15353
        goto endjob;
E
Eric Blake 已提交
15354
    }
15355 15356 15357 15358 15359 15360 15361 15362 15363 15364 15365 15366 15367 15368 15369
    if (mode == BLOCK_JOB_ABORT) {
        if ((flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT) &&
            !(async && disk->mirror)) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("pivot of disk '%s' requires an active copy job"),
                           disk->dst);
            goto endjob;
        }
        if (disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_NONE &&
            disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_READY) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("another job on disk '%s' is still being ended"),
                           disk->dst);
            goto endjob;
        }
15370

15371 15372 15373 15374 15375 15376 15377 15378
        if (disk->mirror && (flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)) {
            ret = qemuDomainBlockPivot(conn, driver, vm, device, disk);
            goto waitjob;
        }
        if (disk->mirror) {
            disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_ABORT;
            save = true;
        }
15379 15380
    }

15381 15382
    if (base &&
        (virStorageFileParseChainIndex(disk->dst, base, &baseIndex) < 0 ||
E
Eric Blake 已提交
15383
         !(baseSource = virStorageFileChainLookup(disk->src, disk->src,
15384 15385 15386
                                                  base, baseIndex, NULL))))
        goto endjob;

15387 15388 15389 15390 15391 15392 15393 15394 15395 15396 15397 15398 15399 15400 15401 15402 15403 15404 15405 15406 15407 15408 15409 15410 15411 15412
    if (baseSource) {
        if (qemuGetDriveSourceString(baseSource, NULL, &basePath) < 0)
            goto endjob;

        if (flags & VIR_DOMAIN_BLOCK_REBASE_RELATIVE) {
            if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CHANGE_BACKING_FILE)) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("this QEMU binary doesn't support relative "
                                 "block pull/rebase"));
                goto endjob;
            }

            if (virStorageFileGetRelativeBackingPath(disk->src->backingStore,
                                                     baseSource,
                                                     &backingPath) < 0)
                goto endjob;


            if (!backingPath) {
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("can't keep relative backing relationship"));
                goto endjob;
            }
        }
    }

15413 15414 15415 15416 15417 15418 15419 15420 15421 15422 15423 15424
    /* Convert bandwidth MiB to bytes, if needed */
    if ((mode == BLOCK_JOB_SPEED &&
         !(flags & VIR_DOMAIN_BLOCK_JOB_SPEED_BANDWIDTH_BYTES)) ||
        (mode == BLOCK_JOB_PULL &&
         !(flags & VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES))) {
        if (speed > LLONG_MAX >> 20) {
            virReportError(VIR_ERR_OVERFLOW,
                           _("bandwidth must be less than %llu"),
                           LLONG_MAX >> 20);
            goto endjob;
        }
        speed <<= 20;
15425 15426
    }

15427
    qemuDomainObjEnterMonitor(driver, vm);
15428
    ret = qemuMonitorBlockJob(priv->mon, device, basePath, backingPath,
15429
                              speed, mode, async);
15430
    qemuDomainObjExitMonitor(driver, vm);
15431 15432 15433
    if (ret < 0) {
        if (mode == BLOCK_JOB_ABORT && disk->mirror)
            disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
15434
        goto endjob;
15435
    }
15436

15437
 waitjob:
15438 15439 15440 15441 15442 15443
    /* If we have made changes to XML due to a copy job, make a best
     * effort to save it now.  But we can ignore failure, since there
     * will be further changes when the event marks completion.  */
    if (save)
        ignore_value(virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm));

15444 15445
    /* With synchronous block cancel, we must synthesize an event, and
     * we silently ignore the ABORT_ASYNC flag.  With asynchronous
15446 15447 15448 15449 15450
     * block cancel, the event will come from qemu and will update the
     * XML as appropriate, 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.  */
15451 15452
    if (mode == BLOCK_JOB_ABORT) {
        if (!async) {
15453
            /* Older qemu that lacked async reporting also lacked
15454 15455 15456
             * blockcopy and active commit, so we can hardcode the
             * event to pull, and we know the XML doesn't need
             * updating.  We have to generate two event variants.  */
15457 15458
            int type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
            int status = VIR_DOMAIN_BLOCK_JOB_CANCELED;
15459
            event = virDomainEventBlockJobNewFromObj(vm, disk->src->path, type,
15460
                                                     status);
15461 15462
            event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type,
                                                       status);
15463
        } else if (!(flags & VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC)) {
15464 15465
            /* XXX If the event reports failure, we should reflect
             * that back into the return status of this API call.  */
15466 15467 15468 15469 15470 15471
            while (1) {
                /* Poll every 50ms */
                static struct timespec ts = { .tv_sec = 0,
                                              .tv_nsec = 50 * 1000 * 1000ull };
                virDomainBlockJobInfo dummy;

15472
                qemuDomainObjEnterMonitor(driver, vm);
15473
                ret = qemuMonitorBlockJobInfo(priv->mon, device, &dummy, NULL);
15474
                qemuDomainObjExitMonitor(driver, vm);
15475 15476 15477 15478

                if (ret <= 0)
                    break;

15479
                virObjectUnlock(vm);
15480 15481 15482

                nanosleep(&ts, NULL);

15483
                virObjectLock(vm);
15484 15485

                if (!virDomainObjIsActive(vm)) {
15486 15487
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("domain is not running"));
15488 15489 15490 15491 15492 15493
                    ret = -1;
                    break;
                }
            }
        }
    }
15494

15495
 endjob:
E
Eric Blake 已提交
15496
    if (!qemuDomainObjEndJob(driver, vm)) {
15497 15498 15499 15500
        vm = NULL;
        goto cleanup;
    }

15501
 cleanup:
15502
    virObjectUnref(cfg);
15503 15504
    VIR_FREE(basePath);
    VIR_FREE(backingPath);
15505 15506
    VIR_FREE(device);
    if (vm)
15507
        virObjectUnlock(vm);
15508 15509
    if (event)
        qemuDomainEventQueue(driver, event);
15510 15511
    if (event2)
        qemuDomainEventQueue(driver, event2);
15512 15513 15514 15515 15516 15517
    return ret;
}

static int
qemuDomainBlockJobAbort(virDomainPtr dom, const char *path, unsigned int flags)
{
15518 15519
    virDomainObjPtr vm;

15520 15521
    virCheckFlags(VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC |
                  VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT, -1);
15522 15523 15524 15525 15526 15527 15528 15529 15530

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

    if (virDomainBlockJobAbortEnsureACL(dom->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

15531 15532
    return qemuDomainBlockJobImpl(vm, dom->conn, path, NULL, 0,
                                  BLOCK_JOB_ABORT, flags);
15533 15534 15535 15536 15537 15538
}

static int
qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
                           virDomainBlockJobInfoPtr info, unsigned int flags)
{
15539 15540
    virQEMUDriverPtr driver = dom->conn->privateData;
    qemuDomainObjPrivatePtr priv;
15541
    virDomainObjPtr vm;
15542 15543 15544 15545
    char *device = NULL;
    int idx;
    virDomainDiskDefPtr disk;
    int ret = -1;
15546
    unsigned long long bandwidth;
15547

15548
    virCheckFlags(VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES, -1);
15549 15550 15551 15552 15553 15554 15555 15556 15557

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

    if (virDomainGetBlockJobInfoEnsureACL(dom->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

15558 15559 15560 15561 15562 15563 15564 15565 15566 15567 15568 15569 15570 15571 15572 15573 15574 15575 15576 15577 15578 15579 15580
    priv = vm->privateData;
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC) &&
        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block jobs not supported with this QEMU binary"));
        goto cleanup;
    }

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

    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
        goto endjob;
    disk = vm->def->disks[idx];

    qemuDomainObjEnterMonitor(driver, vm);
15581
    ret = qemuMonitorBlockJobInfo(priv->mon, device, info, &bandwidth);
15582 15583 15584 15585 15586 15587 15588
    qemuDomainObjExitMonitor(driver, vm);
    if (ret < 0)
        goto endjob;

    if (info->type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT &&
        disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)
        info->type = disk->mirrorJob;
15589 15590 15591 15592 15593 15594 15595 15596 15597 15598 15599
    if (bandwidth) {
        if (!(flags & VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES))
            bandwidth = VIR_DIV_UP(bandwidth, 1024 * 1024);
        info->bandwidth = bandwidth;
        if (info->bandwidth != bandwidth) {
            virReportError(VIR_ERR_OVERFLOW,
                           _("bandwidth %llu cannot be represented in result"),
                           bandwidth);
            goto endjob;
        }
    }
15600 15601 15602 15603 15604 15605 15606 15607 15608 15609 15610 15611 15612 15613 15614 15615 15616 15617 15618 15619 15620 15621

    /* Snoop block copy operations, so future cancel operations can
     * avoid checking if pivot is safe.  Save the change to XML, but
     * we can ignore failure because it is only an optimization.  We
     * hold the vm lock, so modifying the in-memory representation is
     * safe, even if we are a query rather than a modify job. */
    if (ret == 1 && disk->mirror &&
        info->cur == info->end && !disk->mirrorState) {
        virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);

        disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
        ignore_value(virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm));
        virObjectUnref(cfg);
    }
 endjob:
    if (!qemuDomainObjEndJob(driver, vm))
        vm = NULL;

 cleanup:
    if (vm)
        virObjectUnlock(vm);
    return ret;
15622 15623 15624 15625 15626 15627
}

static int
qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
                           unsigned long bandwidth, unsigned int flags)
{
15628
    virDomainObjPtr vm;
15629
    virCheckFlags(VIR_DOMAIN_BLOCK_JOB_SPEED_BANDWIDTH_BYTES, -1);
15630 15631 15632 15633 15634 15635 15636 15637 15638

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

    if (virDomainBlockJobSetSpeedEnsureACL(dom->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

15639
    return qemuDomainBlockJobImpl(vm, dom->conn, path, NULL, bandwidth,
15640
                                  BLOCK_JOB_SPEED, flags);
15641 15642
}

15643

15644 15645 15646
/* bandwidth in bytes/s.  Caller must lock vm beforehand, and not
 * access it afterwards; likewise, caller must not access mirror
 * afterwards.  */
15647
static int
15648 15649 15650 15651 15652
qemuDomainBlockCopyCommon(virDomainObjPtr vm,
                          virConnectPtr conn,
                          const char *path,
                          virStorageSourcePtr mirror,
                          unsigned long long bandwidth,
15653 15654
                          unsigned int granularity,
                          unsigned long long buf_size,
15655
                          unsigned int flags)
15656
{
15657
    virQEMUDriverPtr driver = conn->privateData;
15658 15659
    qemuDomainObjPrivatePtr priv;
    char *device = NULL;
15660
    virDomainDiskDefPtr disk = NULL;
15661 15662
    int ret = -1;
    int idx;
15663
    struct stat st;
15664
    bool need_unlink = false;
15665
    virQEMUDriverConfigPtr cfg = NULL;
15666 15667
    const char *format = NULL;
    int desttype = virStorageSourceGetActualType(mirror);
15668 15669

    /* Preliminaries: find the disk we are editing, sanity checks */
15670 15671
    virCheckFlags(VIR_DOMAIN_BLOCK_COPY_SHALLOW |
                  VIR_DOMAIN_BLOCK_COPY_REUSE_EXT, -1);
15672 15673

    priv = vm->privateData;
15674
    cfg = virQEMUDriverGetConfig(driver);
15675

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

15679 15680 15681
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
15682
        goto endjob;
15683 15684 15685 15686
    }

    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device) {
15687
        goto endjob;
15688 15689 15690 15691
    }
    disk = vm->def->disks[idx];
    if (disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
15692
                       _("disk '%s' already in active block job"),
15693
                       disk->dst);
15694
        goto endjob;
15695 15696
    }

15697 15698
    if (!(virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_MIRROR) &&
          virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC))) {
15699 15700
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block copy is not supported with this QEMU binary"));
15701
        goto endjob;
15702 15703 15704 15705 15706 15707 15708 15709 15710 15711
    }
    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;
    }
15712

15713
    if (qemuDomainDetermineDiskChain(driver, vm, disk, false, true) < 0)
15714 15715
        goto endjob;

15716 15717
    if ((flags & VIR_DOMAIN_BLOCK_COPY_SHALLOW) &&
        mirror->format == VIR_STORAGE_FILE_RAW &&
15718
        disk->src->backingStore->path) {
15719 15720 15721 15722 15723 15724 15725 15726
        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.  */
15727 15728 15729 15730 15731 15732
    /* XXX Allow non-file mirror destinations */
    if (!virStorageSourceIsLocalStorage(mirror)) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("non-file destination not supported yet"));
    }
    if (stat(mirror->path, &st) < 0) {
15733 15734
        if (errno != ENOENT) {
            virReportSystemError(errno, _("unable to stat for disk %s: %s"),
15735
                                 disk->dst, mirror->path);
15736
            goto endjob;
15737 15738
        } else if (flags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT ||
                   desttype == VIR_STORAGE_TYPE_BLOCK) {
15739 15740
            virReportSystemError(errno,
                                 _("missing destination file for disk %s: %s"),
15741
                                 disk->dst, mirror->path);
15742 15743
            goto endjob;
        }
15744
    } else if (!S_ISBLK(st.st_mode)) {
15745
        if (st.st_size && !(flags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT)) {
15746 15747 15748
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("external destination file for disk %s already "
                             "exists and is not a block device: %s"),
15749
                           disk->dst, mirror->path);
15750 15751
            goto endjob;
        }
15752
        if (desttype == VIR_STORAGE_TYPE_BLOCK) {
15753 15754
            virReportError(VIR_ERR_INVALID_ARG,
                           _("blockdev flag requested for disk %s, but file "
15755 15756
                             "'%s' is not a block device"),
                           disk->dst, mirror->path);
15757 15758
            goto endjob;
        }
15759 15760
    }

15761 15762
    if (!mirror->format) {
        if (!(flags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT)) {
15763 15764 15765
            mirror->format = disk->src->format;
        } else {
            /* If the user passed the REUSE_EXT flag, then either they
15766 15767 15768 15769
             * can also pass the RAW flag or use XML to tell us the format.
             * So if we get here, we assume it is safe for us to probe the
             * format from the file that we will be using.  */
            mirror->format = virStorageFileProbeFormat(mirror->path, cfg->user,
15770 15771 15772 15773 15774
                                                       cfg->group);
        }
    }

    /* pre-create the image file */
15775 15776 15777
    if (!(flags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT)) {
        int fd = qemuOpenFile(driver, vm, mirror->path,
                              O_WRONLY | O_TRUNC | O_CREAT,
15778 15779 15780 15781 15782
                              &need_unlink, NULL);
        if (fd < 0)
            goto endjob;
        VIR_FORCE_CLOSE(fd);
    }
15783

15784
    if (mirror->format > 0)
15785
        format = virStorageFileFormatTypeToString(mirror->format);
15786

15787
    if (virStorageSourceInitChainElement(mirror, disk->src, false) < 0)
15788 15789
        goto endjob;

15790
    if (qemuDomainPrepareDiskChainElement(driver, vm, mirror,
15791
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
15792
        qemuDomainPrepareDiskChainElement(driver, vm, mirror,
15793
                                          VIR_DISK_CHAIN_NO_ACCESS);
15794 15795 15796
        goto endjob;
    }

15797 15798
    /* Actually start the mirroring */
    qemuDomainObjEnterMonitor(driver, vm);
15799
    ret = qemuMonitorDriveMirror(priv->mon, device, mirror->path, format,
15800
                                 bandwidth, granularity, buf_size, flags);
15801
    virDomainAuditDisk(vm, NULL, mirror, "mirror", ret >= 0);
15802
    qemuDomainObjExitMonitor(driver, vm);
15803
    if (ret < 0) {
15804
        qemuDomainPrepareDiskChainElement(driver, vm, mirror,
15805
                                          VIR_DISK_CHAIN_NO_ACCESS);
15806 15807 15808 15809 15810 15811 15812
        goto endjob;
    }

    /* Update vm in place to match changes.  */
    need_unlink = false;
    disk->mirror = mirror;
    mirror = NULL;
E
Eric Blake 已提交
15813
    disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
15814

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

15819
 endjob:
15820 15821
    if (need_unlink && unlink(mirror->path))
        VIR_WARN("unable to unlink just-created %s", mirror->path);
15822
    virStorageSourceFree(mirror);
E
Eric Blake 已提交
15823
    if (!qemuDomainObjEndJob(driver, vm))
15824 15825
        vm = NULL;

15826
 cleanup:
15827 15828
    VIR_FREE(device);
    if (vm)
15829
        virObjectUnlock(vm);
15830
    virObjectUnref(cfg);
15831 15832 15833
    return ret;
}

15834
static int
15835 15836
qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
                      unsigned long bandwidth, unsigned int flags)
15837
{
15838
    virDomainObjPtr vm;
E
Eric Blake 已提交
15839
    int ret = -1;
15840
    unsigned long long speed = bandwidth;
15841
    virStorageSourcePtr dest = NULL;
15842

15843
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
15844
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
15845
                  VIR_DOMAIN_BLOCK_REBASE_COPY |
15846
                  VIR_DOMAIN_BLOCK_REBASE_COPY_RAW |
15847
                  VIR_DOMAIN_BLOCK_REBASE_RELATIVE |
15848 15849
                  VIR_DOMAIN_BLOCK_REBASE_COPY_DEV |
                  VIR_DOMAIN_BLOCK_REBASE_BANDWIDTH_BYTES, -1);
15850

15851 15852 15853
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

E
Eric Blake 已提交
15854 15855 15856 15857 15858 15859 15860
    if (virDomainBlockRebaseEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    /* For normal rebase (enhanced blockpull), the common code handles
     * everything, including vm cleanup. */
    if (!(flags & VIR_DOMAIN_BLOCK_REBASE_COPY))
        return qemuDomainBlockJobImpl(vm, dom->conn, path, base, bandwidth,
15861
                                      BLOCK_JOB_PULL, flags);
15862

E
Eric Blake 已提交
15863
    /* If we got here, we are doing a block copy rebase. */
15864 15865 15866 15867 15868 15869
    if (VIR_ALLOC(dest) < 0)
        goto cleanup;
    dest->type = (flags & VIR_DOMAIN_BLOCK_REBASE_COPY_DEV) ?
        VIR_STORAGE_TYPE_BLOCK : VIR_STORAGE_TYPE_FILE;
    if (VIR_STRDUP(dest->path, base) < 0)
        goto cleanup;
E
Eric Blake 已提交
15870
    if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
15871
        dest->format = VIR_STORAGE_FILE_RAW;
E
Eric Blake 已提交
15872

15873 15874 15875 15876 15877 15878 15879 15880 15881
    /* Convert bandwidth MiB to bytes, if necessary */
    if (!(flags & VIR_DOMAIN_BLOCK_REBASE_BANDWIDTH_BYTES)) {
        if (speed > LLONG_MAX >> 20) {
            virReportError(VIR_ERR_OVERFLOW,
                           _("bandwidth must be less than %llu"),
                           LLONG_MAX >> 20);
            goto cleanup;
        }
        speed <<= 20;
15882 15883
    }

E
Eric Blake 已提交
15884 15885 15886 15887 15888 15889 15890
    /* XXX: If we are doing a shallow copy but not reusing an external
     * file, we should attempt to pre-create the destination with a
     * relative backing chain instead of qemu's default of absolute */
    if (flags & VIR_DOMAIN_BLOCK_REBASE_RELATIVE) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Relative backing during copy not supported yet"));
        goto cleanup;
15891 15892
    }

15893 15894 15895
    /* We rely on the fact that VIR_DOMAIN_BLOCK_REBASE_SHALLOW
     * and VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT map to the same values
     * as for block copy. */
E
Eric Blake 已提交
15896
    flags &= (VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
15897 15898
              VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT);
    ret = qemuDomainBlockCopyCommon(vm, dom->conn, path, dest,
15899
                                    bandwidth, 0, 0, flags);
E
Eric Blake 已提交
15900
    vm = NULL;
15901 15902
    dest = NULL;

E
Eric Blake 已提交
15903 15904 15905
 cleanup:
    if (vm)
        virObjectUnlock(vm);
15906
    virStorageSourceFree(dest);
E
Eric Blake 已提交
15907
    return ret;
15908
}
15909

15910 15911 15912 15913 15914 15915 15916 15917 15918 15919 15920 15921 15922 15923 15924 15925 15926 15927 15928 15929 15930 15931 15932 15933 15934 15935 15936 15937 15938 15939 15940 15941 15942 15943 15944 15945 15946 15947 15948 15949 15950 15951 15952 15953 15954 15955 15956 15957 15958 15959 15960 15961 15962 15963 15964 15965 15966 15967 15968 15969 15970 15971 15972

static int
qemuDomainBlockCopy(virDomainPtr dom, const char *disk, const char *destxml,
                    virTypedParameterPtr params, int nparams,
                    unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    unsigned long long bandwidth = 0;
    unsigned int granularity = 0;
    unsigned long long buf_size = 0;
    virStorageSourcePtr dest = NULL;
    size_t i;

    virCheckFlags(VIR_DOMAIN_BLOCK_COPY_SHALLOW |
                  VIR_DOMAIN_BLOCK_COPY_REUSE_EXT, -1);
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLOCK_COPY_BANDWIDTH,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_BLOCK_COPY_GRANULARITY,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_BLOCK_COPY_BUF_SIZE,
                               VIR_TYPED_PARAM_ULLONG,
                               NULL) < 0)
        return -1;

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

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

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

        /* Typed params (wisely) refused to expose unsigned long, but
         * back-compat demands that we stick with a maximum of
         * unsigned long bandwidth in MiB/s, while our value is
         * unsigned long long in bytes/s.  Hence, we have to do
         * overflow detection if this is a 32-bit server handling a
         * 64-bit client.  */
        if (STREQ(param->field, VIR_DOMAIN_BLOCK_COPY_BANDWIDTH)) {
            if (sizeof(unsigned long) < sizeof(bandwidth) &&
                param->value.ul > ULONG_MAX * (1ULL << 20)) {
                virReportError(VIR_ERR_OVERFLOW,
                               _("bandwidth must be less than %llu bytes"),
                               ULONG_MAX * (1ULL << 20));
                goto cleanup;
            }
            bandwidth = param->value.ul;
        } else if (STREQ(param->field, VIR_DOMAIN_BLOCK_COPY_GRANULARITY)) {
            granularity = param->value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BLOCK_COPY_BUF_SIZE)) {
            buf_size = param->value.ul;
        }
    }

    if (!(dest = virDomainDiskDefSourceParse(destxml, vm->def, driver->xmlopt,
                                             VIR_DOMAIN_XML_INACTIVE)))
        goto cleanup;

    ret = qemuDomainBlockCopyCommon(vm, dom->conn, disk, dest,
15973
                                    bandwidth, granularity, buf_size, flags);
15974 15975 15976 15977 15978 15979 15980 15981 15982
    vm = NULL;

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


15983 15984 15985 15986
static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
                    unsigned int flags)
{
15987
    virDomainObjPtr vm;
15988
    virCheckFlags(VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES, -1);
15989 15990 15991 15992 15993 15994 15995 15996 15997

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

    if (virDomainBlockPullEnsureACL(dom->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

15998
    return qemuDomainBlockJobImpl(vm, dom->conn, path, NULL, bandwidth,
15999
                                  BLOCK_JOB_PULL, flags);
16000 16001
}

16002 16003

static int
16004 16005 16006 16007 16008
qemuDomainBlockCommit(virDomainPtr dom,
                      const char *path,
                      const char *base,
                      const char *top,
                      unsigned long bandwidth,
16009 16010
                      unsigned int flags)
{
16011
    virQEMUDriverPtr driver = dom->conn->privateData;
16012 16013 16014 16015 16016
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm = NULL;
    char *device = NULL;
    int ret = -1;
    int idx;
E
Eric Blake 已提交
16017
    virDomainDiskDefPtr disk = NULL;
16018
    virStorageSourcePtr topSource;
16019
    unsigned int topIndex = 0;
16020
    virStorageSourcePtr baseSource;
16021
    unsigned int baseIndex = 0;
16022
    virStorageSourcePtr top_parent = NULL;
E
Eric Blake 已提交
16023
    bool clean_access = false;
16024 16025 16026
    char *topPath = NULL;
    char *basePath = NULL;
    char *backingPath = NULL;
E
Eric Blake 已提交
16027
    virStorageSourcePtr mirror = NULL;
16028
    unsigned long long speed = bandwidth;
16029

E
Eric Blake 已提交
16030
    /* XXX Add support for COMMIT_DELETE */
16031
    virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW |
E
Eric Blake 已提交
16032
                  VIR_DOMAIN_BLOCK_COMMIT_ACTIVE |
16033 16034
                  VIR_DOMAIN_BLOCK_COMMIT_RELATIVE |
                  VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES, -1);
16035 16036 16037 16038 16039

    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
    priv = vm->privateData;

16040 16041 16042
    if (virDomainBlockCommitEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

16043 16044 16045 16046 16047 16048 16049 16050
    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;
    }
16051 16052 16053 16054
    /* Ensure that no one backports commit to RHEL 6.2, where cancel
     * behaved differently */
    if (!(virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCK_COMMIT) &&
          virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC))) {
16055 16056 16057 16058 16059
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("online commit not supported with this QEMU binary"));
        goto endjob;
    }

16060 16061 16062 16063 16064 16065 16066 16067 16068
    /* Convert bandwidth MiB to bytes, if necessary */
    if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES)) {
        if (speed > LLONG_MAX >> 20) {
            virReportError(VIR_ERR_OVERFLOW,
                           _("bandwidth must be less than %llu"),
                           LLONG_MAX >> 20);
            goto endjob;
        }
        speed <<= 20;
16069 16070
    }

16071 16072 16073 16074 16075
    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
        goto endjob;
    disk = vm->def->disks[idx];

16076
    if (!disk->src->path) {
16077 16078 16079 16080 16081
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk %s has no source file to be committed"),
                       disk->dst);
        goto endjob;
    }
16082
    if (qemuDomainDetermineDiskChain(driver, vm, disk, false, true) < 0)
16083
        goto endjob;
16084

16085
    if (!top)
16086
        topSource = disk->src;
16087
    else if (virStorageFileParseChainIndex(disk->dst, top, &topIndex) < 0 ||
16088
             !(topSource = virStorageFileChainLookup(disk->src, NULL,
16089 16090
                                                     top, topIndex,
                                                     &top_parent)))
16091
        goto endjob;
16092

16093
    if (topSource == disk->src) {
16094
        if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_ACTIVE_COMMIT)) {
16095 16096 16097 16098 16099 16100 16101 16102 16103 16104 16105
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("active commit not supported with this QEMU binary"));
            goto endjob;
        }
        /* XXX Should we auto-pivot when COMMIT_ACTIVE is not specified? */
        if (!(flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE)) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("commit of '%s' active layer requires active flag"),
                           disk->dst);
            goto endjob;
        }
E
Eric Blake 已提交
16106 16107 16108 16109 16110 16111
        if (disk->mirror) {
            virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                           _("disk '%s' already in active block job"),
                           disk->dst);
            goto endjob;
        }
16112 16113 16114 16115
    } else if (flags & VIR_DOMAIN_BLOCK_COMMIT_ACTIVE) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("active commit requested but '%s' is not active"),
                       topSource->path);
16116 16117 16118
        goto endjob;
    }

16119
    if (!topSource->backingStore) {
16120 16121
        virReportError(VIR_ERR_INVALID_ARG,
                       _("top '%s' in chain for '%s' has no backing file"),
16122
                       topSource->path, path);
16123 16124
        goto endjob;
    }
16125

16126
    if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW))
16127
        baseSource = topSource->backingStore;
16128
    else if (virStorageFileParseChainIndex(disk->dst, base, &baseIndex) < 0 ||
16129
             !(baseSource = virStorageFileChainLookup(disk->src, topSource,
16130
                                                      base, baseIndex, NULL)))
16131
        goto endjob;
16132

16133
    if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) &&
16134
        baseSource != topSource->backingStore) {
16135 16136 16137
        virReportError(VIR_ERR_INVALID_ARG,
                       _("base '%s' is not immediately below '%s' in chain "
                         "for '%s'"),
16138
                       base, topSource->path, path);
16139 16140
        goto endjob;
    }
16141

E
Eric Blake 已提交
16142 16143 16144 16145 16146 16147 16148 16149 16150 16151
    /* For an active commit, clone enough of the base to act as the mirror */
    if (topSource == disk->src) {
        if (!(mirror = virStorageSourceCopy(baseSource, false)))
            goto endjob;
        if (virStorageSourceInitChainElement(mirror,
                                             disk->src,
                                             false) < 0)
            goto endjob;
    }

16152 16153 16154 16155 16156 16157 16158
    /* 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 已提交
16159
    clean_access = true;
16160
    if (qemuDomainPrepareDiskChainElement(driver, vm, baseSource,
16161
                                          VIR_DISK_CHAIN_READ_WRITE) < 0 ||
16162
        (top_parent && top_parent != disk->src &&
16163
         qemuDomainPrepareDiskChainElement(driver, vm, top_parent,
16164
                                           VIR_DISK_CHAIN_READ_WRITE) < 0))
16165 16166
        goto endjob;

16167 16168 16169 16170 16171 16172 16173 16174 16175 16176 16177 16178 16179 16180 16181 16182 16183 16184 16185 16186 16187 16188 16189 16190 16191
    if (qemuGetDriveSourceString(topSource, NULL, &topPath) < 0)
        goto endjob;

    if (qemuGetDriveSourceString(baseSource, NULL, &basePath) < 0)
        goto endjob;

    if (flags & VIR_DOMAIN_BLOCK_COMMIT_RELATIVE &&
        topSource != disk->src) {
        if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CHANGE_BACKING_FILE)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("this qemu doesn't support relative blockpull"));
            goto endjob;
        }

        if (virStorageFileGetRelativeBackingPath(topSource, baseSource,
                                                 &backingPath) < 0)
            goto endjob;

        if (!backingPath) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("can't keep relative backing relationship"));
            goto endjob;
        }
    }

16192 16193 16194 16195
    /* Start the commit operation.  Pass the user's original spelling,
     * if any, through to qemu, since qemu may behave differently
     * depending on whether the input was specified as relative or
     * absolute (that is, our absolute top_canon may do the wrong
E
Eric Blake 已提交
16196 16197 16198 16199 16200 16201
     * thing if the user specified a relative name).  Be prepared for
     * a ready event to occur while locks are dropped.  */
    if (mirror) {
        disk->mirror = mirror;
        disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT;
    }
16202
    qemuDomainObjEnterMonitor(driver, vm);
16203
    ret = qemuMonitorBlockCommit(priv->mon, device,
16204
                                 topPath, basePath, backingPath,
16205
                                 speed);
16206 16207
    qemuDomainObjExitMonitor(driver, vm);

E
Eric Blake 已提交
16208 16209 16210 16211 16212 16213 16214 16215 16216 16217 16218 16219 16220 16221 16222
    if (mirror) {
        if (ret == 0) {
            virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);

            mirror = NULL;
            if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
                VIR_WARN("Unable to save status on vm %s after block job",
                         vm->def->name);
            virObjectUnref(cfg);
        } else {
            disk->mirror = NULL;
            disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
        }
    }

16223
 endjob:
E
Eric Blake 已提交
16224
    if (ret < 0 && clean_access) {
16225
        /* Revert access to read-only, if possible.  */
16226
        qemuDomainPrepareDiskChainElement(driver, vm, baseSource,
16227
                                          VIR_DISK_CHAIN_READ_ONLY);
16228
        if (top_parent && top_parent != disk->src)
16229
            qemuDomainPrepareDiskChainElement(driver, vm, top_parent,
16230
                                              VIR_DISK_CHAIN_READ_ONLY);
16231
    }
E
Eric Blake 已提交
16232
    virStorageSourceFree(mirror);
E
Eric Blake 已提交
16233
    if (!qemuDomainObjEndJob(driver, vm))
16234 16235
        vm = NULL;

16236
 cleanup:
16237 16238 16239
    VIR_FREE(topPath);
    VIR_FREE(basePath);
    VIR_FREE(backingPath);
16240 16241
    VIR_FREE(device);
    if (vm)
16242
        virObjectUnlock(vm);
16243 16244 16245
    return ret;
}

16246 16247 16248 16249 16250 16251
static int
qemuDomainOpenGraphics(virDomainPtr dom,
                       unsigned int idx,
                       int fd,
                       unsigned int flags)
{
16252
    virQEMUDriverPtr driver = dom->conn->privateData;
16253 16254 16255 16256 16257 16258 16259
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
    const char *protocol;

    virCheckFlags(VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH, -1);

16260 16261
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
16262

16263 16264 16265
    if (virDomainOpenGraphicsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

16266
    if (!virDomainObjIsActive(vm)) {
16267 16268
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
16269 16270 16271 16272 16273 16274
        goto cleanup;
    }

    priv = vm->privateData;

    if (idx >= vm->def->ngraphics) {
16275 16276
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No graphics backend with index %d"), idx);
16277 16278 16279 16280 16281 16282 16283 16284 16285 16286
        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:
16287 16288 16289
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can only open VNC or SPICE graphics backends, not %s"),
                       virDomainGraphicsTypeToString(vm->def->graphics[idx]->type));
16290 16291 16292
        goto cleanup;
    }

16293 16294 16295 16296
    if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def,
                                          fd) < 0)
        goto cleanup;

16297
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
16298
        goto cleanup;
16299
    qemuDomainObjEnterMonitor(driver, vm);
16300 16301
    ret = qemuMonitorOpenGraphics(priv->mon, protocol, fd, "graphicsfd",
                                  (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH) != 0);
16302
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
16303
    if (!qemuDomainObjEndJob(driver, vm))
16304 16305
        vm = NULL;

16306
 cleanup:
16307
    if (vm)
16308
        virObjectUnlock(vm);
16309 16310 16311
    return ret;
}

16312 16313 16314 16315 16316 16317 16318 16319 16320 16321 16322 16323 16324 16325 16326 16327 16328 16329 16330 16331 16332 16333 16334 16335 16336 16337 16338 16339 16340 16341 16342 16343 16344 16345 16346 16347 16348 16349 16350 16351 16352 16353 16354 16355 16356 16357 16358 16359 16360 16361 16362 16363 16364 16365 16366 16367 16368 16369 16370 16371
static int
qemuDomainOpenGraphicsFD(virDomainPtr dom,
                         unsigned int idx,
                         unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
    const char *protocol;
    int pair[2] = {-1, -1};

    virCheckFlags(VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH, -1);

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

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

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

    priv = vm->privateData;

    if (idx >= vm->def->ngraphics) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No graphics backend with index %d"), idx);
        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:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can only open VNC or SPICE graphics backends, not %s"),
                       virDomainGraphicsTypeToString(vm->def->graphics[idx]->type));
        goto cleanup;
    }

    if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0)
        goto cleanup;

    if (socketpair(PF_UNIX, SOCK_STREAM, 0, pair) < 0)
        goto cleanup;

    if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0)
        goto cleanup;

    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorOpenGraphics(priv->mon, protocol, pair[1], "graphicsfd",
16372
                                  (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH));
16373 16374 16375
    qemuDomainObjExitMonitor(driver, vm);
    if (!qemuDomainObjEndJob(driver, vm))
        vm = NULL;
16376 16377
    if (ret < 0)
        goto cleanup;
16378

16379 16380
    ret = pair[0];
    pair[0] = -1;
16381 16382

 cleanup:
16383 16384
    VIR_FORCE_CLOSE(pair[0]);
    VIR_FORCE_CLOSE(pair[1]);
16385 16386 16387 16388 16389
    if (vm)
        virObjectUnlock(vm);
    return ret;
}

16390 16391 16392 16393 16394 16395 16396
static int
qemuDomainSetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int nparams,
                         unsigned int flags)
{
16397
    virQEMUDriverPtr driver = dom->conn->privateData;
16398 16399 16400 16401
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo info;
E
Eric Blake 已提交
16402
    virDomainBlockIoTuneInfo *oldinfo;
16403
    char *device = NULL;
16404
    int ret = -1;
16405
    size_t i;
16406
    int idx = -1;
16407
    int conf_idx = -1;
E
Eric Blake 已提交
16408 16409
    bool set_bytes = false;
    bool set_iops = false;
16410
    virQEMUDriverConfigPtr cfg = NULL;
16411
    virCapsPtr caps = NULL;
16412 16413 16414 16415
    virObjectEventPtr event = NULL;
    virTypedParameterPtr eventParams = NULL;
    int eventNparams = 0;
    int eventMaxparams = 0;
16416 16417 16418

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
16419 16420 16421 16422 16423 16424 16425 16426 16427 16428 16429 16430 16431 16432
    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)
16433
        return -1;
16434 16435 16436

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

16437 16438 16439
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

16440 16441 16442
    if (virDomainSetBlockIoTuneEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

16443 16444
    cfg = virQEMUDriverGetConfig(driver);

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

16448
    priv = vm->privateData;
16449

16450
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
16451
        goto endjob;
16452

16453
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
16454
                                        &persistentDef) < 0)
16455 16456
        goto endjob;

16457
    if (virTypedParamsAddString(&eventParams, &eventNparams, &eventMaxparams,
16458
                                VIR_DOMAIN_TUNABLE_BLKDEV_DISK, disk) < 0)
16459 16460
        goto endjob;

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

16464 16465 16466 16467 16468 16469 16470
        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;
        }

16471 16472
        if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC)) {
            info.total_bytes_sec = param->value.ul;
E
Eric Blake 已提交
16473
            set_bytes = true;
16474 16475
            if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                        &eventMaxparams,
16476
                                        VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_BYTES_SEC,
16477 16478
                                        param->value.ul) < 0)
                goto endjob;
16479 16480 16481
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC)) {
            info.read_bytes_sec = param->value.ul;
E
Eric Blake 已提交
16482
            set_bytes = true;
16483 16484
            if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                        &eventMaxparams,
16485
                                        VIR_DOMAIN_TUNABLE_BLKDEV_READ_BYTES_SEC,
16486 16487
                                        param->value.ul) < 0)
                goto endjob;
16488 16489 16490
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC)) {
            info.write_bytes_sec = param->value.ul;
E
Eric Blake 已提交
16491
            set_bytes = true;
16492 16493
            if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                        &eventMaxparams,
16494
                                        VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_BYTES_SEC,
16495 16496
                                        param->value.ul) < 0)
                goto endjob;
16497 16498 16499
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC)) {
            info.total_iops_sec = param->value.ul;
E
Eric Blake 已提交
16500
            set_iops = true;
16501 16502
            if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                        &eventMaxparams,
16503
                                        VIR_DOMAIN_TUNABLE_BLKDEV_TOTAL_IOPS_SEC,
16504 16505
                                        param->value.ul) < 0)
                goto endjob;
16506 16507 16508
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC)) {
            info.read_iops_sec = param->value.ul;
E
Eric Blake 已提交
16509
            set_iops = true;
16510 16511
            if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                        &eventMaxparams,
16512
                                        VIR_DOMAIN_TUNABLE_BLKDEV_READ_IOPS_SEC,
16513 16514
                                        param->value.ul) < 0)
                goto endjob;
16515 16516 16517
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC)) {
            info.write_iops_sec = param->value.ul;
E
Eric Blake 已提交
16518
            set_iops = true;
16519 16520
            if (virTypedParamsAddULLong(&eventParams, &eventNparams,
                                        &eventMaxparams,
16521
                                        VIR_DOMAIN_TUNABLE_BLKDEV_WRITE_IOPS_SEC,
16522 16523
                                        param->value.ul) < 0)
                goto endjob;
16524 16525 16526 16527 16528
        }
    }

    if ((info.total_bytes_sec && info.read_bytes_sec) ||
        (info.total_bytes_sec && info.write_bytes_sec)) {
16529 16530
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of bytes_sec cannot be set at the same time"));
16531 16532 16533 16534 16535
        goto endjob;
    }

    if ((info.total_iops_sec && info.read_iops_sec) ||
        (info.total_iops_sec && info.write_iops_sec)) {
16536 16537
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of iops_sec cannot be set at the same time"));
16538 16539 16540
        goto endjob;
    }

16541 16542 16543 16544 16545 16546 16547 16548 16549
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if ((conf_idx = virDomainDiskIndexByName(persistentDef, disk, true)) < 0) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("missing persistent configuration for disk '%s'"),
                           disk);
            goto endjob;
        }
    }

16550
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
16551 16552 16553 16554 16555 16556 16557
        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;
        }

16558 16559 16560
        if (!(device = qemuDiskPathToAlias(vm, disk, &idx)))
            goto endjob;

E
Eric Blake 已提交
16561 16562 16563 16564 16565 16566 16567 16568 16569 16570 16571 16572 16573 16574
        /* 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;
        }
16575
        qemuDomainObjEnterMonitor(driver, vm);
16576
        ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
16577
        qemuDomainObjExitMonitor(driver, vm);
L
Lei Li 已提交
16578 16579
        if (ret < 0)
            goto endjob;
16580
        vm->def->disks[idx]->blkdeviotune = info;
16581 16582 16583 16584 16585 16586 16587

        ret = virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm);
        if (ret < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Saving live XML config failed"));
            goto endjob;
        }
16588 16589 16590 16591 16592 16593 16594

        if (eventNparams) {
            event = virDomainEventTunableNewFromDom(dom, eventParams, eventNparams);
            eventNparams = 0;
            if (event)
                qemuDomainEventQueue(driver, event);
        }
16595 16596 16597
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
16598
        sa_assert(persistentDef);
16599
        oldinfo = &persistentDef->disks[conf_idx]->blkdeviotune;
E
Eric Blake 已提交
16600 16601 16602 16603 16604 16605 16606 16607 16608 16609
        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;
        }
16610
        persistentDef->disks[conf_idx]->blkdeviotune = info;
16611
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
16612
        if (ret < 0) {
16613
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
16614 16615 16616 16617 16618
                           _("Write to config file failed"));
            goto endjob;
        }
    }

16619
 endjob:
16620
    if (!qemuDomainObjEndJob(driver, vm))
16621 16622
        vm = NULL;

16623
 cleanup:
16624 16625
    VIR_FREE(device);
    if (vm)
16626
        virObjectUnlock(vm);
16627 16628
    if (eventNparams)
        virTypedParamsFree(eventParams, eventNparams);
16629
    virObjectUnref(caps);
16630
    virObjectUnref(cfg);
16631 16632 16633 16634 16635 16636 16637 16638 16639 16640
    return ret;
}

static int
qemuDomainGetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int *nparams,
                         unsigned int flags)
{
16641
    virQEMUDriverPtr driver = dom->conn->privateData;
16642 16643 16644 16645
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo reply;
16646
    char *device = NULL;
16647
    int ret = -1;
16648
    size_t i;
16649
    virCapsPtr caps = NULL;
16650 16651 16652 16653 16654 16655 16656 16657

    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;

16658 16659
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
16660

16661 16662 16663
    if (virDomainGetBlockIoTuneEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

16667 16668 16669 16670 16671 16672 16673
    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;
    }

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

16677
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
16678
                                        &persistentDef) < 0)
16679 16680
        goto endjob;

16681 16682 16683 16684 16685
    device = qemuDiskPathToAlias(vm, disk, NULL);
    if (!device) {
        goto endjob;
    }

16686 16687
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        priv = vm->privateData;
16688
        qemuDomainObjEnterMonitor(driver, vm);
16689
        ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply);
16690
        qemuDomainObjExitMonitor(driver, vm);
16691 16692 16693 16694 16695
        if (ret < 0)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
16696 16697 16698 16699 16700
        int idx = virDomainDiskIndexByName(persistentDef, disk, true);
        if (idx < 0) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("disk '%s' was not found in the domain config"),
                           disk);
16701
            goto endjob;
16702
        }
16703 16704 16705 16706 16707 16708
        reply = persistentDef->disks[idx]->blkdeviotune;
    }

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

16709
        switch (i) {
16710
        case 0:
16711 16712 16713 16714
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_bytes_sec) < 0)
16715 16716 16717
                goto endjob;
            break;
        case 1:
16718 16719 16720 16721
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_bytes_sec) < 0)
16722 16723 16724
                goto endjob;
            break;
        case 2:
16725 16726 16727 16728
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_bytes_sec) < 0)
16729 16730 16731
                goto endjob;
            break;
        case 3:
16732 16733 16734 16735
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_iops_sec) < 0)
16736 16737 16738
                goto endjob;
            break;
        case 4:
16739 16740 16741 16742
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_iops_sec) < 0)
16743 16744 16745
                goto endjob;
            break;
        case 5:
16746 16747 16748 16749
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_iops_sec) < 0)
16750 16751
                goto endjob;
            break;
16752
        /* coverity[dead_error_begin] */
16753 16754 16755 16756 16757 16758 16759 16760 16761
        default:
            break;
        }
    }

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

16762
 endjob:
E
Eric Blake 已提交
16763
    if (!qemuDomainObjEndJob(driver, vm))
16764 16765
        vm = NULL;

16766
 cleanup:
16767 16768
    VIR_FREE(device);
    if (vm)
16769
        virObjectUnlock(vm);
16770
    virObjectUnref(caps);
16771 16772
    return ret;
}
16773

16774 16775 16776 16777 16778 16779
static int
qemuDomainGetDiskErrors(virDomainPtr dom,
                        virDomainDiskErrorPtr errors,
                        unsigned int nerrors,
                        unsigned int flags)
{
16780
    virQEMUDriverPtr driver = dom->conn->privateData;
16781 16782 16783 16784
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virHashTablePtr table = NULL;
    int ret = -1;
16785
    size_t i;
16786 16787 16788 16789
    int n = 0;

    virCheckFlags(0, -1);

16790
    if (!(vm = qemuDomObjFromDomain(dom)))
16791 16792 16793 16794
        goto cleanup;

    priv = vm->privateData;

16795 16796 16797
    if (virDomainGetDiskErrorsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

16798 16799 16800 16801
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
16802 16803
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
16804 16805 16806 16807 16808 16809 16810 16811 16812 16813 16814 16815 16816 16817 16818 16819 16820 16821 16822 16823 16824 16825 16826
        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;

16827
            if (VIR_STRDUP(errors[n].disk, disk->dst) < 0)
16828 16829 16830 16831 16832 16833 16834 16835
                goto endjob;
            errors[n].error = info->io_status;
            n++;
        }
    }

    ret = n;

16836
 endjob:
E
Eric Blake 已提交
16837
    if (!qemuDomainObjEndJob(driver, vm))
16838 16839
        vm = NULL;

16840
 cleanup:
16841
    if (vm)
16842
        virObjectUnlock(vm);
16843 16844 16845 16846 16847 16848 16849 16850
    virHashFree(table);
    if (ret < 0) {
        for (i = 0; i < n; i++)
            VIR_FREE(errors[i].disk);
    }
    return ret;
}

16851 16852 16853 16854
static int
qemuDomainSetMetadata(virDomainPtr dom,
                      int type,
                      const char *metadata,
16855 16856
                      const char *key,
                      const char *uri,
16857 16858
                      unsigned int flags)
{
16859
    virQEMUDriverPtr driver = dom->conn->privateData;
16860
    virDomainObjPtr vm;
16861
    virQEMUDriverConfigPtr cfg = NULL;
16862
    virCapsPtr caps = NULL;
16863
    int ret = -1;
16864 16865 16866 16867

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

16868
    if (!(vm = qemuDomObjFromDomain(dom)))
16869
        return -1;
16870

16871 16872
    cfg = virQEMUDriverGetConfig(driver);

16873 16874 16875
    if (virDomainSetMetadataEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

16879
    ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
16880 16881
                                  driver->xmlopt, cfg->stateDir,
                                  cfg->configDir, flags);
16882

16883
 cleanup:
16884
    virObjectUnlock(vm);
16885
    virObjectUnref(caps);
16886
    virObjectUnref(cfg);
16887 16888 16889 16890 16891 16892
    return ret;
}

static char *
qemuDomainGetMetadata(virDomainPtr dom,
                      int type,
16893
                      const char *uri,
16894 16895
                      unsigned int flags)
{
16896
    virQEMUDriverPtr driver = dom->conn->privateData;
16897
    virCapsPtr caps = NULL;
16898 16899 16900
    virDomainObjPtr vm;
    char *ret = NULL;

16901
    if (!(vm = qemuDomObjFromDomain(dom)))
16902
        return NULL;
16903

16904 16905 16906
    if (virDomainGetMetadataEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

16910
    ret = virDomainObjGetMetadata(vm, type, uri, caps, driver->xmlopt, flags);
16911

16912
 cleanup:
16913
    virObjectUnlock(vm);
16914
    virObjectUnref(caps);
16915 16916 16917
    return ret;
}

16918 16919 16920

static int
qemuDomainGetCPUStats(virDomainPtr domain,
16921 16922 16923 16924 16925
                      virTypedParameterPtr params,
                      unsigned int nparams,
                      int start_cpu,
                      unsigned int ncpus,
                      unsigned int flags)
16926 16927 16928 16929
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    bool isActive;
16930
    qemuDomainObjPrivatePtr priv;
16931 16932 16933

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

16934 16935
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
16936

16937 16938
    priv = vm->privateData;

16939 16940 16941
    if (virDomainGetCPUStatsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

16942 16943
    isActive = virDomainObjIsActive(vm);
    if (!isActive) {
16944 16945
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
16946 16947 16948
        goto cleanup;
    }

16949
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) {
16950 16951
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPUACCT controller is not mounted"));
16952 16953 16954 16955
        goto cleanup;
    }

    if (start_cpu == -1)
16956 16957
        ret = virCgroupGetDomainTotalCpuStats(priv->cgroup,
                                              params, nparams);
16958
    else
16959 16960
        ret = virCgroupGetPercpuStats(priv->cgroup, params, nparams,
                                      start_cpu, ncpus, priv->nvcpupids);
16961
 cleanup:
16962
    if (vm)
16963
        virObjectUnlock(vm);
16964 16965 16966
    return ret;
}

16967 16968 16969 16970 16971 16972
static int
qemuDomainPMSuspendForDuration(virDomainPtr dom,
                               unsigned int target,
                               unsigned long long duration,
                               unsigned int flags)
{
16973
    virQEMUDriverPtr driver = dom->conn->privateData;
16974 16975 16976 16977 16978 16979 16980
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    if (duration) {
16981 16982
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Duration not supported. Use 0 for now"));
16983 16984 16985 16986 16987 16988
        return -1;
    }

    if (!(target == VIR_NODE_SUSPEND_TARGET_MEM ||
          target == VIR_NODE_SUSPEND_TARGET_DISK ||
          target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
16989 16990 16991
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unknown suspend target: %u"),
                       target);
16992 16993 16994
        return -1;
    }

16995
    if (!(vm = qemuDomObjFromDomain(dom)))
16996 16997 16998 16999
        goto cleanup;

    priv = vm->privateData;

17000 17001 17002
    if (virDomainPMSuspendForDurationEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

17003
    if (!virDomainObjIsActive(vm)) {
17004 17005
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
17006 17007 17008
        goto cleanup;
    }

17009
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP) &&
17010 17011
        (target == VIR_NODE_SUSPEND_TARGET_MEM ||
         target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
17012 17013 17014
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Unable to suspend domain due to "
                         "missing system_wakeup monitor command"));
O
Osier Yang 已提交
17015
        goto cleanup;
17016 17017
    }

17018
    if (vm->def->pm.s3 || vm->def->pm.s4) {
J
Ján Tomko 已提交
17019
        if (vm->def->pm.s3 == VIR_TRISTATE_BOOL_NO &&
17020 17021 17022 17023 17024 17025 17026
            (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;
        }

J
Ján Tomko 已提交
17027
        if (vm->def->pm.s4 == VIR_TRISTATE_BOOL_NO &&
17028 17029 17030 17031 17032 17033 17034
            target == VIR_NODE_SUSPEND_TARGET_DISK) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("S4 state is disabled for this domain"));
            goto cleanup;
        }
    }

17035
    if (!qemuDomainAgentAvailable(priv, true))
17036 17037 17038 17039 17040 17041
        goto cleanup;

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

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

17047
    qemuDomainObjEnterAgent(vm);
17048
    ret = qemuAgentSuspend(priv->agent, target);
17049
    qemuDomainObjExitAgent(vm);
17050

17051
 endjob:
E
Eric Blake 已提交
17052
    if (!qemuDomainObjEndJob(driver, vm))
17053 17054
        vm = NULL;

17055
 cleanup:
17056
    if (vm)
17057
        virObjectUnlock(vm);
17058 17059 17060
    return ret;
}

17061 17062 17063 17064
static int
qemuDomainPMWakeup(virDomainPtr dom,
                   unsigned int flags)
{
17065
    virQEMUDriverPtr driver = dom->conn->privateData;
17066 17067 17068 17069 17070 17071
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

17072
    if (!(vm = qemuDomObjFromDomain(dom)))
17073 17074
        goto cleanup;

17075 17076 17077
    if (virDomainPMWakeupEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

17078 17079 17080 17081
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
17082 17083
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
17084 17085 17086 17087 17088
        goto endjob;
    }

    priv = vm->privateData;

17089
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP)) {
17090 17091 17092
       virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                      _("Unable to wake up domain due to "
                        "missing system_wakeup monitor command"));
17093 17094 17095 17096 17097 17098 17099
       goto endjob;
    }

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

17100
 endjob:
E
Eric Blake 已提交
17101
    if (!qemuDomainObjEndJob(driver, vm))
17102 17103
        vm = NULL;

17104
 cleanup:
17105
    if (vm)
17106
        virObjectUnlock(vm);
17107 17108 17109
    return ret;
}

17110
static int
17111 17112 17113
qemuConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
17114
{
17115
    virQEMUDriverPtr driver = conn->privateData;
17116 17117
    int ret = -1;

O
Osier Yang 已提交
17118
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
17119

17120 17121 17122
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        goto cleanup;

17123 17124
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
17125

17126
 cleanup:
17127 17128 17129
    return ret;
}

M
MATSUDA Daiki 已提交
17130
static char *
17131 17132 17133 17134
qemuDomainQemuAgentCommand(virDomainPtr domain,
                           const char *cmd,
                           int timeout,
                           unsigned int flags)
M
MATSUDA Daiki 已提交
17135
{
17136
    virQEMUDriverPtr driver = domain->conn->privateData;
M
MATSUDA Daiki 已提交
17137 17138 17139 17140 17141 17142 17143
    virDomainObjPtr vm;
    int ret = -1;
    char *result = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, NULL);

17144
    if (!(vm = qemuDomObjFromDomain(domain)))
M
MATSUDA Daiki 已提交
17145 17146 17147 17148
        goto cleanup;

    priv = vm->privateData;

17149 17150 17151
    if (virDomainQemuAgentCommandEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

M
MATSUDA Daiki 已提交
17152 17153 17154 17155 17156 17157
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

17158
    if (!qemuDomainAgentAvailable(priv, true))
M
MATSUDA Daiki 已提交
17159 17160 17161 17162 17163 17164 17165 17166 17167 17168 17169
        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;
    }

17170
    qemuDomainObjEnterAgent(vm);
M
MATSUDA Daiki 已提交
17171
    ret = qemuAgentArbitraryCommand(priv->agent, cmd, &result, timeout);
17172
    qemuDomainObjExitAgent(vm);
17173 17174
    if (ret < 0)
        VIR_FREE(result);
M
MATSUDA Daiki 已提交
17175

17176
 endjob:
E
Eric Blake 已提交
17177
    if (!qemuDomainObjEndJob(driver, vm))
M
MATSUDA Daiki 已提交
17178 17179
        vm = NULL;

17180
 cleanup:
M
MATSUDA Daiki 已提交
17181
    if (vm)
17182
        virObjectUnlock(vm);
M
MATSUDA Daiki 已提交
17183 17184 17185
    return result;
}

17186 17187 17188 17189 17190 17191 17192 17193 17194 17195 17196 17197 17198 17199 17200 17201 17202 17203 17204 17205 17206 17207 17208

static int
qemuConnectDomainQemuMonitorEventRegister(virConnectPtr conn,
                                          virDomainPtr dom,
                                          const char *event,
                                          virConnectDomainQemuMonitorEventCallback callback,
                                          void *opaque,
                                          virFreeCallback freecb,
                                          unsigned int flags)
{
    virQEMUDriverPtr driver = conn->privateData;
    int ret = -1;

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

    if (virDomainQemuMonitorEventStateRegisterID(conn,
                                                 driver->domainEventState,
                                                 dom, event, callback,
                                                 opaque, freecb, flags,
                                                 &ret) < 0)
        ret = -1;

17209
 cleanup:
17210 17211 17212 17213 17214 17215 17216 17217 17218 17219 17220 17221 17222 17223 17224 17225 17226 17227 17228 17229
    return ret;
}


static int
qemuConnectDomainQemuMonitorEventDeregister(virConnectPtr conn,
                                            int callbackID)
{
    virQEMUDriverPtr driver = conn->privateData;
    int ret = -1;

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

    if (virObjectEventStateDeregisterID(conn, driver->domainEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;

17230
 cleanup:
17231 17232 17233 17234
    return ret;
}


M
Michal Privoznik 已提交
17235 17236 17237 17238 17239 17240
static int
qemuDomainFSTrim(virDomainPtr dom,
                 const char *mountPoint,
                 unsigned long long minimum,
                 unsigned int flags)
{
17241
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Michal Privoznik 已提交
17242 17243 17244 17245 17246 17247 17248 17249 17250 17251 17252 17253 17254 17255 17256 17257 17258 17259
    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;

17260 17261 17262
    if (virDomainFSTrimEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

M
Michal Privoznik 已提交
17263 17264 17265 17266 17267 17268
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

17269
    if (!qemuDomainAgentAvailable(priv, true))
M
Michal Privoznik 已提交
17270 17271 17272 17273 17274 17275 17276 17277 17278 17279 17280
        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;
    }

17281
    qemuDomainObjEnterAgent(vm);
M
Michal Privoznik 已提交
17282
    ret = qemuAgentFSTrim(priv->agent, minimum);
17283
    qemuDomainObjExitAgent(vm);
M
Michal Privoznik 已提交
17284

17285
 endjob:
E
Eric Blake 已提交
17286
    if (!qemuDomainObjEndJob(driver, vm))
M
Michal Privoznik 已提交
17287 17288
        vm = NULL;

17289
 cleanup:
M
Michal Privoznik 已提交
17290
    if (vm)
17291
        virObjectUnlock(vm);
M
Michal Privoznik 已提交
17292 17293 17294
    return ret;
}

17295 17296

static int
17297
qemuNodeGetInfo(virConnectPtr conn,
17298 17299
                virNodeInfoPtr nodeinfo)
{
17300 17301 17302
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

17303 17304 17305 17306 17307
    return nodeGetInfo(nodeinfo);
}


static int
17308
qemuNodeGetCPUStats(virConnectPtr conn,
17309 17310 17311 17312 17313
                    int cpuNum,
                    virNodeCPUStatsPtr params,
                    int *nparams,
                    unsigned int flags)
{
17314 17315 17316
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

17317 17318 17319 17320 17321
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}


static int
17322
qemuNodeGetMemoryStats(virConnectPtr conn,
17323 17324 17325 17326 17327
                       int cellNum,
                       virNodeMemoryStatsPtr params,
                       int *nparams,
                       unsigned int flags)
{
17328 17329 17330
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

17331 17332 17333 17334 17335
    return nodeGetMemoryStats(cellNum, params, nparams, flags);
}


static int
17336
qemuNodeGetCellsFreeMemory(virConnectPtr conn,
17337 17338 17339 17340
                           unsigned long long *freeMems,
                           int startCell,
                           int maxCells)
{
17341 17342 17343
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

17344 17345 17346 17347 17348
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
17349
qemuNodeGetFreeMemory(virConnectPtr conn)
17350
{
17351 17352
    unsigned long long freeMem;

17353 17354 17355
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

17356 17357 17358 17359
    if (nodeGetMemory(NULL, &freeMem) < 0)
        return 0;

    return freeMem;
17360 17361 17362 17363
}


static int
17364
qemuNodeGetMemoryParameters(virConnectPtr conn,
17365 17366 17367 17368
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
17369 17370 17371
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

17372 17373 17374 17375 17376
    return nodeGetMemoryParameters(params, nparams, flags);
}


static int
17377
qemuNodeSetMemoryParameters(virConnectPtr conn,
17378 17379 17380 17381
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
17382 17383 17384
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

17385 17386 17387 17388 17389
    return nodeSetMemoryParameters(params, nparams, flags);
}


static int
17390
qemuNodeGetCPUMap(virConnectPtr conn,
17391 17392 17393 17394
                  unsigned char **cpumap,
                  unsigned int *online,
                  unsigned int flags)
{
17395 17396 17397
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

17398 17399 17400
    return nodeGetCPUMap(cpumap, online, flags);
}

17401 17402

static int
17403
qemuNodeSuspendForDuration(virConnectPtr conn,
17404 17405 17406 17407
                           unsigned int target,
                           unsigned long long duration,
                           unsigned int flags)
{
17408 17409 17410
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

17411 17412 17413
    return nodeSuspendForDuration(target, duration, flags);
}

17414 17415 17416 17417 17418 17419 17420 17421 17422 17423 17424 17425 17426
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);
}

17427 17428 17429 17430 17431 17432 17433 17434 17435 17436 17437 17438 17439 17440 17441 17442 17443 17444 17445 17446 17447 17448 17449 17450 17451 17452 17453 17454 17455 17456 17457 17458 17459 17460 17461 17462 17463 17464 17465 17466 17467 17468 17469 17470 17471 17472 17473 17474 17475 17476 17477 17478 17479 17480 17481 17482 17483 17484 17485 17486 17487 17488
static int
qemuDomainGetTime(virDomainPtr dom,
                  long long *seconds,
                  unsigned int *nseconds,
                  unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;
    int rv;

    virCheckFlags(0, ret);

    if (!(vm = qemuDomObjFromDomain(dom)))
        return ret;

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

    priv = vm->privateData;

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

    if (!qemuDomainAgentAvailable(priv, true))
        goto endjob;

    qemuDomainObjEnterAgent(vm);
    rv = qemuAgentGetTime(priv->agent, seconds, nseconds);
    qemuDomainObjExitAgent(vm);

    if (rv < 0)
        goto endjob;

    ret = 0;

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

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

static int
qemuDomainSetTime(virDomainPtr dom,
                  long long seconds,
                  unsigned int nseconds,
                  unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
E
Eric Blake 已提交
17489
    bool rtcSync = flags & VIR_DOMAIN_TIME_SYNC;
17490 17491 17492 17493 17494 17495 17496 17497 17498 17499 17500 17501 17502 17503 17504 17505 17506 17507 17508 17509 17510 17511
    int ret = -1;
    int rv;

    virCheckFlags(VIR_DOMAIN_TIME_SYNC, ret);

    if (!(vm = qemuDomObjFromDomain(dom)))
        return ret;

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

    priv = vm->privateData;

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

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

17512 17513 17514 17515 17516 17517 17518
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_RTC_RESET_REINJECTION)) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot set time: qemu doesn't support "
                         "rtc-reset-reinjection command"));
        goto endjob;
    }

17519 17520 17521 17522
    if (!qemuDomainAgentAvailable(priv, true))
        goto endjob;

    qemuDomainObjEnterAgent(vm);
E
Eric Blake 已提交
17523
    rv = qemuAgentSetTime(priv->agent, seconds, nseconds, rtcSync);
17524 17525
    qemuDomainObjExitAgent(vm);

17526 17527 17528
    if (rv < 0)
        goto endjob;

17529 17530 17531 17532 17533 17534 17535 17536 17537 17538
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto endjob;
    }

    qemuDomainObjEnterMonitor(driver, vm);
    rv = qemuMonitorRTCResetReinjection(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

17539 17540 17541 17542 17543 17544 17545 17546 17547 17548 17549 17550 17551 17552 17553
    if (rv < 0)
        goto endjob;

    ret = 0;

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

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

17554

17555 17556 17557 17558 17559 17560 17561 17562 17563 17564 17565 17566 17567 17568 17569 17570 17571 17572 17573 17574 17575 17576 17577 17578 17579 17580 17581
static int
qemuDomainFSFreeze(virDomainPtr dom,
                   const char **mountpoints,
                   unsigned int nmountpoints,
                   unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

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

    if (virDomainFSFreezeEnsureACL(dom->conn, vm->def) < 0)
        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;
    }

17582
    ret = qemuDomainSnapshotFSFreeze(driver, vm, mountpoints, nmountpoints);
17583 17584 17585 17586 17587 17588 17589 17590 17591 17592 17593 17594 17595 17596 17597 17598 17599 17600 17601 17602 17603 17604 17605 17606 17607 17608 17609 17610 17611 17612 17613 17614 17615 17616 17617 17618 17619 17620 17621 17622 17623 17624 17625 17626 17627 17628 17629 17630 17631 17632 17633 17634 17635 17636 17637 17638 17639 17640 17641 17642 17643 17644
    if (ret == -2) {
        qemuDomainSnapshotFSThaw(driver, vm, false);
        ret = -1;
    }

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

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


static int
qemuDomainFSThaw(virDomainPtr dom,
                 const char **mountpoints,
                 unsigned int nmountpoints,
                 unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    if (mountpoints || nmountpoints) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("specifying mountpoints is not supported"));
        return ret;
    }

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

    if (virDomainFSThawEnsureACL(dom->conn, vm->def) < 0)
        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;
    }

    ret = qemuDomainSnapshotFSThaw(driver, vm, true);

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

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


17645 17646 17647 17648 17649 17650 17651 17652 17653 17654 17655 17656 17657 17658 17659 17660 17661 17662
static int
qemuNodeGetFreePages(virConnectPtr conn,
                     unsigned int npages,
                     unsigned int *pages,
                     int startCell,
                     unsigned int cellCount,
                     unsigned long long *counts,
                     unsigned int flags)
{
    virCheckFlags(0, -1);

    if (virNodeGetFreePagesEnsureACL(conn) < 0)
        return -1;

    return nodeGetFreePages(npages, pages, startCell, cellCount, counts);
}


17663 17664 17665 17666 17667 17668 17669 17670 17671 17672 17673 17674 17675
static char *
qemuConnectGetDomainCapabilities(virConnectPtr conn,
                                 const char *emulatorbin,
                                 const char *arch_str,
                                 const char *machine,
                                 const char *virttype_str,
                                 unsigned int flags)
{
    char *ret = NULL;
    virQEMUDriverPtr driver = conn->privateData;
    virQEMUCapsPtr qemuCaps = NULL;
    int virttype; /* virDomainVirtType */
    virDomainCapsPtr domCaps = NULL;
17676
    int arch = virArchFromHost(); /* virArch */
17677
    virQEMUDriverConfigPtr cfg = NULL;
17678 17679 17680 17681 17682 17683

    virCheckFlags(0, ret);

    if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0)
        return ret;

17684 17685
    cfg = virQEMUDriverGetConfig(driver);

17686 17687 17688 17689 17690 17691 17692
    if (qemuHostdevHostSupportsPassthroughLegacy())
        virttype = VIR_DOMAIN_VIRT_KVM;
    else
        virttype = VIR_DOMAIN_VIRT_QEMU;

    if (virttype_str &&
        (virttype = virDomainVirtTypeFromString(virttype_str)) < 0) {
17693 17694 17695 17696 17697 17698 17699 17700 17701 17702 17703 17704 17705 17706 17707 17708 17709 17710 17711 17712 17713 17714 17715 17716 17717 17718 17719 17720 17721 17722
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown virttype: %s"),
                       virttype_str);
        goto cleanup;
    }

    if (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown architecture: %s"),
                       arch_str);
        goto cleanup;
    }

    if (emulatorbin) {
        virArch arch_from_caps;

        if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache,
                                                emulatorbin)))
            goto cleanup;

        arch_from_caps = virQEMUCapsGetArch(qemuCaps);

        if (arch_from_caps != arch) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("architecture from emulator '%s' doesn't "
                             "match given architecture '%s'"),
                           virArchToString(arch_from_caps),
                           virArchToString(arch));
            goto cleanup;
        }
17723
    } else {
17724
        if (!(qemuCaps = virQEMUCapsCacheLookupByArch(driver->qemuCapsCache,
17725 17726 17727 17728
                                                      arch))) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("unable to find any emulator to serve '%s' "
                             "architecture"), virArchToString(arch));
17729
            goto cleanup;
17730
        }
17731

17732
        emulatorbin = virQEMUCapsGetBinary(qemuCaps);
17733 17734 17735 17736 17737 17738 17739 17740 17741 17742 17743 17744 17745 17746 17747 17748 17749 17750 17751
    }

    if (machine) {
        /* Turn @machine into canonical name */
        machine = virQEMUCapsGetCanonicalMachine(qemuCaps, machine);

        if (!virQEMUCapsIsMachineSupported(qemuCaps, machine)) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("the machine '%s' is not supported by emulator '%s'"),
                           machine, emulatorbin);
            goto cleanup;
        }
    } else {
        machine = virQEMUCapsGetDefaultMachine(qemuCaps);
    }

    if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
        goto cleanup;

17752 17753
    if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps,
                                  cfg->loader, cfg->nloader) < 0)
17754
        goto cleanup;
17755 17756 17757

    ret = virDomainCapsFormat(domCaps);
 cleanup:
17758
    virObjectUnref(cfg);
17759 17760 17761 17762 17763 17764
    virObjectUnref(domCaps);
    virObjectUnref(qemuCaps);
    return ret;
}


17765
static int
17766 17767
qemuDomainGetStatsState(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
                        virDomainObjPtr dom,
17768 17769 17770 17771 17772 17773 17774 17775 17776 17777 17778 17779 17780 17781 17782 17783 17784 17785 17786 17787 17788 17789
                        virDomainStatsRecordPtr record,
                        int *maxparams,
                        unsigned int privflags ATTRIBUTE_UNUSED)
{
    if (virTypedParamsAddInt(&record->params,
                             &record->nparams,
                             maxparams,
                             "state.state",
                             dom->state.state) < 0)
        return -1;

    if (virTypedParamsAddInt(&record->params,
                             &record->nparams,
                             maxparams,
                             "state.reason",
                             dom->state.reason) < 0)
        return -1;

    return 0;
}


17790 17791 17792 17793 17794 17795 17796 17797 17798
typedef enum {
    QEMU_DOMAIN_STATS_HAVE_JOB = (1 << 0), /* job is entered, monitor can be
                                              accessed */
} qemuDomainStatsFlags;


#define HAVE_JOB(flags) ((flags) & QEMU_DOMAIN_STATS_HAVE_JOB)


17799 17800 17801 17802 17803 17804 17805 17806 17807 17808 17809 17810 17811 17812 17813 17814 17815 17816 17817 17818 17819 17820 17821 17822 17823 17824 17825 17826 17827 17828 17829 17830 17831 17832 17833 17834 17835 17836 17837 17838 17839
static int
qemuDomainGetStatsCpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
                      virDomainObjPtr dom,
                      virDomainStatsRecordPtr record,
                      int *maxparams,
                      unsigned int privflags ATTRIBUTE_UNUSED)
{
    qemuDomainObjPrivatePtr priv = dom->privateData;
    unsigned long long cpu_time = 0;
    unsigned long long user_time = 0;
    unsigned long long sys_time = 0;
    int err = 0;

    if (!priv->cgroup)
        return 0;

    err = virCgroupGetCpuacctUsage(priv->cgroup, &cpu_time);
    if (!err && virTypedParamsAddULLong(&record->params,
                                        &record->nparams,
                                        maxparams,
                                        "cpu.time",
                                        cpu_time) < 0)
        return -1;

    err = virCgroupGetCpuacctStat(priv->cgroup, &user_time, &sys_time);
    if (!err && virTypedParamsAddULLong(&record->params,
                                        &record->nparams,
                                        maxparams,
                                        "cpu.user",
                                        user_time) < 0)
        return -1;
    if (!err && virTypedParamsAddULLong(&record->params,
                                        &record->nparams,
                                        maxparams,
                                        "cpu.system",
                                        sys_time) < 0)
        return -1;

    return 0;
}

17840 17841 17842 17843 17844 17845 17846 17847 17848 17849 17850 17851 17852 17853 17854 17855 17856 17857 17858 17859 17860 17861 17862 17863 17864 17865 17866 17867 17868 17869 17870 17871 17872 17873 17874 17875
static int
qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
                          virDomainObjPtr dom,
                          virDomainStatsRecordPtr record,
                          int *maxparams,
                          unsigned int privflags ATTRIBUTE_UNUSED)
{
    qemuDomainObjPrivatePtr priv = dom->privateData;
    unsigned long long cur_balloon = 0;
    int err = 0;

    if (dom->def->memballoon &&
        dom->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE) {
        cur_balloon = dom->def->mem.max_balloon;
    } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) {
        cur_balloon = dom->def->mem.cur_balloon;
    } else {
        err = -1;
    }

    if (!err && virTypedParamsAddULLong(&record->params,
                                        &record->nparams,
                                        maxparams,
                                        "balloon.current",
                                        cur_balloon) < 0)
        return -1;

    if (virTypedParamsAddULLong(&record->params,
                                &record->nparams,
                                maxparams,
                                "balloon.maximum",
                                dom->def->mem.max_balloon) < 0)
        return -1;

    return 0;
}
17876

17877 17878 17879 17880 17881 17882 17883 17884 17885 17886 17887 17888 17889 17890 17891 17892 17893 17894 17895 17896 17897 17898 17899 17900 17901 17902 17903 17904 17905 17906 17907 17908 17909 17910 17911 17912 17913 17914 17915 17916 17917 17918 17919 17920 17921 17922 17923 17924 17925 17926 17927 17928 17929 17930 17931 17932 17933 17934 17935 17936 17937 17938 17939 17940 17941 17942 17943 17944

static int
qemuDomainGetStatsVcpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
                       virDomainObjPtr dom,
                       virDomainStatsRecordPtr record,
                       int *maxparams,
                       unsigned int privflags ATTRIBUTE_UNUSED)
{
    size_t i;
    int ret = -1;
    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
    virVcpuInfoPtr cpuinfo = NULL;

    if (virTypedParamsAddUInt(&record->params,
                              &record->nparams,
                              maxparams,
                              "vcpu.current",
                              (unsigned) dom->def->vcpus) < 0)
        return -1;

    if (virTypedParamsAddUInt(&record->params,
                              &record->nparams,
                              maxparams,
                              "vcpu.maximum",
                              (unsigned) dom->def->maxvcpus) < 0)
        return -1;

    if (VIR_ALLOC_N(cpuinfo, dom->def->vcpus) < 0)
        return -1;

    if (qemuDomainHelperGetVcpus(dom, cpuinfo, dom->def->vcpus,
                                 NULL, 0) < 0) {
        virResetLastError();
        ret = 0; /* it's ok to be silent and go ahead */
        goto cleanup;
    }

    for (i = 0; i < dom->def->vcpus; i++) {
        snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
                 "vcpu.%zu.state", i);
        if (virTypedParamsAddInt(&record->params,
                                 &record->nparams,
                                 maxparams,
                                 param_name,
                                 cpuinfo[i].state) < 0)
            goto cleanup;

        /* stats below are available only if the VM is alive */
        if (!virDomainObjIsActive(dom))
            continue;

        snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
                 "vcpu.%zu.time", i);
        if (virTypedParamsAddULLong(&record->params,
                                    &record->nparams,
                                    maxparams,
                                    param_name,
                                    cpuinfo[i].cpuTime) < 0)
            goto cleanup;
    }

    ret = 0;

 cleanup:
    VIR_FREE(cpuinfo);
    return ret;
}

17945 17946 17947 17948 17949 17950 17951 17952 17953 17954 17955 17956 17957 17958 17959 17960 17961 17962 17963 17964 17965 17966 17967 17968 17969 17970 17971 17972 17973 17974 17975 17976 17977 17978 17979 17980 17981 17982 17983 17984 17985 17986 17987 17988 17989 17990 17991 17992 17993 17994 17995 17996 17997 17998 17999 18000 18001 18002 18003 18004 18005 18006 18007 18008 18009 18010 18011 18012 18013 18014 18015 18016 18017 18018 18019 18020 18021 18022 18023 18024 18025 18026 18027 18028 18029 18030 18031 18032 18033 18034 18035
#define QEMU_ADD_COUNT_PARAM(record, maxparams, type, count) \
do { \
    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "%s.count", type); \
    if (virTypedParamsAddUInt(&(record)->params, \
                              &(record)->nparams, \
                              maxparams, \
                              param_name, \
                              count) < 0) \
        return -1; \
} while (0)

#define QEMU_ADD_NAME_PARAM(record, maxparams, type, num, name) \
do { \
    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
             "%s.%zu.name", type, num); \
    if (virTypedParamsAddString(&(record)->params, \
                                &(record)->nparams, \
                                maxparams, \
                                param_name, \
                                name) < 0) \
        return -1; \
} while (0)

#define QEMU_ADD_NET_PARAM(record, maxparams, num, name, value) \
do { \
    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
             "net.%zu.%s", num, name); \
    if (value >= 0 && virTypedParamsAddULLong(&(record)->params, \
                                              &(record)->nparams, \
                                              maxparams, \
                                              param_name, \
                                              value) < 0) \
        return -1; \
} while (0)

static int
qemuDomainGetStatsInterface(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
                            virDomainObjPtr dom,
                            virDomainStatsRecordPtr record,
                            int *maxparams,
                            unsigned int privflags ATTRIBUTE_UNUSED)
{
    size_t i;
    struct _virDomainInterfaceStats tmp;

    if (!virDomainObjIsActive(dom))
        return 0;

    QEMU_ADD_COUNT_PARAM(record, maxparams, "net", dom->def->nnets);

    /* Check the path is one of the domain's network interfaces. */
    for (i = 0; i < dom->def->nnets; i++) {
        if (!dom->def->nets[i]->ifname)
            continue;

        memset(&tmp, 0, sizeof(tmp));

        QEMU_ADD_NAME_PARAM(record, maxparams,
                            "net", i, dom->def->nets[i]->ifname);

        if (virNetInterfaceStats(dom->def->nets[i]->ifname, &tmp) < 0) {
            virResetLastError();
            continue;
        }

        QEMU_ADD_NET_PARAM(record, maxparams, i,
                           "rx.bytes", tmp.rx_bytes);
        QEMU_ADD_NET_PARAM(record, maxparams, i,
                           "rx.pkts", tmp.rx_packets);
        QEMU_ADD_NET_PARAM(record, maxparams, i,
                           "rx.errs", tmp.rx_errs);
        QEMU_ADD_NET_PARAM(record, maxparams, i,
                           "rx.drop", tmp.rx_drop);
        QEMU_ADD_NET_PARAM(record, maxparams, i,
                           "tx.bytes", tmp.tx_bytes);
        QEMU_ADD_NET_PARAM(record, maxparams, i,
                           "tx.pkts", tmp.tx_packets);
        QEMU_ADD_NET_PARAM(record, maxparams, i,
                           "tx.errs", tmp.tx_errs);
        QEMU_ADD_NET_PARAM(record, maxparams, i,
                           "tx.drop", tmp.tx_drop);
    }

    return 0;
}

#undef QEMU_ADD_NET_PARAM

18036 18037 18038 18039 18040 18041 18042 18043 18044 18045 18046 18047 18048 18049
/* expects a LL, but typed parameter must be ULL */
#define QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, num, name, value) \
do { \
    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
             "block.%zu.%s", num, name); \
    if (value >= 0 && virTypedParamsAddULLong(&(record)->params, \
                                              &(record)->nparams, \
                                              maxparams, \
                                              param_name, \
                                              value) < 0) \
        goto cleanup; \
} while (0)

18050 18051 18052 18053 18054 18055 18056 18057 18058 18059 18060 18061 18062
#define QEMU_ADD_BLOCK_PARAM_ULL(record, maxparams, num, name, value) \
do { \
    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH]; \
    snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
             "block.%zu.%s", num, name); \
    if (virTypedParamsAddULLong(&(record)->params, \
                                &(record)->nparams, \
                                maxparams, \
                                param_name, \
                                value) < 0) \
        goto cleanup; \
} while (0)

18063 18064 18065 18066 18067 18068 18069 18070 18071
static int
qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
                        virDomainObjPtr dom,
                        virDomainStatsRecordPtr record,
                        int *maxparams,
                        unsigned int privflags)
{
    size_t i;
    int ret = -1;
18072 18073
    int rc;
    virHashTablePtr stats = NULL;
18074 18075 18076 18077 18078 18079
    qemuDomainObjPrivatePtr priv = dom->privateData;

    if (!HAVE_JOB(privflags) || !virDomainObjIsActive(dom))
        return 0; /* it's ok, just go ahead silently */

    qemuDomainObjEnterMonitor(driver, dom);
18080
    rc = qemuMonitorGetAllBlockStatsInfo(priv->mon, &stats);
18081
    ignore_value(qemuMonitorBlockStatsUpdateCapacity(priv->mon, stats));
18082 18083
    qemuDomainObjExitMonitor(driver, dom);

18084
    if (rc < 0) {
18085 18086 18087 18088 18089 18090 18091
        virResetLastError();
        ret = 0; /* still ok, again go ahead silently */
        goto cleanup;
    }

    QEMU_ADD_COUNT_PARAM(record, maxparams, "block", dom->def->ndisks);

18092 18093 18094 18095 18096 18097 18098 18099 18100
    for (i = 0; i < dom->def->ndisks; i++) {
        qemuBlockStats *entry;
        virDomainDiskDefPtr disk = dom->def->disks[i];

        QEMU_ADD_NAME_PARAM(record, maxparams, "block", i, disk->dst);

        if (!disk->info.alias ||
            !(entry = virHashLookup(stats, disk->info.alias)))
            continue;
18101 18102

        QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
18103
                                "rd.reqs", entry->rd_req);
18104
        QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
18105
                                "rd.bytes", entry->rd_bytes);
18106
        QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
18107
                                "rd.times", entry->rd_total_times);
18108
        QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
18109
                                "wr.reqs", entry->wr_req);
18110
        QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
18111
                                "wr.bytes", entry->wr_bytes);
18112
        QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
18113
                                "wr.times", entry->wr_total_times);
18114
        QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
18115
                                "fl.reqs", entry->flush_req);
18116
        QEMU_ADD_BLOCK_PARAM_LL(record, maxparams, i,
18117
                                "fl.times", entry->flush_total_times);
18118 18119 18120 18121 18122 18123 18124 18125 18126 18127 18128

        QEMU_ADD_BLOCK_PARAM_ULL(record, maxparams, i,
                                 "allocation", entry->wr_highest_offset);

        if (entry->capacity)
            QEMU_ADD_BLOCK_PARAM_ULL(record, maxparams, i,
                                     "capacity", entry->capacity);
        if (entry->physical)
            QEMU_ADD_BLOCK_PARAM_ULL(record, maxparams, i,
                                     "physical", entry->physical);

18129 18130 18131 18132 18133
    }

    ret = 0;

 cleanup:
18134
    virHashFree(stats);
18135 18136 18137 18138 18139
    return ret;
}

#undef QEMU_ADD_BLOCK_PARAM_LL

18140 18141
#undef QEMU_ADD_BLOCK_PARAM_ULL

18142 18143 18144
#undef QEMU_ADD_NAME_PARAM

#undef QEMU_ADD_COUNT_PARAM
18145

18146
typedef int
18147 18148
(*qemuDomainGetStatsFunc)(virQEMUDriverPtr driver,
                          virDomainObjPtr dom,
18149 18150 18151 18152 18153 18154 18155
                          virDomainStatsRecordPtr record,
                          int *maxparams,
                          unsigned int flags);

struct qemuDomainGetStatsWorker {
    qemuDomainGetStatsFunc func;
    unsigned int stats;
18156
    bool monitor;
18157 18158 18159
};

static struct qemuDomainGetStatsWorker qemuDomainGetStatsWorkers[] = {
18160
    { qemuDomainGetStatsState, VIR_DOMAIN_STATS_STATE, false },
18161
    { qemuDomainGetStatsCpu, VIR_DOMAIN_STATS_CPU_TOTAL, false },
18162
    { qemuDomainGetStatsBalloon, VIR_DOMAIN_STATS_BALLOON, true },
18163
    { qemuDomainGetStatsVcpu, VIR_DOMAIN_STATS_VCPU, false },
18164
    { qemuDomainGetStatsInterface, VIR_DOMAIN_STATS_INTERFACE, false },
18165
    { qemuDomainGetStatsBlock, VIR_DOMAIN_STATS_BLOCK, true },
18166
    { NULL, 0, false }
18167 18168 18169 18170 18171 18172 18173 18174 18175 18176 18177 18178 18179 18180 18181 18182 18183 18184 18185 18186 18187 18188 18189 18190 18191 18192 18193 18194 18195 18196 18197
};


static int
qemuDomainGetStatsCheckSupport(unsigned int *stats,
                               bool enforce)
{
    unsigned int supportedstats = 0;
    size_t i;

    for (i = 0; qemuDomainGetStatsWorkers[i].func; i++)
        supportedstats |= qemuDomainGetStatsWorkers[i].stats;

    if (*stats == 0) {
        *stats = supportedstats;
        return 0;
    }

    if (enforce &&
        *stats & ~supportedstats) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                       _("Stats types bits 0x%x are not supported by this daemon"),
                       *stats & ~supportedstats);
        return -1;
    }

    *stats &= supportedstats;
    return 0;
}


18198 18199 18200 18201 18202 18203 18204 18205 18206 18207 18208 18209 18210 18211
static bool
qemuDomainGetStatsNeedMonitor(unsigned int stats)
{
    size_t i;

    for (i = 0; qemuDomainGetStatsWorkers[i].func; i++)
        if (stats & qemuDomainGetStatsWorkers[i].stats &&
            qemuDomainGetStatsWorkers[i].monitor)
            return true;

    return false;
}


18212 18213 18214 18215 18216 18217 18218 18219 18220 18221 18222 18223 18224 18225 18226 18227 18228
static int
qemuDomainGetStats(virConnectPtr conn,
                   virDomainObjPtr dom,
                   unsigned int stats,
                   virDomainStatsRecordPtr *record,
                   unsigned int flags)
{
    int maxparams = 0;
    virDomainStatsRecordPtr tmp;
    size_t i;
    int ret = -1;

    if (VIR_ALLOC(tmp) < 0)
        goto cleanup;

    for (i = 0; qemuDomainGetStatsWorkers[i].func; i++) {
        if (stats & qemuDomainGetStatsWorkers[i].stats) {
18229 18230
            if (qemuDomainGetStatsWorkers[i].func(conn->privateData, dom, tmp,
                                                  &maxparams, flags) < 0)
18231 18232 18233 18234 18235 18236 18237 18238 18239 18240 18241 18242 18243 18244 18245 18246 18247 18248 18249 18250 18251 18252 18253 18254 18255 18256 18257 18258 18259 18260 18261 18262 18263 18264 18265 18266 18267 18268
                goto cleanup;
        }
    }

    if (!(tmp->dom = virGetDomain(conn, dom->def->name, dom->def->uuid)))
        goto cleanup;

    *record = tmp;
    tmp = NULL;
    ret = 0;

 cleanup:
    if (tmp) {
        virTypedParamsFree(tmp->params, tmp->nparams);
        VIR_FREE(tmp);
    }

    return ret;
}


static int
qemuConnectGetAllDomainStats(virConnectPtr conn,
                             virDomainPtr *doms,
                             unsigned int ndoms,
                             unsigned int stats,
                             virDomainStatsRecordPtr **retStats,
                             unsigned int flags)
{
    virQEMUDriverPtr driver = conn->privateData;
    virDomainPtr *domlist = NULL;
    virDomainObjPtr dom = NULL;
    virDomainStatsRecordPtr *tmpstats = NULL;
    bool enforce = !!(flags & VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS);
    int ntempdoms;
    int nstats = 0;
    size_t i;
    int ret = -1;
18269 18270
    unsigned int privflags = 0;
    unsigned int domflags = 0;
18271 18272 18273 18274 18275 18276 18277 18278 18279 18280 18281 18282 18283 18284 18285 18286 18287 18288 18289 18290 18291 18292 18293 18294 18295 18296 18297 18298 18299 18300 18301 18302 18303 18304

    if (ndoms)
        virCheckFlags(VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS, -1);
    else
        virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
                      VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
                      VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE |
                      VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS, -1);

    if (virConnectGetAllDomainStatsEnsureACL(conn) < 0)
        return -1;

    if (qemuDomainGetStatsCheckSupport(&stats, enforce) < 0)
        return -1;

    if (!ndoms) {
        unsigned int lflags = flags & (VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
                                       VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
                                       VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE);

        if ((ntempdoms = virDomainObjListExport(driver->domains,
                                                conn,
                                                &domlist,
                                                virConnectGetAllDomainStatsCheckACL,
                                                lflags)) < 0)
            goto cleanup;

        ndoms = ntempdoms;
        doms = domlist;
    }

    if (VIR_ALLOC_N(tmpstats, ndoms + 1) < 0)
        goto cleanup;

18305 18306 18307
    if (qemuDomainGetStatsNeedMonitor(stats))
        privflags |= QEMU_DOMAIN_STATS_HAVE_JOB;

18308
    for (i = 0; i < ndoms; i++) {
18309
        domflags = privflags;
18310 18311 18312 18313 18314
        virDomainStatsRecordPtr tmp = NULL;

        if (!(dom = qemuDomObjFromDomain(doms[i])))
            continue;

18315
        if (doms != domlist &&
18316 18317 18318
            !virConnectGetAllDomainStatsCheckACL(conn, dom->def))
            continue;

18319 18320 18321 18322 18323 18324 18325
        if (HAVE_JOB(domflags) &&
            qemuDomainObjBeginJob(driver, dom, QEMU_JOB_QUERY) < 0)
            /* As it was never requested. Gather as much as possible anyway. */
            domflags &= ~QEMU_DOMAIN_STATS_HAVE_JOB;

        if (qemuDomainGetStats(conn, dom, stats, &tmp, domflags) < 0)
            goto endjob;
18326 18327 18328 18329

        if (tmp)
            tmpstats[nstats++] = tmp;

18330 18331 18332 18333 18334
        if (HAVE_JOB(domflags) && !qemuDomainObjEndJob(driver, dom)) {
            dom = NULL;
            continue;
        }

18335 18336 18337 18338 18339 18340 18341 18342 18343
        virObjectUnlock(dom);
        dom = NULL;
    }

    *retStats = tmpstats;
    tmpstats = NULL;

    ret = nstats;

18344 18345 18346 18347 18348
 endjob:
    if (HAVE_JOB(domflags) && dom)
        if (!qemuDomainObjEndJob(driver, dom))
            dom = NULL;

18349 18350 18351 18352 18353 18354 18355 18356 18357 18358 18359
 cleanup:
    if (dom)
        virObjectUnlock(dom);

    virDomainStatsRecordListFree(tmpstats);
    virDomainListFree(domlist);

    return ret;
}


18360 18361 18362 18363 18364 18365 18366 18367 18368 18369 18370 18371 18372 18373 18374 18375 18376 18377 18378 18379 18380
static int
qemuNodeAllocPages(virConnectPtr conn,
                   unsigned int npages,
                   unsigned int *pageSizes,
                   unsigned long long *pageCounts,
                   int startCell,
                   unsigned int cellCount,
                   unsigned int flags)
{
    bool add = !(flags & VIR_NODE_ALLOC_PAGES_SET);

    virCheckFlags(VIR_NODE_ALLOC_PAGES_SET, -1);

    if (virNodeAllocPagesEnsureACL(conn) < 0)
        return -1;

    return nodeAllocPages(npages, pageSizes, pageCounts,
                          startCell, cellCount, add);
}


18381
static virDriver qemuDriver = {
18382
    .no = VIR_DRV_QEMU,
18383
    .name = QEMU_DRIVER_NAME,
18384 18385 18386 18387 18388
    .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 */
18389
    .connectGetHostname = qemuConnectGetHostname, /* 0.3.3 */
18390 18391
    .connectGetSysinfo = qemuConnectGetSysinfo, /* 0.8.8 */
    .connectGetMaxVcpus = qemuConnectGetMaxVcpus, /* 0.2.1 */
18392
    .nodeGetInfo = qemuNodeGetInfo, /* 0.2.0 */
18393 18394 18395 18396 18397
    .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 */
18398 18399 18400 18401 18402
    .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 */
18403
    .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
18404
    .domainShutdownFlags = qemuDomainShutdownFlags, /* 0.9.10 */
18405
    .domainReboot = qemuDomainReboot, /* 0.9.3 */
18406
    .domainReset = qemuDomainReset, /* 0.9.7 */
18407 18408
    .domainDestroy = qemuDomainDestroy, /* 0.2.0 */
    .domainDestroyFlags = qemuDomainDestroyFlags, /* 0.9.4 */
18409
    .domainGetOSType = qemuDomainGetOSType, /* 0.2.2 */
18410
    .domainGetMaxMemory = qemuDomainGetMaxMemory, /* 0.4.2 */
18411 18412 18413
    .domainSetMaxMemory = qemuDomainSetMaxMemory, /* 0.4.2 */
    .domainSetMemory = qemuDomainSetMemory, /* 0.4.2 */
    .domainSetMemoryFlags = qemuDomainSetMemoryFlags, /* 0.9.0 */
18414 18415
    .domainSetMemoryParameters = qemuDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */
18416
    .domainSetMemoryStatsPeriod = qemuDomainSetMemoryStatsPeriod, /* 1.1.1 */
18417 18418
    .domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */
    .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */
18419
    .domainGetInfo = qemuDomainGetInfo, /* 0.2.0 */
18420
    .domainGetState = qemuDomainGetState, /* 0.9.2 */
18421
    .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */
18422 18423
    .domainSave = qemuDomainSave, /* 0.2.0 */
    .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */
18424
    .domainRestore = qemuDomainRestore, /* 0.2.0 */
18425
    .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */
18426 18427
    .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */
    .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */
18428
    .domainCoreDump = qemuDomainCoreDump, /* 0.7.0 */
18429
    .domainCoreDumpWithFormat = qemuDomainCoreDumpWithFormat, /* 1.2.3 */
18430
    .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */
18431 18432
    .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */
    .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */
18433 18434 18435 18436 18437 18438 18439 18440 18441
    .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 已提交
18442
    .domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
18443
    .nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */
18444
    .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */
18445 18446 18447 18448 18449 18450 18451
    .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 */
18452
    .domainUndefine = qemuDomainUndefine, /* 0.2.0 */
18453
    .domainUndefineFlags = qemuDomainUndefineFlags, /* 0.9.4 */
18454 18455 18456 18457 18458
    .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 */
18459 18460
    .domainGetAutostart = qemuDomainGetAutostart, /* 0.2.1 */
    .domainSetAutostart = qemuDomainSetAutostart, /* 0.2.1 */
18461 18462 18463 18464 18465
    .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 */
18466
    .domainMigratePerform = qemuDomainMigratePerform, /* 0.5.0 */
18467
    .domainBlockResize = qemuDomainBlockResize, /* 0.9.8 */
18468 18469
    .domainBlockStats = qemuDomainBlockStats, /* 0.4.1 */
    .domainBlockStatsFlags = qemuDomainBlockStatsFlags, /* 0.9.5 */
18470 18471 18472 18473
    .domainInterfaceStats = qemuDomainInterfaceStats, /* 0.4.1 */
    .domainMemoryStats = qemuDomainMemoryStats, /* 0.7.5 */
    .domainBlockPeek = qemuDomainBlockPeek, /* 0.4.4 */
    .domainMemoryPeek = qemuDomainMemoryPeek, /* 0.4.4 */
18474
    .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
18475 18476 18477 18478
    .nodeGetCPUStats = qemuNodeGetCPUStats, /* 0.9.3 */
    .nodeGetMemoryStats = qemuNodeGetMemoryStats, /* 0.9.3 */
    .nodeGetCellsFreeMemory = qemuNodeGetCellsFreeMemory, /* 0.4.4 */
    .nodeGetFreeMemory = qemuNodeGetFreeMemory, /* 0.4.4 */
18479 18480
    .connectDomainEventRegister = qemuConnectDomainEventRegister, /* 0.5.0 */
    .connectDomainEventDeregister = qemuConnectDomainEventDeregister, /* 0.5.0 */
18481 18482 18483
    .domainMigratePrepare2 = qemuDomainMigratePrepare2, /* 0.5.0 */
    .domainMigrateFinish2 = qemuDomainMigrateFinish2, /* 0.5.0 */
    .nodeDeviceDettach = qemuNodeDeviceDettach, /* 0.6.1 */
18484
    .nodeDeviceDetachFlags = qemuNodeDeviceDetachFlags, /* 1.0.5 */
18485 18486 18487
    .nodeDeviceReAttach = qemuNodeDeviceReAttach, /* 0.6.1 */
    .nodeDeviceReset = qemuNodeDeviceReset, /* 0.6.1 */
    .domainMigratePrepareTunnel = qemuDomainMigratePrepareTunnel, /* 0.7.2 */
18488 18489
    .connectIsEncrypted = qemuConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = qemuConnectIsSecure, /* 0.7.3 */
18490 18491 18492
    .domainIsActive = qemuDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = qemuDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = qemuDomainIsUpdated, /* 0.8.6 */
18493 18494
    .connectCompareCPU = qemuConnectCompareCPU, /* 0.7.5 */
    .connectBaselineCPU = qemuConnectBaselineCPU, /* 0.7.7 */
18495
    .domainGetJobInfo = qemuDomainGetJobInfo, /* 0.7.7 */
18496
    .domainGetJobStats = qemuDomainGetJobStats, /* 1.0.3 */
18497 18498
    .domainAbortJob = qemuDomainAbortJob, /* 0.7.7 */
    .domainMigrateSetMaxDowntime = qemuDomainMigrateSetMaxDowntime, /* 0.8.0 */
18499 18500
    .domainMigrateGetCompressionCache = qemuDomainMigrateGetCompressionCache, /* 1.0.3 */
    .domainMigrateSetCompressionCache = qemuDomainMigrateSetCompressionCache, /* 1.0.3 */
18501
    .domainMigrateSetMaxSpeed = qemuDomainMigrateSetMaxSpeed, /* 0.9.0 */
18502
    .domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
18503 18504
    .connectDomainEventRegisterAny = qemuConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = qemuConnectDomainEventDeregisterAny, /* 0.8.0 */
18505 18506 18507 18508 18509 18510 18511
    .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 */
18512
    .domainListAllSnapshots = qemuDomainListAllSnapshots, /* 0.9.13 */
18513 18514
    .domainSnapshotNumChildren = qemuDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = qemuDomainSnapshotListChildrenNames, /* 0.9.7 */
18515
    .domainSnapshotListAllChildren = qemuDomainSnapshotListAllChildren, /* 0.9.13 */
18516 18517
    .domainSnapshotLookupByName = qemuDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = qemuDomainHasCurrentSnapshot, /* 0.8.0 */
18518
    .domainSnapshotGetParent = qemuDomainSnapshotGetParent, /* 0.9.7 */
18519
    .domainSnapshotCurrent = qemuDomainSnapshotCurrent, /* 0.8.0 */
18520 18521
    .domainSnapshotIsCurrent = qemuDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = qemuDomainSnapshotHasMetadata, /* 0.9.13 */
18522 18523
    .domainRevertToSnapshot = qemuDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = qemuDomainSnapshotDelete, /* 0.8.0 */
18524 18525 18526
    .domainQemuMonitorCommand = qemuDomainQemuMonitorCommand, /* 0.8.3 */
    .domainQemuAttach = qemuDomainQemuAttach, /* 0.9.4 */
    .domainQemuAgentCommand = qemuDomainQemuAgentCommand, /* 0.10.0 */
18527 18528
    .connectDomainQemuMonitorEventRegister = qemuConnectDomainQemuMonitorEventRegister, /* 1.2.3 */
    .connectDomainQemuMonitorEventDeregister = qemuConnectDomainQemuMonitorEventDeregister, /* 1.2.3 */
18529
    .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */
18530
    .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */
18531
    .domainOpenGraphicsFD = qemuDomainOpenGraphicsFD, /* 1.2.8 */
18532
    .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */
18533 18534 18535 18536 18537 18538
    .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 */
18539
    .domainSendKey = qemuDomainSendKey, /* 0.9.4 */
18540 18541 18542 18543
    .domainBlockJobAbort = qemuDomainBlockJobAbort, /* 0.9.4 */
    .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
    .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
    .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
18544
    .domainBlockRebase = qemuDomainBlockRebase, /* 0.9.10 */
18545
    .domainBlockCopy = qemuDomainBlockCopy, /* 1.2.9 */
18546
    .domainBlockCommit = qemuDomainBlockCommit, /* 1.0.0 */
18547
    .connectIsAlive = qemuConnectIsAlive, /* 0.9.8 */
18548
    .nodeSuspendForDuration = qemuNodeSuspendForDuration, /* 0.9.8 */
18549 18550
    .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
    .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
18551 18552
    .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */
    .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
18553 18554
    .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
    .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
18555
    .domainGetDiskErrors = qemuDomainGetDiskErrors, /* 0.9.10 */
18556 18557
    .domainSetMetadata = qemuDomainSetMetadata, /* 0.9.10 */
    .domainGetMetadata = qemuDomainGetMetadata, /* 0.9.10 */
18558
    .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
18559
    .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
18560
    .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
18561 18562 18563
    .nodeGetMemoryParameters = qemuNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = qemuNodeSetMemoryParameters, /* 0.10.2 */
    .nodeGetCPUMap = qemuNodeGetCPUMap, /* 1.0.0 */
M
Michal Privoznik 已提交
18564
    .domainFSTrim = qemuDomainFSTrim, /* 1.0.1 */
18565
    .domainOpenChannel = qemuDomainOpenChannel, /* 1.0.2 */
18566 18567 18568 18569 18570 18571
    .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 */
18572
    .connectGetCPUModelNames = qemuConnectGetCPUModelNames, /* 1.1.3 */
18573 18574
    .domainFSFreeze = qemuDomainFSFreeze, /* 1.2.5 */
    .domainFSThaw = qemuDomainFSThaw, /* 1.2.5 */
18575 18576
    .domainGetTime = qemuDomainGetTime, /* 1.2.5 */
    .domainSetTime = qemuDomainSetTime, /* 1.2.5 */
18577
    .nodeGetFreePages = qemuNodeGetFreePages, /* 1.2.6 */
18578
    .connectGetDomainCapabilities = qemuConnectGetDomainCapabilities, /* 1.2.7 */
18579
    .connectGetAllDomainStats = qemuConnectGetAllDomainStats, /* 1.2.8 */
18580
    .nodeAllocPages = qemuNodeAllocPages, /* 1.2.9 */
18581 18582 18583
};


18584
static virStateDriver qemuStateDriver = {
C
Chunyan Liu 已提交
18585
    .name = QEMU_DRIVER_NAME,
18586
    .stateInitialize = qemuStateInitialize,
18587
    .stateAutoStart = qemuStateAutoStart,
18588 18589 18590
    .stateCleanup = qemuStateCleanup,
    .stateReload = qemuStateReload,
    .stateStop = qemuStateStop,
18591
};
18592

18593 18594
int qemuRegister(void)
{
18595 18596 18597 18598
    if (virRegisterDriver(&qemuDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&qemuStateDriver) < 0)
        return -1;
18599 18600
    return 0;
}