qemu_driver.c 482.4 KB
Newer Older
D
Daniel P. Berrange 已提交
1
/*
2
 * qemu_driver.c: core driver methods for managing qemu guests
D
Daniel P. Berrange 已提交
3
 *
4
 * Copyright (C) 2006-2013 Red Hat, Inc.
D
Daniel P. Berrange 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
D
Daniel P. Berrange 已提交
20 21 22 23
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

24
#include <config.h>
25

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

47

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

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

97 98
#define VIR_FROM_THIS VIR_FROM_QEMU

99 100
#define QEMU_DRIVER_NAME "QEMU"

101 102
#define QEMU_NB_MEM_PARAM  3

103 104
#define QEMU_NB_BLOCK_IO_TUNE_PARAM  6

105 106
#define QEMU_NB_NUMA_PARAM 2

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

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

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

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

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

133
#define QEMU_NB_BLKIO_PARAM  2
134

135 136
#define QEMU_NB_BANDWIDTH_PARAM 6

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

139
static int qemuShutdown(void);
140

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

146
static int qemuDomainGetMaxVcpus(virDomainPtr dom);
147

148 149
static int qemuDomainManagedSaveLoad(virDomainObjPtr vm,
                                     void *opaque);
150 151


152
virQEMUDriverPtr qemu_driver = NULL;
153 154


155
static void
156
qemuVMDriverLock(void) {}
157
static void
158
qemuVMDriverUnlock(void) {}
159 160 161

static int
qemuVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
162
                    virDomainObjListIterator iter, void *data)
163
{
164
    return virDomainObjListForEach(qemu_driver->domains, iter, data);
165 166 167 168 169 170 171 172 173 174
}

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


175
struct qemuAutostartData {
176
    virQEMUDriverPtr driver;
177 178
    virConnectPtr conn;
};
179

180

181
/**
182
 * qemuDomObjFromDomain:
183 184
 * @domain: Domain pointer that has to be looked up
 *
185 186
 * This function looks up @domain and returns the appropriate
 * virDomainObjPtr.
187
 *
188 189
 * Returns the domain object which is locked on success, NULL
 * otherwise.
190
 */
191
static virDomainObjPtr
192
qemuDomObjFromDomain(virDomainPtr domain)
193 194
{
    virDomainObjPtr vm;
195
    virQEMUDriverPtr driver = domain->conn->privateData;
196 197
    char uuidstr[VIR_UUID_STRING_BUFLEN];

198
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
199 200 201 202
    if (!vm) {
        virUUIDFormat(domain->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
203
        return NULL;
204 205
    }

206 207
    return vm;
}
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

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

243 244
static int
qemuAutostartDomain(virDomainObjPtr vm,
245
                    void *opaque)
246 247
{
    struct qemuAutostartData *data = opaque;
248
    virErrorPtr err;
249
    int flags = 0;
250
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(data->driver);
251
    int ret = -1;
252

253
    if (cfg->autoStartBypassCache)
254
        flags |= VIR_DOMAIN_START_BYPASS_CACHE;
255

256
    virObjectLock(vm);
257
    virResetLastError();
258 259
    if (vm->autostart &&
        !virDomainObjIsActive(vm)) {
260 261
        if (qemuDomainObjBeginJob(data->driver, vm,
                                  QEMU_JOB_MODIFY) < 0) {
262 263 264 265 266 267 268 269
            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) {
270
            err = virGetLastError();
271
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
272
                      vm->def->name,
273
                      err ? err->message : _("unknown error"));
274
        }
275

276
        if (qemuDomainObjEndJob(data->driver, vm) == 0)
277
            vm = NULL;
278
    }
279

280
    ret = 0;
281
cleanup:
282
    if (vm)
283
        virObjectUnlock(vm);
284
    virObjectUnref(cfg);
285
    return ret;
286 287
}

288

289
static void
290
qemuAutostartDomains(virQEMUDriverPtr driver)
291
{
292
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
293 294 295 296 297
    /* 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
     */
298
    virConnectPtr conn = virConnectOpen(cfg->uri);
299
    /* Ignoring NULL conn which is mostly harmless here */
300
    struct qemuAutostartData data = { driver, conn };
301

302
    virDomainObjListForEach(driver->domains, qemuAutostartDomain, &data);
303

304 305
    if (conn)
        virConnectClose(conn);
306
    virObjectUnref(cfg);
307 308
}

309
static int
310
qemuSecurityInit(virQEMUDriverPtr driver)
311
{
312
    char **names;
313 314
    virSecurityManagerPtr mgr = NULL;
    virSecurityManagerPtr stack = NULL;
315
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
316

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

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

368
    driver->securityManager = stack;
369
    virObjectUnref(cfg);
370
    return 0;
371

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

380

381 382
static int
qemuDomainSnapshotLoad(virDomainObjPtr vm,
383
                       void *data)
384
{
385 386 387 388 389 390 391
    char *baseDir = (char *)data;
    char *snapDir = NULL;
    DIR *dir = NULL;
    struct dirent *entry;
    char *xmlStr;
    char *fullpath;
    virDomainSnapshotDefPtr def = NULL;
392
    virDomainSnapshotObjPtr snap = NULL;
393
    virDomainSnapshotObjPtr current = NULL;
394
    char ebuf[1024];
395
    unsigned int flags = (VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE |
396
                          VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
397
                          VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL);
398
    int ret = -1;
399
    virCapsPtr caps = NULL;
400

401
    virObjectLock(vm);
402 403 404
    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);
405
        goto cleanup;
406 407
    }

408 409 410
    if (!(caps = virQEMUDriverGetCapabilities(qemu_driver, false)))
        goto cleanup;

411 412
    VIR_INFO("Scanning for snapshots for domain %s in %s", vm->def->name,
             snapDir);
413

414 415 416 417 418
    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)));
419
        goto cleanup;
420 421
    }

422 423 424
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.')
            continue;
425

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

430
        if (virAsprintf(&fullpath, "%s/%s", snapDir, entry->d_name) < 0) {
431
            VIR_ERROR(_("Failed to allocate memory for path"));
432 433
            continue;
        }
434

435
        if (virFileReadAll(fullpath, 1024*1024*1, &xmlStr) < 0) {
436 437 438 439 440 441
            /* 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;
        }
442

443
        def = virDomainSnapshotDefParseString(xmlStr, caps,
444
                                              qemu_driver->xmlopt,
445 446
                                              QEMU_EXPECTED_VIRT_TYPES,
                                              flags);
447 448
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
449 450
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
                      fullpath);
451 452 453 454
            VIR_FREE(fullpath);
            VIR_FREE(xmlStr);
            continue;
        }
455

456
        snap = virDomainSnapshotAssignDef(vm->snapshots, def);
457 458
        if (snap == NULL) {
            virDomainSnapshotDefFree(def);
459 460 461 462
        } else if (snap->def->current) {
            current = snap;
            if (!vm->current_snapshot)
                vm->current_snapshot = snap;
463
        }
464

465 466
        VIR_FREE(fullpath);
        VIR_FREE(xmlStr);
467 468
    }

469 470 471 472 473 474
    if (vm->current_snapshot != current) {
        VIR_ERROR(_("Too many snapshots claiming to be current for domain %s"),
                  vm->def->name);
        vm->current_snapshot = NULL;
    }

475
    if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0)
476 477 478
        VIR_ERROR(_("Snapshots have inconsistent relations for domain %s"),
                  vm->def->name);

479 480 481 482 483 484 485 486
    /* 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.
     */
487

488
    virResetLastError();
489

490
    ret = 0;
491 492 493 494
cleanup:
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
495
    virObjectUnref(caps);
496
    virObjectUnlock(vm);
497
    return ret;
498 499
}

500

501 502
static int
qemuDomainNetsRestart(virDomainObjPtr vm,
503
                      void *data ATTRIBUTE_UNUSED)
504
{
505 506 507
    int i;
    virDomainDefPtr def = vm->def;

508
    virObjectLock(vm);
509 510 511 512 513 514 515 516

    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,
517
                                                                 &net->mac,
518 519 520 521 522 523 524
                                                                 virDomainNetGetActualDirectDev(net),
                                                                 def->uuid,
                                                                 virDomainNetGetActualVirtPortProfile(net),
                                                                 VIR_NETDEV_VPORT_PROFILE_OP_CREATE));
        }
    }

525
    virObjectUnlock(vm);
526
    return 0;
527 528
}

529

530 531
static int
qemuDomainFindMaxID(virDomainObjPtr vm,
532 533 534 535 536 537
                    void *data)
{
    int *driver_maxid = data;

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

    return 0;
540 541 542
}


543
/**
544
 * qemuStartup:
545 546 547
 *
 * Initialization function for the QEmu daemon
 */
548
static int
549 550 551 552
qemuStartup(bool privileged,
            virStateInhibitCallback callback,
            void *opaque)
{
553 554 555
    char *driverConf = NULL;
    int rc;
    virConnectPtr conn = NULL;
556
    char ebuf[1024];
557 558
    char *membase = NULL;
    char *mempath = NULL;
559
    virQEMUDriverConfigPtr cfg;
560 561
    uid_t run_uid = -1;
    gid_t run_gid = -1;
562

563 564
    if (VIR_ALLOC(qemu_driver) < 0)
        return -1;
565

566
    if (virMutexInit(&qemu_driver->lock) < 0) {
567
        VIR_ERROR(_("cannot initialize mutex"));
568 569
        VIR_FREE(qemu_driver);
        return -1;
570
    }
571

572 573
    qemu_driver->inhibitCallback = callback;
    qemu_driver->inhibitOpaque = opaque;
574

575 576
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;
577

578 579
    if (!(qemu_driver->domains = virDomainObjListNew()))
        goto error;
580

581
    /* Init domain events */
582
    qemu_driver->domainEventState = virDomainEventStateNew();
583
    if (!qemu_driver->domainEventState)
584
        goto error;
585

586 587 588
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();
589

590 591
    if (!(qemu_driver->config = cfg = virQEMUDriverConfigNew(privileged)))
        goto error;
592

593 594
    if (virAsprintf(&driverConf, "%s/qemu.conf", cfg->configBaseDir) < 0)
        goto out_of_memory;
595

596 597 598
    if (virQEMUDriverConfigLoadFile(cfg, driverConf) < 0)
        goto error;
    VIR_FREE(driverConf);
H
Hu Tao 已提交
599

600
    if (virFileMakePath(cfg->stateDir) < 0) {
601
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
602
                  cfg->stateDir, virStrerror(errno, ebuf, sizeof(ebuf)));
603
        goto error;
H
Hu Tao 已提交
604
    }
605
    if (virFileMakePath(cfg->libDir) < 0) {
606
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
607
                  cfg->libDir, virStrerror(errno, ebuf, sizeof(ebuf)));
608 609
        goto error;
    }
610
    if (virFileMakePath(cfg->cacheDir) < 0) {
611
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
612
                  cfg->cacheDir, virStrerror(errno, ebuf, sizeof(ebuf)));
613 614
        goto error;
    }
615
    if (virFileMakePath(cfg->saveDir) < 0) {
616
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
617
                  cfg->saveDir, virStrerror(errno, ebuf, sizeof(ebuf)));
618 619
        goto error;
    }
620
    if (virFileMakePath(cfg->snapshotDir) < 0) {
621
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
622
                  cfg->snapshotDir, virStrerror(errno, ebuf, sizeof(ebuf)));
623 624
        goto error;
    }
625
    if (virFileMakePath(cfg->autoDumpPath) < 0) {
626
        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
627
                  cfg->autoDumpPath, virStrerror(errno, ebuf, sizeof(ebuf)));
628
        goto error;
629 630
    }

631 632 633
    rc = virCgroupForDriver("qemu", &qemu_driver->cgroup, privileged, 1);
    if (rc < 0) {
        VIR_INFO("Unable to create cgroup for driver: %s",
634
                 virStrerror(-rc, ebuf, sizeof(ebuf)));
635 636
    }

637 638 639
    qemu_driver->qemuImgBinary = virFindFileInPath("kvm-img");
    if (!qemu_driver->qemuImgBinary)
        qemu_driver->qemuImgBinary = virFindFileInPath("qemu-img");
640 641 642 643 644 645 646

    if (!(qemu_driver->lockManager =
          virLockManagerPluginNew(cfg->lockManagerName ?
                                  cfg->lockManagerName : "nop",
                                  "qemu",
                                  cfg->configBaseDir,
                                  0)))
647
        goto error;
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663

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

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

665 666 667
    /* Allocate bitmap for remote display port reservations. We cannot
     * do this before the config is loaded properly, since the port
     * numbers are configurable now */
668
    if ((qemu_driver->remotePorts =
669 670
         virPortAllocatorNew(cfg->remotePortMin,
                             cfg->remotePortMax)) == NULL)
671 672
        goto error;

673 674
    if (qemuSecurityInit(qemu_driver) < 0)
        goto error;
675

676
    if ((qemu_driver->activePciHostdevs = virPCIDeviceListNew()) == NULL)
677
        goto error;
678

679
    if ((qemu_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL)
680 681
        goto error;

682
    if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
683 684
        goto error;

685
    if (!(qemu_driver->sharedDisks = virHashCreate(30, qemuSharedDiskEntryFree)))
686 687
        goto error;

688
    if (privileged) {
689
        if (chown(cfg->libDir, cfg->user, cfg->group) < 0) {
690 691
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to user %d:%d"),
692
                                 cfg->libDir, cfg->user, cfg->group);
693
            goto error;
694
        }
695
        if (chown(cfg->cacheDir, cfg->user, cfg->group) < 0) {
696
            virReportSystemError(errno,
697
                                 _("unable to set ownership of '%s' to %d:%d"),
698
                                 cfg->cacheDir, cfg->user, cfg->group);
699
            goto error;
700
        }
701
        if (chown(cfg->saveDir, cfg->user, cfg->group) < 0) {
702 703
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
704
                                 cfg->saveDir, cfg->user, cfg->group);
705 706
            goto error;
        }
707
        if (chown(cfg->snapshotDir, cfg->user, cfg->group) < 0) {
708 709
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
710
                                 cfg->snapshotDir, cfg->user, cfg->group);
711
            goto error;
712
        }
713 714
        run_uid = cfg->user;
        run_gid = cfg->group;
715
    }
716

717
    qemu_driver->qemuCapsCache = virQEMUCapsCacheNew(cfg->libDir,
718 719
                                                     run_uid,
                                                     run_gid);
720
    if (!qemu_driver->qemuCapsCache)
721 722
        goto error;

723
    if ((qemu_driver->caps = virQEMUDriverCreateCapabilities(qemu_driver)) == NULL)
724 725
        goto error;

726
    if (!(qemu_driver->xmlopt = virQEMUDriverCreateXMLConf()))
727 728
        goto error;

729 730 731 732 733 734
    /* If hugetlbfs is present, then we need to create a sub-directory within
     * it, since we can't assume the root mount point has permissions that
     * will let our spawned QEMU instances use it.
     *
     * NB the check for '/', since user may config "" to disable hugepages
     * even when mounted
735
     */
736 737
    if (cfg->hugetlbfsMount &&
        cfg->hugetlbfsMount[0] == '/') {
738
        if (virAsprintf(&membase, "%s/libvirt",
739
                        cfg->hugetlbfsMount) < 0 ||
740
            virAsprintf(&mempath, "%s/qemu", membase) < 0)
741
            goto out_of_memory;
742

743 744
        if (virFileMakePath(mempath) < 0) {
            virReportSystemError(errno,
745 746
                                 _("unable to create hugepage path %s"), mempath);
            goto error;
747
        }
748
        if (cfg->privileged) {
749 750
            if (virFileUpdatePerm(membase, 0, S_IXGRP | S_IXOTH) < 0)
                goto error;
751
            if (chown(mempath, cfg->user, cfg->group) < 0) {
752 753
                virReportSystemError(errno,
                                     _("unable to set ownership on %s to %d:%d"),
754 755
                                     mempath, cfg->user,
                                     cfg->group);
756 757
                goto error;
            }
G
Guido Günther 已提交
758
        }
S
Stefan Berger 已提交
759
        VIR_FREE(membase);
E
Eric Blake 已提交
760

761
        cfg->hugepagePath = mempath;
762
    }
763

764
    if (!(qemu_driver->closeCallbacks = virQEMUCloseCallbacksNew()))
765 766
        goto error;

767
    /* Get all the running persistent or transient configs first */
768
    if (virDomainObjListLoadAllConfigs(qemu_driver->domains,
769 770
                                       cfg->stateDir,
                                       NULL, 1,
771
                                       qemu_driver->caps,
772
                                       qemu_driver->xmlopt,
773
                                       QEMU_EXPECTED_VIRT_TYPES,
774
                                       NULL, NULL) < 0)
775
        goto error;
776

777 778 779
    /* find the maximum ID from active and transient configs to initialize
     * the driver with. This is to avoid race between autostart and reconnect
     * threads */
780 781 782
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainFindMaxID,
                            &qemu_driver->nextvmid);
783

784 785 786
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainNetsRestart,
                            NULL);
787

788
    conn = virConnectOpen(cfg->uri);
789

790
    qemuProcessReconnectAll(conn, qemu_driver);
791

792
    /* Then inactive persistent configs */
793
    if (virDomainObjListLoadAllConfigs(qemu_driver->domains,
794 795
                                       cfg->configDir,
                                       cfg->autostartDir, 0,
796
                                       qemu_driver->caps,
797
                                       qemu_driver->xmlopt,
798
                                       QEMU_EXPECTED_VIRT_TYPES,
799
                                       NULL, NULL) < 0)
800
        goto error;
801

802

803 804 805
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainSnapshotLoad,
                            cfg->snapshotDir);
806

807 808 809
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainManagedSaveLoad,
                            qemu_driver);
810

811
    qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, processWatchdogEvent, qemu_driver);
812 813
    if (!qemu_driver->workerPool)
        goto error;
814

815 816
    qemuAutostartDomains(qemu_driver);

817 818
    if (conn)
        virConnectClose(conn);
819

820
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
821
    return 0;
822

823 824 825 826 827 828
out_of_memory:
    virReportOOMError();
error:
    if (conn)
        virConnectClose(conn);
    VIR_FREE(driverConf);
829 830
    VIR_FREE(membase);
    VIR_FREE(mempath);
831
    qemuShutdown();
832
    return -1;
833 834
}

835
static void qemuNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
836
{
837
    virQEMUDriverPtr driver = opaque;
838

839 840 841 842 843 844 845
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
E
Eric Blake 已提交
846
    }
847
}
E
Eric Blake 已提交
848

849
/**
850
 * qemuReload:
851 852 853 854 855
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
856
qemuReload(void) {
857 858
    virQEMUDriverConfigPtr cfg = NULL;
    virCapsPtr caps = NULL;
859

860 861
    if (!qemu_driver)
        return 0;
862

863 864 865
    if (!(caps = virQEMUDriverGetCapabilities(qemu_driver, false)))
        goto cleanup;

866
    cfg = virQEMUDriverGetConfig(qemu_driver);
867 868
    virDomainObjListLoadAllConfigs(qemu_driver->domains,
                                   cfg->configDir,
869 870 871
                                   cfg->autostartDir, 0,
                                   caps, qemu_driver->xmlopt,
                                   QEMU_EXPECTED_VIRT_TYPES,
872
                                   qemuNotifyLoadDomain, qemu_driver);
873
cleanup:
874
    virObjectUnref(cfg);
875
    virObjectUnref(caps);
876 877
    return 0;
}
S
Stefan Berger 已提交
878

879 880 881 882 883 884 885 886 887 888 889

/*
 * qemuStop:
 *
 * Save any VMs in preparation for shutdown
 *
 */
static int
qemuStop(void) {
    int ret = -1;
    virConnectPtr conn;
890
    int numDomains = 0;
891 892 893 894
    size_t i;
    int state;
    virDomainPtr *domains = NULL;
    unsigned int *flags = NULL;
895
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(qemu_driver);
896

897 898
    if (!(conn = virConnectOpen(cfg->uri)))
        goto cleanup;
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933

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

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

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

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

 cleanup:
    for (i = 0 ; i < numDomains ; i++)
        virDomainFree(domains[i]);
    VIR_FREE(domains);
    VIR_FREE(flags);
934 935 936
    if (conn)
        virConnectClose(conn);
    virObjectUnref(cfg);
937 938 939 940

    return ret;
}

941
/**
942
 * qemuShutdown:
943 944 945 946
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
947
qemuShutdown(void) {
948 949
    if (!qemu_driver)
        return -1;
950

951
    virNWFilterUnRegisterCallbackDriver(&qemuCallbackDriver);
952
    virObjectUnref(qemu_driver->config);
953 954 955
    virObjectUnref(qemu_driver->activePciHostdevs);
    virObjectUnref(qemu_driver->inactivePciHostdevs);
    virObjectUnref(qemu_driver->activeUsbHostdevs);
956
    virHashFree(qemu_driver->sharedDisks);
957
    virObjectUnref(qemu_driver->caps);
958
    virQEMUCapsCacheFree(qemu_driver->qemuCapsCache);
959

960
    virObjectUnref(qemu_driver->domains);
961
    virObjectUnref(qemu_driver->remotePorts);
962

963
    virObjectUnref(qemu_driver->xmlopt);
964

965
    virSysinfoDefFree(qemu_driver->hostsysinfo);
966

967
    virObjectUnref(qemu_driver->closeCallbacks);
968

E
Eric Blake 已提交
969
    VIR_FREE(qemu_driver->qemuImgBinary);
970

971
    virObjectUnref(qemu_driver->securityManager);
972

973
    ebtablesContextFree(qemu_driver->ebtables);
974

975
    /* Free domain callback list */
976
    virDomainEventStateFree(qemu_driver->domainEventState);
D
Daniel P. Berrange 已提交
977

978
    virCgroupFree(&qemu_driver->cgroup);
979

980 981
    virLockManagerPluginUnref(qemu_driver->lockManager);

982 983 984
    virMutexDestroy(&qemu_driver->lock);
    virThreadPoolFree(qemu_driver->workerPool);
    VIR_FREE(qemu_driver);
985

986
    return 0;
987 988
}

989

990 991 992
static virDrvOpenStatus qemuOpen(virConnectPtr conn,
                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                 unsigned int flags)
993
{
994 995
    virQEMUDriverConfigPtr cfg = NULL;
    virDrvOpenStatus ret = VIR_DRV_OPEN_ERROR;
E
Eric Blake 已提交
996 997
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

998
    if (conn->uri == NULL) {
999 1000 1001 1002 1003 1004
        if (qemu_driver == NULL) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }

        cfg = virQEMUDriverGetConfig(qemu_driver);
1005

1006 1007
        if (!(conn->uri = virURIParse(cfg->uri)))
            goto cleanup;
1008 1009 1010
    } else {
        /* If URI isn't 'qemu' its definitely not for us */
        if (conn->uri->scheme == NULL ||
1011 1012 1013 1014
            STRNEQ(conn->uri->scheme, "qemu")) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }
1015 1016

        /* Allow remote driver to deal with URIs with hostname server */
1017 1018 1019 1020
        if (conn->uri->server != NULL) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }
1021

1022
        if (qemu_driver == NULL) {
1023 1024
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("qemu state driver is not active"));
1025
            goto cleanup;
1026 1027
        }

1028
        if (conn->uri->path == NULL) {
1029 1030
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no QEMU URI path given, try %s"),
1031 1032
                           cfg->uri);
            goto cleanup;
1033 1034
        }

1035 1036
        cfg = virQEMUDriverGetConfig(qemu_driver);
        if (cfg->privileged) {
1037 1038
            if (STRNEQ(conn->uri->path, "/system") &&
                STRNEQ(conn->uri->path, "/session")) {
1039 1040 1041
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///system"),
                               conn->uri->path);
1042
                goto cleanup;
1043 1044
            }
        } else {
1045
            if (STRNEQ(conn->uri->path, "/session")) {
1046 1047 1048
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///session"),
                               conn->uri->path);
1049
                goto cleanup;
1050 1051
            }
        }
1052 1053 1054
    }
    conn->privateData = qemu_driver;

1055 1056 1057 1058
    ret = VIR_DRV_OPEN_SUCCESS;
cleanup:
    virObjectUnref(cfg);
    return ret;
1059 1060
}

1061 1062
static int qemuClose(virConnectPtr conn)
{
1063
    virQEMUDriverPtr driver = conn->privateData;
1064 1065

    /* Get rid of callbacks registered for this conn */
1066
    virQEMUCloseCallbacksRun(driver->closeCallbacks, conn, driver);
1067 1068 1069 1070 1071 1072

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
1073 1074
/* Which features are supported by this driver? */
static int
1075
qemuSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
D
Daniel Veillard 已提交
1076 1077
{
    switch (feature) {
1078
    case VIR_DRV_FEATURE_MIGRATION_V2:
1079
    case VIR_DRV_FEATURE_MIGRATION_V3:
1080
    case VIR_DRV_FEATURE_MIGRATION_P2P:
1081
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
1082
    case VIR_DRV_FEATURE_FD_PASSING:
1083
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
1084
    case VIR_DRV_FEATURE_XML_MIGRATABLE:
L
liguang 已提交
1085
    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
1086 1087 1088
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
1089 1090 1091
    }
}

1092
static const char *qemuGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1093
    return "QEMU";
1094 1095
}

1096

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
static int qemuIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}

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

1109 1110 1111 1112 1113
static int qemuIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}

1114

1115 1116 1117 1118
static int
kvmGetMaxVCPUs(void) {
    int fd;
    int ret;
1119

1120
    if ((fd = open(KVM_DEVICE, O_RDONLY)) < 0) {
1121
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
1122
        return -1;
1123 1124
    }

1125
#ifdef KVM_CAP_MAX_VCPUS
1126 1127 1128
    /* 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;
1129
#endif /* KVM_CAP_MAX_VCPUS */
1130 1131 1132 1133 1134 1135 1136 1137 1138

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

1140
cleanup:
1141
    VIR_FORCE_CLOSE(fd);
1142
    return ret;
1143 1144 1145
}


E
Eric Blake 已提交
1146 1147 1148
static char *
qemuGetSysinfo(virConnectPtr conn, unsigned int flags)
{
1149
    virQEMUDriverPtr driver = conn->privateData;
1150
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
1151 1152 1153 1154

    virCheckFlags(0, NULL);

    if (!driver->hostsysinfo) {
1155 1156
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Host SMBIOS information is not available"));
E
Eric Blake 已提交
1157 1158 1159
        return NULL;
    }

1160 1161 1162 1163 1164 1165 1166
    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
    if (virBufferError(&buf)) {
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&buf);
E
Eric Blake 已提交
1167 1168
}

1169
static int qemuGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
1170 1171 1172
    if (!type)
        return 16;

1173
    if (STRCASEEQ(type, "qemu"))
1174 1175
        return 16;

1176
    if (STRCASEEQ(type, "kvm"))
1177
        return kvmGetMaxVCPUs();
1178

1179
    if (STRCASEEQ(type, "kqemu"))
1180
        return 1;
1181

1182 1183
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unknown type '%s'"), type);
1184 1185 1186
    return -1;
}

1187

1188
static char *qemuGetCapabilities(virConnectPtr conn) {
1189
    virQEMUDriverPtr driver = conn->privateData;
1190
    virCapsPtr caps = NULL;
1191
    char *xml = NULL;
1192

1193
    if (!(caps = virQEMUDriverGetCapabilities(driver, true)))
1194
        goto cleanup;
1195

1196
    if ((xml = virCapabilitiesFormatXML(caps)) == NULL)
1197
        virReportOOMError();
1198
    virObjectUnref(caps);
1199 1200

cleanup:
1201

1202
    return xml;
1203 1204 1205
}


1206
static int
1207 1208
qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
                   pid_t pid, int tid)
1209 1210
{
    char *proc;
D
Daniel P. Berrange 已提交
1211
    FILE *pidinfo;
1212
    unsigned long long usertime, systime;
1213
    long rss;
1214 1215
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
1216

1217 1218
    /* In general, we cannot assume pid_t fits in int; but /proc parsing
     * is specific to Linux where int works fine.  */
1219
    if (tid)
1220
        ret = virAsprintf(&proc, "/proc/%d/task/%d/stat", (int) pid, tid);
1221
    else
1222
        ret = virAsprintf(&proc, "/proc/%d/stat", (int) pid);
1223
    if (ret < 0)
D
Daniel P. Berrange 已提交
1224 1225 1226 1227
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
1228 1229 1230 1231
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
1232 1233
        if (vm_rss)
            *vm_rss = 0;
1234
        VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1235 1236
        return 0;
    }
1237
    VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1238

1239 1240 1241 1242 1243 1244
    /* 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 */
1245
               "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
1246 1247
               /* startstack -> processor */
               "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
1248
               &usertime, &systime, &rss, &cpu) != 4) {
1249
        VIR_FORCE_FCLOSE(pidinfo);
1250
        VIR_WARN("cannot parse process status data");
1251
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
1252 1253 1254 1255 1256 1257 1258 1259
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
1260 1261 1262 1263 1264
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

1265 1266 1267 1268 1269 1270
    /* 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 已提交
1271

1272 1273

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

1276
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
1277 1278 1279 1280 1281

    return 0;
}


1282 1283
static virDomainPtr qemuDomainLookupByID(virConnectPtr conn,
                                         int id) {
1284
    virQEMUDriverPtr driver = conn->privateData;
1285 1286 1287
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1288
    vm  = virDomainObjListFindByID(driver->domains, id);
1289 1290

    if (!vm) {
1291 1292
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), id);
1293
        goto cleanup;
1294 1295
    }

1296
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1297
    if (dom) dom->id = vm->def->id;
1298 1299

cleanup:
1300
    if (vm)
1301
        virObjectUnlock(vm);
1302 1303
    return dom;
}
1304

1305 1306
static virDomainPtr qemuDomainLookupByUUID(virConnectPtr conn,
                                           const unsigned char *uuid) {
1307
    virQEMUDriverPtr driver = conn->privateData;
1308 1309
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1310

1311
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
1312

1313
    if (!vm) {
1314 1315
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
1316 1317
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1318
        goto cleanup;
1319 1320
    }

1321
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1322
    if (dom) dom->id = vm->def->id;
1323 1324

cleanup:
1325
    if (vm)
1326
        virObjectUnlock(vm);
1327 1328
    return dom;
}
1329

1330 1331
static virDomainPtr qemuDomainLookupByName(virConnectPtr conn,
                                           const char *name) {
1332
    virQEMUDriverPtr driver = conn->privateData;
1333 1334
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1335

1336
    vm = virDomainObjListFindByName(driver->domains, name);
1337

1338
    if (!vm) {
1339 1340
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
1341
        goto cleanup;
1342 1343
    }

1344
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1345
    if (dom) dom->id = vm->def->id;
1346 1347

cleanup:
1348
    if (vm)
1349
        virObjectUnlock(vm);
1350 1351 1352
    return dom;
}

1353 1354 1355 1356 1357 1358

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

1359
    if (!(obj = qemuDomObjFromDomain(dom)))
1360
        goto cleanup;
1361

1362 1363 1364 1365
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
1366
        virObjectUnlock(obj);
1367 1368 1369 1370 1371 1372 1373 1374
    return ret;
}

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

1375
    if (!(obj = qemuDomObjFromDomain(dom)))
1376
        goto cleanup;
1377

1378 1379 1380 1381
    ret = obj->persistent;

cleanup:
    if (obj)
1382
        virObjectUnlock(obj);
1383 1384 1385
    return ret;
}

1386 1387 1388 1389 1390
static int qemuDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

1391
    if (!(obj = qemuDomObjFromDomain(dom)))
1392
        goto cleanup;
1393

1394 1395 1396 1397
    ret = obj->updated;

cleanup:
    if (obj)
1398
        virObjectUnlock(obj);
1399 1400
    return ret;
}
1401

1402
static int qemuGetVersion(virConnectPtr conn, unsigned long *version) {
1403
    virQEMUDriverPtr driver = conn->privateData;
1404
    int ret = -1;
1405
    unsigned int qemuVersion = 0;
1406
    virCapsPtr caps = NULL;
1407

1408 1409 1410 1411
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (virQEMUCapsGetDefaultVersion(caps,
1412 1413
                                     driver->qemuCapsCache,
                                     &qemuVersion) < 0)
1414
        goto cleanup;
1415

1416
    *version = qemuVersion;
1417 1418 1419
    ret = 0;

cleanup:
1420
    virObjectUnref(caps);
1421
    return ret;
D
Daniel P. Berrange 已提交
1422 1423
}

1424
static int qemuListDomains(virConnectPtr conn, int *ids, int nids) {
1425
    virQEMUDriverPtr driver = conn->privateData;
1426
    int n;
1427

1428
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids);
1429

1430
    return n;
D
Daniel P. Berrange 已提交
1431
}
1432

1433
static int qemuNumDomains(virConnectPtr conn) {
1434
    virQEMUDriverPtr driver = conn->privateData;
1435
    int n;
1436

1437
    n = virDomainObjListNumOfDomains(driver->domains, 1);
1438

1439
    return n;
D
Daniel P. Berrange 已提交
1440
}
1441

1442 1443

static int
1444
qemuCanonicalizeMachine(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
1445
{
1446
    const char *canon;
1447

1448
    if (!(canon = virQEMUCapsGetCanonicalMachine(qemuCaps, def->os.machine)))
1449 1450 1451
        return 0;

    if (STRNEQ(canon, def->os.machine)) {
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
        char *tmp;
        if (!(tmp = strdup(canon))) {
            virReportOOMError();
            return -1;
        }
        VIR_FREE(def->os.machine);
        def->os.machine = tmp;
    }

    return 0;
}


1465 1466
static virDomainPtr qemuDomainCreate(virConnectPtr conn, const char *xml,
                                     unsigned int flags) {
1467
    virQEMUDriverPtr driver = conn->privateData;
1468
    virDomainDefPtr def = NULL;
1469
    virDomainObjPtr vm = NULL;
1470
    virDomainPtr dom = NULL;
1471
    virDomainEventPtr event = NULL;
1472
    virDomainEventPtr event2 = NULL;
1473
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;
1474
    virQEMUCapsPtr qemuCaps = NULL;
1475
    virCapsPtr caps = NULL;
D
Daniel P. Berrange 已提交
1476

1477 1478
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_AUTODESTROY, NULL);
1479

1480 1481 1482
    if (flags & VIR_DOMAIN_START_PAUSED)
        start_flags |= VIR_QEMU_PROCESS_START_PAUSED;
    if (flags & VIR_DOMAIN_START_AUTODESTROY)
1483
        start_flags |= VIR_QEMU_PROCESS_START_AUTODESTROY;
1484

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

1488
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
1489
                                        QEMU_EXPECTED_VIRT_TYPES,
1490
                                        VIR_DOMAIN_XML_INACTIVE)))
1491
        goto cleanup;
1492

1493
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1494 1495
        goto cleanup;

1496
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
1497 1498
        goto cleanup;

1499
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
1500 1501
        goto cleanup;

1502
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
1503 1504
        goto cleanup;

1505
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1506
                                   driver->xmlopt,
1507 1508
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1509 1510 1511
        goto cleanup;

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

1513
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
1514 1515
        goto cleanup; /* XXXX free the 'vm' we created ? */

1516 1517 1518
    if (qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                         VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                         start_flags) < 0) {
1519
        virDomainAuditStart(vm, "booted", false);
1520
        if (qemuDomainObjEndJob(driver, vm) > 0)
1521
            qemuDomainRemoveInactive(driver, vm);
1522
        vm = NULL;
1523
        goto cleanup;
D
Daniel P. Berrange 已提交
1524
    }
1525 1526 1527 1528

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
    if (event && (flags & VIR_DOMAIN_START_PAUSED)) {
        /* There are two classes of event-watching clients - those
         * that only care about on/off (and must see a started event
         * no matter what, but don't care about suspend events), and
         * those that also care about running/paused.  To satisfy both
         * client types, we have to send two events.  */
        event2 = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_SUSPENDED,
                                          VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }
1539
    virDomainAuditStart(vm, "booted", true);
D
Daniel P. Berrange 已提交
1540

1541
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1542
    if (dom) dom->id = vm->def->id;
1543

1544
    if (vm &&
1545
        qemuDomainObjEndJob(driver, vm) == 0)
1546
        vm = NULL;
1547

1548 1549
cleanup:
    virDomainDefFree(def);
1550
    if (vm)
1551
        virObjectUnlock(vm);
1552
    if (event) {
1553
        qemuDomainEventQueue(driver, event);
1554 1555 1556
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
1557
    virObjectUnref(caps);
1558
    virObjectUnref(qemuCaps);
1559
    return dom;
D
Daniel P. Berrange 已提交
1560 1561 1562
}


1563
static int qemuDomainSuspend(virDomainPtr dom) {
1564
    virQEMUDriverPtr driver = dom->conn->privateData;
1565 1566
    virDomainObjPtr vm;
    int ret = -1;
1567
    virDomainEventPtr event = NULL;
1568
    qemuDomainObjPrivatePtr priv;
1569 1570
    virDomainPausedReason reason;
    int eventDetail;
1571
    int state;
1572
    virQEMUDriverConfigPtr cfg = NULL;
1573

1574
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1575

D
Daniel P. Berrange 已提交
1576
    if (!vm) {
1577 1578
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1579 1580
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1581
        goto cleanup;
D
Daniel P. Berrange 已提交
1582
    }
D
Daniel P. Berrange 已提交
1583
    if (!virDomainObjIsActive(vm)) {
1584 1585
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1586
        goto cleanup;
D
Daniel P. Berrange 已提交
1587
    }
1588

1589
    cfg = virQEMUDriverGetConfig(driver);
1590 1591
    priv = vm->privateData;

1592
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_SUSPEND) < 0)
1593 1594 1595
        goto cleanup;

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

1601 1602 1603
    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) {
        reason = VIR_DOMAIN_PAUSED_MIGRATION;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED;
1604 1605 1606
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_SNAPSHOT) {
        reason = VIR_DOMAIN_PAUSED_SNAPSHOT;
        eventDetail = -1; /* don't create lifecycle events when doing snapshot */
1607 1608 1609 1610 1611
    } else {
        reason = VIR_DOMAIN_PAUSED_USER;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
    }

1612 1613 1614 1615 1616 1617
    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) {
1618
        if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) {
1619
            goto endjob;
1620
        }
1621 1622 1623 1624 1625 1626

        if (eventDetail >= 0) {
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             eventDetail);
        }
D
Daniel P. Berrange 已提交
1627
    }
1628
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1629 1630
        goto endjob;
    ret = 0;
1631

1632
endjob:
1633
    if (qemuDomainObjEndJob(driver, vm) == 0)
1634
        vm = NULL;
1635

1636
cleanup:
1637
    if (vm)
1638
        virObjectUnlock(vm);
1639

1640
    if (event)
1641
        qemuDomainEventQueue(driver, event);
1642
    virObjectUnref(cfg);
1643
    return ret;
D
Daniel P. Berrange 已提交
1644 1645 1646
}


1647
static int qemuDomainResume(virDomainPtr dom) {
1648
    virQEMUDriverPtr driver = dom->conn->privateData;
1649 1650
    virDomainObjPtr vm;
    int ret = -1;
1651
    virDomainEventPtr event = NULL;
1652
    int state;
1653
    virQEMUDriverConfigPtr cfg = NULL;
1654
    virCapsPtr caps = NULL;
1655

1656
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1657

D
Daniel P. Berrange 已提交
1658
    if (!vm) {
1659 1660
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1661 1662
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1663
        goto cleanup;
D
Daniel P. Berrange 已提交
1664
    }
1665

1666 1667
    cfg = virQEMUDriverGetConfig(driver);

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

D
Daniel P. Berrange 已提交
1671
    if (!virDomainObjIsActive(vm)) {
1672 1673
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1674
        goto endjob;
D
Daniel P. Berrange 已提交
1675
    }
1676 1677 1678 1679 1680 1681 1682

    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 已提交
1683
        if (qemuProcessStartCPUs(driver, vm, dom->conn,
1684 1685
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
1686
            if (virGetLastError() == NULL)
1687 1688
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resume operation failed"));
1689
            goto endjob;
1690
        }
1691 1692 1693
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
1694
    }
1695 1696
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto endjob;
1697
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1698
        goto endjob;
1699 1700
    ret = 0;

1701
endjob:
1702
    if (qemuDomainObjEndJob(driver, vm) == 0)
1703
        vm = NULL;
1704

1705
cleanup:
1706
    if (vm)
1707
        virObjectUnlock(vm);
1708
    if (event)
1709
        qemuDomainEventQueue(driver, event);
1710
    virObjectUnref(caps);
1711
    virObjectUnref(cfg);
1712
    return ret;
D
Daniel P. Berrange 已提交
1713 1714
}

1715
static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) {
1716
    virQEMUDriverPtr driver = dom->conn->privateData;
1717 1718
    virDomainObjPtr vm;
    int ret = -1;
1719
    qemuDomainObjPrivatePtr priv;
1720
    bool useAgent = false, agentRequested, acpiRequested;
1721 1722 1723

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
1724

1725
    if (!(vm = qemuDomObjFromDomain(dom)))
1726
        goto cleanup;
1727

1728
    priv = vm->privateData;
1729 1730
    agentRequested = flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT;
    acpiRequested  = flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN;
1731

1732 1733
    /* Prefer agent unless we were requested to not to. */
    if (agentRequested || (!flags && priv->agent))
1734 1735
        useAgent = true;

1736 1737
    if (priv->agentError) {
        if (agentRequested && !acpiRequested) {
1738 1739 1740
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
1741
            goto cleanup;
1742 1743
        } else {
            useAgent = false;
1744
        }
1745 1746 1747 1748
    }

    if (!priv->agent) {
        if (agentRequested && !acpiRequested) {
1749 1750
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
1751
            goto cleanup;
1752 1753
        } else {
            useAgent = false;
1754 1755 1756
        }
    }

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

D
Daniel P. Berrange 已提交
1760
    if (!virDomainObjIsActive(vm)) {
1761 1762
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1763
        goto endjob;
1764 1765
    }

1766
    if (useAgent) {
1767
        qemuDomainObjEnterAgent(vm);
1768
        ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_POWERDOWN);
1769
        qemuDomainObjExitAgent(vm);
1770 1771 1772 1773 1774 1775 1776
    }

    /* 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))) {
1777
        qemuDomainSetFakeReboot(driver, vm, false);
1778

1779 1780 1781 1782
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSystemPowerdown(priv->mon);
        qemuDomainObjExitMonitor(driver, vm);
    }
1783

1784
endjob:
1785
    if (qemuDomainObjEndJob(driver, vm) == 0)
1786
        vm = NULL;
1787

1788
cleanup:
1789
    if (vm)
1790
        virObjectUnlock(vm);
1791
    return ret;
1792 1793
}

1794 1795
static int qemuDomainShutdown(virDomainPtr dom)
{
1796 1797 1798
    return qemuDomainShutdownFlags(dom, 0);
}

1799

1800 1801 1802
static int
qemuDomainReboot(virDomainPtr dom, unsigned int flags)
{
1803
    virQEMUDriverPtr driver = dom->conn->privateData;
1804 1805 1806
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
1807
    bool useAgent = false;
1808

1809 1810
    virCheckFlags(VIR_DOMAIN_REBOOT_ACPI_POWER_BTN |
                  VIR_DOMAIN_REBOOT_GUEST_AGENT , -1);
1811

1812 1813 1814 1815 1816 1817 1818 1819
    /* 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;
    }

1820
    if (!(vm = qemuDomObjFromDomain(dom)))
1821 1822
        goto cleanup;

1823 1824
    priv = vm->privateData;

1825 1826
    if ((flags & VIR_DOMAIN_REBOOT_GUEST_AGENT) ||
        (!(flags & VIR_DOMAIN_REBOOT_ACPI_POWER_BTN) &&
1827 1828 1829 1830 1831
         priv->agent))
        useAgent = true;

    if (useAgent) {
        if (priv->agentError) {
1832 1833 1834
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
1835 1836 1837
            goto cleanup;
        }
        if (!priv->agent) {
1838 1839
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
1840 1841 1842
            goto cleanup;
        }
    } else {
1843
#if WITH_YAJL
1844 1845
        if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
            if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) {
1846 1847
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Reboot is not supported with this QEMU binary"));
1848 1849 1850 1851
                goto cleanup;
            }
        } else {
#endif
1852 1853
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Reboot is not supported without the JSON monitor"));
1854
            goto cleanup;
1855
#if WITH_YAJL
1856
        }
1857 1858
#endif
    }
1859

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

1863
    if (!virDomainObjIsActive(vm)) {
1864 1865
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1866 1867
        goto endjob;
    }
1868

1869
    if (useAgent) {
1870
        qemuDomainObjEnterAgent(vm);
1871
        ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_REBOOT);
1872
        qemuDomainObjExitAgent(vm);
1873
    } else {
1874
        qemuDomainObjEnterMonitor(driver, vm);
1875
        ret = qemuMonitorSystemPowerdown(priv->mon);
1876
        qemuDomainObjExitMonitor(driver, vm);
1877

1878 1879
        if (ret == 0)
            qemuDomainSetFakeReboot(driver, vm, true);
1880 1881
    }

1882 1883 1884 1885
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

1886 1887
cleanup:
    if (vm)
1888
        virObjectUnlock(vm);
1889 1890 1891 1892
    return ret;
}


1893 1894 1895
static int
qemuDomainReset(virDomainPtr dom, unsigned int flags)
{
1896
    virQEMUDriverPtr driver = dom->conn->privateData;
1897 1898 1899 1900 1901 1902
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

1903
    if (!(vm = qemuDomObjFromDomain(dom)))
1904 1905 1906 1907 1908 1909
        goto cleanup;

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

    if (!virDomainObjIsActive(vm)) {
1910 1911
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927
        goto endjob;
    }

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

    priv->fakeReboot = false;

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

cleanup:
    if (vm)
1928
        virObjectUnlock(vm);
1929 1930 1931 1932
    return ret;
}


1933
/* Count how many snapshots in a set are external snapshots or checkpoints.  */
1934 1935 1936 1937 1938 1939 1940 1941
static void
qemuDomainSnapshotCountExternal(void *payload,
                                const void *name ATTRIBUTE_UNUSED,
                                void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    int *count = data;

1942
    if (virDomainSnapshotIsExternal(snap))
1943 1944 1945
        (*count)++;
}

1946 1947 1948 1949
static int
qemuDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
1950
    virQEMUDriverPtr driver = dom->conn->privateData;
1951 1952
    virDomainObjPtr vm;
    int ret = -1;
1953
    virDomainEventPtr event = NULL;
1954
    qemuDomainObjPrivatePtr priv;
1955

1956
    virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1);
1957

1958
    vm  = virDomainObjListFindByUUID(driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
1959
    if (!vm) {
1960 1961
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1962 1963
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1964
        goto cleanup;
D
Daniel P. Berrange 已提交
1965
    }
1966

1967 1968
    priv = vm->privateData;

1969
    qemuDomainSetFakeReboot(driver, vm, false);
1970

1971 1972 1973 1974 1975 1976

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

1977 1978 1979 1980 1981
    /* 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
     */
1982
    if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
1983
        if (qemuProcessKill(vm, 0) < 0) {
1984
            priv->beingDestroyed = false;
1985
            goto cleanup;
1986
        }
1987
    } else {
1988
        if (qemuProcessKill(vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
1989
            priv->beingDestroyed = false;
1990
            goto cleanup;
1991
        }
1992
    }
1993

1994
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_DESTROY) < 0)
1995 1996
        goto cleanup;

1997 1998
    priv->beingDestroyed = false;

D
Daniel P. Berrange 已提交
1999
    if (!virDomainObjIsActive(vm)) {
2000 2001
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2002
        goto endjob;
2003
    }
2004

2005
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED, 0);
2006 2007 2008
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
2009
    virDomainAuditStop(vm, "destroyed");
2010

2011
    if (!vm->persistent) {
2012
        if (qemuDomainObjEndJob(driver, vm) > 0)
2013
            qemuDomainRemoveInactive(driver, vm);
2014 2015
        vm = NULL;
    }
2016 2017
    ret = 0;

2018
endjob:
2019
    if (vm &&
2020
        qemuDomainObjEndJob(driver, vm) == 0)
2021
        vm = NULL;
2022

2023
cleanup:
2024
    if (vm)
2025
        virObjectUnlock(vm);
2026 2027
    if (event)
        qemuDomainEventQueue(driver, event);
2028
    return ret;
D
Daniel P. Berrange 已提交
2029 2030
}

2031 2032 2033 2034 2035
static int
qemuDomainDestroy(virDomainPtr dom)
{
    return qemuDomainDestroyFlags(dom, 0);
}
D
Daniel P. Berrange 已提交
2036

2037
static char *qemuDomainGetOSType(virDomainPtr dom) {
2038 2039
    virDomainObjPtr vm;
    char *type = NULL;
2040

2041
    if (!(vm = qemuDomObjFromDomain(dom)))
2042
        goto cleanup;
2043

2044
    if (!(type = strdup(vm->def->os.type)))
2045
        virReportOOMError();
2046 2047

cleanup:
2048
    if (vm)
2049
        virObjectUnlock(vm);
2050 2051 2052
    return type;
}

2053
/* Returns max memory in kb, 0 if error */
2054 2055 2056
static unsigned long long
qemuDomainGetMaxMemory(virDomainPtr dom)
{
2057
    virDomainObjPtr vm;
2058
    unsigned long long ret = 0;
2059

2060
    if (!(vm = qemuDomObjFromDomain(dom)))
2061
        goto cleanup;
2062

2063
    ret = vm->def->mem.max_balloon;
2064 2065

cleanup:
2066
    if (vm)
2067
        virObjectUnlock(vm);
2068
    return ret;
2069 2070
}

2071 2072
static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                    unsigned int flags) {
2073
    virQEMUDriverPtr driver = dom->conn->privateData;
2074
    qemuDomainObjPrivatePtr priv;
2075
    virDomainObjPtr vm;
2076
    virDomainDefPtr persistentDef = NULL;
2077
    int ret = -1, r;
2078
    virQEMUDriverConfigPtr cfg = NULL;
2079
    virCapsPtr caps = NULL;
2080

2081 2082
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
2083
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
2084

2085
    if (!(vm = qemuDomObjFromDomain(dom)))
2086
        goto cleanup;
2087

2088 2089
    cfg = virQEMUDriverGetConfig(driver);

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

2093 2094
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto endjob;
2095
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
2096
                                        &persistentDef) < 0)
2097
        goto endjob;
2098

2099 2100 2101
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */

2102
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2103 2104 2105
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot resize the maximum memory on an "
                             "active domain"));
2106
            goto endjob;
2107
        }
2108

2109
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2110 2111
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
2112 2113 2114
            persistentDef->mem.max_balloon = newmem;
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
2115
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
2116 2117 2118
            goto endjob;
        }

2119 2120 2121 2122
    } else {
        /* resize the current memory */

        if (newmem > vm->def->mem.max_balloon) {
2123 2124
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
2125 2126 2127
            goto endjob;
        }

2128
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2129
            priv = vm->privateData;
2130
            qemuDomainObjEnterMonitor(driver, vm);
2131
            r = qemuMonitorSetBalloon(priv->mon, newmem);
2132
            qemuDomainObjExitMonitor(driver, vm);
2133 2134
            virDomainAuditMemory(vm, vm->def->mem.cur_balloon, newmem, "update",
                                 r == 1);
2135 2136 2137 2138 2139
            if (r < 0)
                goto endjob;

            /* Lack of balloon support is a fatal error */
            if (r == 0) {
2140 2141 2142
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Unable to change memory of active domain without "
                                 "the balloon device and guest OS balloon driver"));
2143 2144 2145 2146
                goto endjob;
            }
        }

2147
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2148
            sa_assert(persistentDef);
2149
            persistentDef->mem.cur_balloon = newmem;
2150
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
2151 2152
            goto endjob;
        }
2153
    }
2154

2155
    ret = 0;
2156
endjob:
2157
    if (qemuDomainObjEndJob(driver, vm) == 0)
2158
        vm = NULL;
2159

2160
cleanup:
2161
    if (vm)
2162
        virObjectUnlock(vm);
2163
    virObjectUnref(caps);
2164
    virObjectUnref(cfg);
2165
    return ret;
2166 2167
}

2168
static int qemuDomainSetMemory(virDomainPtr dom, unsigned long newmem)
2169
{
2170
    return qemuDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
2171 2172
}

2173
static int qemuDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
2174
{
2175
    return qemuDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
2176 2177
}

2178 2179
static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
{
2180
    virQEMUDriverPtr driver = domain->conn->privateData;
2181 2182 2183 2184 2185 2186
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2187
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
2188 2189 2190
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
2191 2192
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2193 2194 2195 2196
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2197 2198
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2199 2200 2201 2202 2203
        goto cleanup;
    }

    priv = vm->privateData;

2204
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2205
        goto cleanup;
2206 2207

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

2213
    qemuDomainObjEnterMonitor(driver, vm);
2214
    ret = qemuMonitorInjectNMI(priv->mon);
2215
    qemuDomainObjExitMonitor(driver, vm);
2216 2217

endjob:
2218
    if (qemuDomainObjEndJob(driver, vm) == 0) {
2219 2220 2221 2222 2223 2224
        vm = NULL;
        goto cleanup;
    }

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

2229 2230 2231 2232 2233 2234 2235
static int qemuDomainSendKey(virDomainPtr domain,
                             unsigned int codeset,
                             unsigned int holdtime,
                             unsigned int *keycodes,
                             int nkeycodes,
                             unsigned int flags)
{
2236
    virQEMUDriverPtr driver = domain->conn->privateData;
2237 2238 2239 2240 2241 2242
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2243 2244
    /* translate the keycode to RFB for qemu driver */
    if (codeset != VIR_KEYCODE_SET_RFB) {
2245 2246 2247 2248
        int i;
        int keycode;

        for (i = 0; i < nkeycodes; i++) {
2249
            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_RFB,
2250 2251
                                               keycodes[i]);
            if (keycode < 0) {
2252 2253 2254 2255
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot translate keycode %u of %s codeset to rfb keycode"),
                               keycodes[i],
                               virKeycodeSetTypeToString(codeset));
2256 2257 2258 2259 2260 2261
                return -1;
            }
            keycodes[i] = keycode;
        }
    }

2262
    if (!(vm = qemuDomObjFromDomain(domain)))
2263 2264 2265 2266
        goto cleanup;

    priv = vm->privateData;

2267
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2268 2269 2270
        goto cleanup;

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

2276
    qemuDomainObjEnterMonitor(driver, vm);
2277
    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
2278
    qemuDomainObjExitMonitor(driver, vm);
2279 2280 2281

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
2282 2283 2284 2285
        vm = NULL;

cleanup:
    if (vm)
2286
        virObjectUnlock(vm);
2287 2288 2289
    return ret;
}

2290 2291
static int qemuDomainGetInfo(virDomainPtr dom,
                             virDomainInfoPtr info)
2292
{
2293
    virQEMUDriverPtr driver = dom->conn->privateData;
2294 2295
    virDomainObjPtr vm;
    int ret = -1;
2296
    int err;
2297
    unsigned long long balloon;
2298

2299
    if (!(vm = qemuDomObjFromDomain(dom)))
2300
        goto cleanup;
D
Daniel P. Berrange 已提交
2301

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

D
Daniel P. Berrange 已提交
2304
    if (!virDomainObjIsActive(vm)) {
2305
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2306
    } else {
2307
        if (qemuGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) {
2308 2309
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("cannot read cputime for domain"));
2310
            goto cleanup;
D
Daniel P. Berrange 已提交
2311 2312 2313
        }
    }

2314
    info->maxMem = vm->def->mem.max_balloon;
2315

D
Daniel P. Berrange 已提交
2316
    if (virDomainObjIsActive(vm)) {
2317
        qemuDomainObjPrivatePtr priv = vm->privateData;
2318 2319 2320

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
2321
            info->memory = vm->def->mem.max_balloon;
2322
        } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) {
2323
            info->memory = vm->def->mem.cur_balloon;
2324
        } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
2325
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
2326
                goto cleanup;
2327 2328 2329
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
2330
                qemuDomainObjEnterMonitor(driver, vm);
2331
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
2332
                qemuDomainObjExitMonitor(driver, vm);
2333
            }
2334
            if (qemuDomainObjEndJob(driver, vm) == 0) {
2335
                vm = NULL;
2336 2337 2338
                goto cleanup;
            }

2339 2340 2341 2342 2343 2344 2345
            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) {
2346
                /* Balloon not supported, so maxmem is always the allocation */
2347
                info->memory = vm->def->mem.max_balloon;
2348
            } else {
2349
                info->memory = balloon;
2350
            }
2351
        } else {
2352
            info->memory = vm->def->mem.cur_balloon;
2353
        }
2354
    } else {
2355
        info->memory = vm->def->mem.cur_balloon;
2356 2357
    }

2358
    info->nrVirtCpu = vm->def->vcpus;
2359 2360 2361
    ret = 0;

cleanup:
2362
    if (vm)
2363
        virObjectUnlock(vm);
2364
    return ret;
D
Daniel P. Berrange 已提交
2365 2366
}

2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377
static int
qemuDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

2378
    if (!(vm = qemuDomObjFromDomain(dom)))
2379 2380
        goto cleanup;

J
Jiri Denemark 已提交
2381
    *state = virDomainObjGetState(vm, reason);
2382 2383 2384 2385
    ret = 0;

cleanup:
    if (vm)
2386
        virObjectUnlock(vm);
2387 2388 2389
    return ret;
}

2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
static int
qemuDomainGetControlInfo(virDomainPtr dom,
                          virDomainControlInfoPtr info,
                          unsigned int flags)
{
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

2401
    if (!(vm = qemuDomObjFromDomain(dom)))
2402 2403 2404
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
2405 2406
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2407 2408 2409 2410 2411 2412 2413 2414 2415
        goto cleanup;
    }

    priv = vm->privateData;

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

    if (priv->monError) {
        info->state = VIR_DOMAIN_CONTROL_ERROR;
2416
    } else if (priv->job.active) {
2417 2418
        if (!priv->monStart) {
            info->state = VIR_DOMAIN_CONTROL_JOB;
2419
            if (virTimeMillisNow(&info->stateTime) < 0)
2420
                goto cleanup;
2421
            info->stateTime -= priv->job.start;
2422 2423
        } else {
            info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
2424
            if (virTimeMillisNow(&info->stateTime) < 0)
2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435
                goto cleanup;
            info->stateTime -= priv->monStart;
        }
    } else {
        info->state = VIR_DOMAIN_CONTROL_OK;
    }

    ret = 0;

cleanup:
    if (vm)
2436
        virObjectUnlock(vm);
2437 2438 2439
    return ret;
}

D
Daniel P. Berrange 已提交
2440

2441 2442 2443 2444 2445 2446
/* 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
2447

2448
verify(sizeof(QEMU_SAVE_MAGIC) == sizeof(QEMU_SAVE_PARTIAL));
E
Eric Blake 已提交
2449

2450
typedef enum {
2451 2452 2453
    QEMU_SAVE_FORMAT_RAW = 0,
    QEMU_SAVE_FORMAT_GZIP = 1,
    QEMU_SAVE_FORMAT_BZIP2 = 2,
2454 2455
    /*
     * Deprecated by xz and never used as part of a release
2456
     * QEMU_SAVE_FORMAT_LZMA
2457
     */
2458 2459
    QEMU_SAVE_FORMAT_XZ = 3,
    QEMU_SAVE_FORMAT_LZOP = 4,
2460 2461 2462
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2463

2464
    QEMU_SAVE_FORMAT_LAST
2465
} virQEMUSaveFormat;
2466

2467 2468
VIR_ENUM_DECL(qemuSaveCompression)
VIR_ENUM_IMPL(qemuSaveCompression, QEMU_SAVE_FORMAT_LAST,
2469 2470 2471
              "raw",
              "gzip",
              "bzip2",
2472 2473
              "xz",
              "lzop")
2474

2475 2476 2477
typedef struct _virQEMUSaveHeader virQEMUSaveHeader;
typedef virQEMUSaveHeader *virQEMUSaveHeaderPtr;
struct _virQEMUSaveHeader {
2478
    char magic[sizeof(QEMU_SAVE_MAGIC)-1];
2479 2480 2481 2482 2483
    uint32_t version;
    uint32_t xml_len;
    uint32_t was_running;
    uint32_t compressed;
    uint32_t unused[15];
2484 2485
};

2486
static inline void
2487
bswap_header(virQEMUSaveHeaderPtr hdr) {
2488 2489 2490 2491 2492 2493 2494
    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);
}


2495
/* return -errno on failure, or 0 on success */
E
Eric Blake 已提交
2496
static int
2497
qemuDomainSaveHeader(int fd, const char *path, const char *xml,
2498
                     virQEMUSaveHeaderPtr header)
E
Eric Blake 已提交
2499
{
2500 2501
    int ret = 0;

E
Eric Blake 已提交
2502
    if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
2503
        ret = -errno;
2504 2505 2506
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write header to domain save file '%s'"),
                       path);
2507 2508 2509
        goto endjob;
    }

E
Eric Blake 已提交
2510
    if (safewrite(fd, xml, header->xml_len) != header->xml_len) {
2511
        ret = -errno;
2512 2513
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write xml to '%s'"), path);
2514 2515 2516 2517 2518 2519
        goto endjob;
    }
endjob:
    return ret;
}

2520
/* Given a virQEMUSaveFormat compression level, return the name
2521 2522 2523 2524
 * of the program to run, or NULL if no program is needed.  */
static const char *
qemuCompressProgramName(int compress)
{
2525 2526
    return (compress == QEMU_SAVE_FORMAT_RAW ? NULL :
            qemuSaveCompressionTypeToString(compress));
2527 2528
}

2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555
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 已提交
2556 2557 2558
/* Internal function to properly create or open existing files, with
 * ownership affected by qemu driver setup.  */
static int
2559
qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
E
Eric Blake 已提交
2560 2561 2562 2563 2564 2565
             bool *needUnlink, bool *bypassSecurityDriver)
{
    struct stat sb;
    bool is_reg = true;
    bool need_unlink = false;
    bool bypass_security = false;
L
Laine Stump 已提交
2566
    unsigned int vfoflags = 0;
E
Eric Blake 已提交
2567
    int fd = -1;
2568
    int path_shared = virStorageFileIsSharedFS(path);
E
Eric Blake 已提交
2569 2570
    uid_t uid = getuid();
    gid_t gid = getgid();
2571
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
E
Eric Blake 已提交
2572 2573 2574 2575 2576 2577

    /* 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;
2578 2579 2580

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

E
Eric Blake 已提交
2584 2585 2586 2587 2588
        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 */
2589
            if (is_reg && !cfg->dynamicOwnership) {
E
Eric Blake 已提交
2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603
                uid = sb.st_uid;
                gid = sb.st_gid;
            }
        }
    }

    /* First try creating the file as root */
    if (!is_reg) {
        fd = open(path, oflags & ~O_CREAT);
        if (fd < 0) {
            virReportSystemError(errno, _("unable to open %s"), path);
            goto cleanup;
        }
    } else {
L
Laine Stump 已提交
2604 2605
        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
E
Eric Blake 已提交
2606 2607 2608
            /* 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
2609
               qemu user (cfg->user) is non-root, just set a flag to
E
Eric Blake 已提交
2610 2611 2612
               bypass security driver shenanigans, and retry the operation
               after doing setuid to qemu user */
            if ((fd != -EACCES && fd != -EPERM) ||
2613
                cfg->user == getuid()) {
E
Eric Blake 已提交
2614 2615 2616 2617 2618 2619 2620
                virReportSystemError(-fd,
                                     _("Failed to create file '%s'"),
                                     path);
                goto cleanup;
            }

            /* On Linux we can also verify the FS-type of the directory. */
2621
            switch (path_shared) {
E
Eric Blake 已提交
2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643
                case 1:
                   /* it was on a network share, so we'll continue
                    * as outlined above
                    */
                   break;

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

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

2644
            /* Retry creating the file as cfg->user */
E
Eric Blake 已提交
2645 2646 2647

            if ((fd = virFileOpenAs(path, oflags,
                                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
2648
                                    cfg->user, cfg->group,
L
Laine Stump 已提交
2649
                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
E
Eric Blake 已提交
2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667
                virReportSystemError(-fd,
                                   _("Error from child process creating '%s'"),
                                     path);
                goto cleanup;
            }

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

            bypass_security = true;
        }
    }
cleanup:
    if (needUnlink)
        *needUnlink = need_unlink;
    if (bypassSecurityDriver)
        *bypassSecurityDriver = bypass_security;
2668
    virObjectUnref(cfg);
E
Eric Blake 已提交
2669 2670 2671
    return fd;
}

2672 2673 2674
/* 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 */
2675
static int
2676
qemuDomainSaveMemory(virQEMUDriverPtr driver,
2677 2678
                     virDomainObjPtr vm,
                     const char *path,
2679
                     const char *domXML,
2680 2681 2682 2683
                     int compressed,
                     bool was_running,
                     unsigned int flags,
                     enum qemuDomainAsyncJob asyncJob)
2684
{
2685
    virQEMUSaveHeader header;
2686
    bool bypassSecurityDriver = false;
E
Eric Blake 已提交
2687
    bool needUnlink = false;
2688
    int ret = -1;
2689
    int fd = -1;
2690
    int directFlag = 0;
J
Jiri Denemark 已提交
2691
    virFileWrapperFdPtr wrapperFd = NULL;
2692
    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
2693 2694 2695
    unsigned long long pad;
    unsigned long long offset;
    size_t len;
2696
    char *xml = NULL;
2697

2698
    memset(&header, 0, sizeof(header));
2699 2700
    memcpy(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic));
    header.version = QEMU_SAVE_VERSION;
2701
    header.was_running = was_running ? 1 : 0;
2702

2703
    header.compressed = compressed;
2704

2705
    len = strlen(domXML) + 1;
2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718
    offset = sizeof(header) + len;

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

2725 2726
    offset += pad;
    header.xml_len = len;
2727

2728
    /* Obtain the file handle.  */
2729 2730
    if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
2731 2732
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
2733 2734
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
E
Eric Blake 已提交
2735
            goto cleanup;
2736
        }
2737
    }
E
Eric Blake 已提交
2738 2739 2740
    fd = qemuOpenFile(driver, path, O_WRONLY | O_TRUNC | O_CREAT | directFlag,
                      &needUnlink, &bypassSecurityDriver);
    if (fd < 0)
2741 2742
        goto cleanup;

2743
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
2744
        goto cleanup;
2745

2746
    /* Write header to file, followed by XML */
2747 2748
    if (qemuDomainSaveHeader(fd, path, xml, &header) < 0)
        goto cleanup;
2749

2750
    /* Perform the migration */
2751
    if (qemuMigrationToFile(driver, vm, fd, offset, path,
2752
                            qemuCompressProgramName(compressed),
E
Eric Blake 已提交
2753
                            bypassSecurityDriver,
2754 2755
                            asyncJob) < 0)
        goto cleanup;
E
Eric Blake 已提交
2756

2757 2758 2759 2760 2761 2762 2763 2764
    /* 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);
2765
        goto cleanup;
E
Eric Blake 已提交
2766
    }
2767

2768
    if (virFileWrapperFdClose(wrapperFd) < 0)
2769 2770 2771 2772
        goto cleanup;

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

2774
    memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic));
2775

E
Eric Blake 已提交
2776 2777
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        virReportSystemError(errno, _("unable to write %s"), path);
2778
        goto cleanup;
E
Eric Blake 已提交
2779
    }
2780

2781 2782
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
2783
        goto cleanup;
2784 2785
    }

2786 2787
    ret = 0;

2788 2789 2790
cleanup:
    VIR_FORCE_CLOSE(fd);
    virFileWrapperFdFree(wrapperFd);
2791
    VIR_FREE(xml);
2792 2793 2794 2795 2796 2797 2798

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

    return ret;
}

2799
/* The vm must be active + locked. Vm will be unlocked and
2800 2801 2802 2803 2804
 * 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
2805
qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
2806 2807 2808 2809 2810 2811 2812 2813 2814
                       virDomainObjPtr vm, const char *path,
                       int compressed, const char *xmlin, unsigned int flags)
{
    char *xml = NULL;
    bool was_running = false;
    int ret = -1;
    int rc;
    virDomainEventPtr event = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2815 2816 2817 2818
    virCapsPtr caps;

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

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

2823
    if (qemuDomainObjBeginAsyncJob(driver, vm,
2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855
                                             QEMU_ASYNC_JOB_SAVE) < 0)

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

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

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

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

    /* Get XML for the domain.  Restore needs only the inactive xml,
     * including secure.  We should get the same result whether xmlin
     * is NULL or whether it was the live xml of the domain moments
     * before.  */
    if (xmlin) {
        virDomainDefPtr def = NULL;

2856
        if (!(def = virDomainDefParseString(xmlin, caps, driver->xmlopt,
2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879
                                            QEMU_EXPECTED_VIRT_TYPES,
                                            VIR_DOMAIN_XML_INACTIVE))) {
            goto endjob;
        }
        if (!virDomainDefCheckABIStability(vm->def, def)) {
            virDomainDefFree(def);
            goto endjob;
        }
        xml = qemuDomainDefFormatLive(driver, def, true, true);
    } else {
        xml = qemuDomainDefFormatLive(driver, vm->def, true, true);
    }
    if (!xml) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to get domain xml"));
        goto endjob;
    }

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

2880
    /* Shut it down */
2881
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED, 0);
2882
    virDomainAuditStop(vm, "saved");
2883 2884 2885
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
2886
    if (!vm->persistent) {
2887
        if (qemuDomainObjEndAsyncJob(driver, vm) > 0)
2888
            qemuDomainRemoveInactive(driver, vm);
2889 2890
        vm = NULL;
    }
2891

2892
endjob:
2893
    if (vm) {
2894
        if (ret != 0) {
2895
            if (was_running && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
2896
                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
2897 2898
                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED,
                                          QEMU_ASYNC_JOB_SAVE);
2899
                if (rc < 0) {
2900
                    VIR_WARN("Unable to resume guest CPUs after save failure");
2901 2902 2903 2904
                    event = virDomainEventNewFromObj(vm,
                                                     VIR_DOMAIN_EVENT_SUSPENDED,
                                                     VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
                }
2905
            }
2906
        }
2907
        if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
2908
            vm = NULL;
2909
    }
2910

2911 2912
cleanup:
    VIR_FREE(xml);
2913 2914
    if (event)
        qemuDomainEventQueue(driver, event);
2915
    if (vm)
2916
        virObjectUnlock(vm);
2917
    virObjectUnref(caps);
2918
    return ret;
D
Daniel P. Berrange 已提交
2919 2920
}

2921
/* Returns true if a compression program is available in PATH */
2922
static bool qemuCompressProgramAvailable(virQEMUSaveFormat compress)
2923 2924 2925 2926
{
    const char *prog;
    char *c;

2927
    if (compress == QEMU_SAVE_FORMAT_RAW)
2928
        return true;
2929
    prog = qemuSaveCompressionTypeToString(compress);
2930 2931 2932 2933 2934 2935 2936
    c = virFindFileInPath(prog);
    if (!c)
        return false;
    VIR_FREE(c);
    return true;
}

2937 2938 2939
static int
qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                    unsigned int flags)
2940
{
2941
    virQEMUDriverPtr driver = dom->conn->privateData;
2942
    int compressed;
2943 2944
    int ret = -1;
    virDomainObjPtr vm = NULL;
2945
    virQEMUDriverConfigPtr cfg = NULL;
2946

2947 2948 2949
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
2950

2951 2952
    cfg = virQEMUDriverGetConfig(driver);
    if (cfg->saveImageFormat == NULL)
2953
        compressed = QEMU_SAVE_FORMAT_RAW;
2954
    else {
2955
        compressed = qemuSaveCompressionTypeFromString(cfg->saveImageFormat);
2956
        if (compressed < 0) {
2957 2958 2959
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Invalid save image format specified "
                                   "in configuration file"));
2960
            goto cleanup;
2961
        }
2962
        if (!qemuCompressProgramAvailable(compressed)) {
2963 2964 2965
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Compression program for image format "
                                   "in configuration file isn't available"));
2966
            goto cleanup;
2967
        }
2968 2969
    }

2970
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2971 2972 2973
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2974 2975
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2976 2977 2978
        goto cleanup;
    }

2979
    if (!virDomainObjIsActive(vm)) {
2980 2981
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2982 2983 2984
        goto cleanup;
    }

2985
    ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
2986
                                 dxml, flags);
2987
    vm = NULL;
2988 2989 2990

cleanup:
    if (vm)
2991
        virObjectUnlock(vm);
2992
    virObjectUnref(cfg);
2993
    return ret;
2994 2995
}

2996 2997 2998 2999 3000 3001
static int
qemuDomainSave(virDomainPtr dom, const char *path)
{
    return qemuDomainSaveFlags(dom, path, NULL, 0);
}

3002
static char *
3003 3004
qemuDomainManagedSavePath(virQEMUDriverPtr driver, virDomainObjPtr vm)
{
3005
    char *ret;
3006
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3007

3008
    if (virAsprintf(&ret, "%s/%s.save", cfg->saveDir, vm->def->name) < 0) {
3009
        virReportOOMError();
3010
        virObjectUnref(cfg);
3011
        return NULL;
3012 3013
    }

3014
    virObjectUnref(cfg);
3015
    return ret;
3016 3017 3018 3019 3020
}

static int
qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
3021
    virQEMUDriverPtr driver = dom->conn->privateData;
3022
    virDomainObjPtr vm;
3023 3024 3025 3026
    char *name = NULL;
    int ret = -1;
    int compressed;

3027 3028 3029
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3030

3031
    if (!(vm = qemuDomObjFromDomain(dom)))
3032
        return -1;
3033

3034
    if (!virDomainObjIsActive(vm)) {
3035 3036
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3037 3038
        goto cleanup;
    }
3039
    if (!vm->persistent) {
3040 3041
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
3042 3043
        goto cleanup;
    }
3044

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

3048
    VIR_INFO("Saving state to %s", name);
3049

3050
    compressed = QEMU_SAVE_FORMAT_RAW;
3051 3052 3053 3054
    if ((ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
                                      NULL, flags)) == 0)
        vm->hasManagedSave = true;

3055
    vm = NULL;
3056 3057 3058

cleanup:
    if (vm)
3059
        virObjectUnlock(vm);
3060 3061 3062
    VIR_FREE(name);

    return ret;
3063 3064
}

3065 3066
static int
qemuDomainManagedSaveLoad(virDomainObjPtr vm,
3067 3068
                          void *opaque)
{
3069
    virQEMUDriverPtr driver = opaque;
3070
    char *name;
3071
    int ret = -1;
3072

3073
    virObjectLock(vm);
3074 3075 3076 3077 3078 3079

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

    vm->hasManagedSave = virFileExists(name);

3080
    ret = 0;
3081
cleanup:
3082
    virObjectUnlock(vm);
3083
    VIR_FREE(name);
3084
    return ret;
3085 3086
}

3087

3088 3089 3090 3091
static int
qemuDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
3092
    int ret;
3093

3094
    virCheckFlags(0, -1);
3095

3096 3097
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
3098

3099
    ret = vm->hasManagedSave;
3100
    virObjectUnlock(vm);
3101 3102 3103 3104 3105 3106
    return ret;
}

static int
qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
3107
    virQEMUDriverPtr driver = dom->conn->privateData;
3108
    virDomainObjPtr vm;
3109 3110 3111
    int ret = -1;
    char *name = NULL;

3112
    virCheckFlags(0, -1);
3113

3114
    if (!(vm = qemuDomObjFromDomain(dom)))
3115
        return -1;
3116

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

3120 3121 3122 3123 3124 3125 3126
    if (unlink(name) < 0) {
        virReportSystemError(errno,
                             _("Failed to remove managed save file '%s'"),
                             name);
        goto cleanup;
    }

3127
    vm->hasManagedSave = false;
3128
    ret = 0;
3129 3130 3131

cleanup:
    VIR_FREE(name);
3132
    virObjectUnlock(vm);
3133 3134
    return ret;
}
D
Daniel P. Berrange 已提交
3135

3136
static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
3137 3138 3139 3140 3141
                        int fd, enum qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

3142
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
3143
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3144
                       _("dump-guest-memory is not supported"));
3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156
        return -1;
    }

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

    priv->job.dump_memory_only = true;

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

3157
    ret = qemuMonitorDumpToFd(priv->mon, fd);
3158
    qemuDomainObjExitMonitor(driver, vm);
3159 3160 3161 3162

    return ret;
}

3163
static int
3164
doCoreDump(virQEMUDriverPtr driver,
3165 3166
           virDomainObjPtr vm,
           const char *path,
3167
           virQEMUSaveFormat compress,
3168
           unsigned int dump_flags)
H
Hu Tao 已提交
3169 3170 3171
{
    int fd = -1;
    int ret = -1;
J
Jiri Denemark 已提交
3172
    virFileWrapperFdPtr wrapperFd = NULL;
3173
    int directFlag = 0;
3174
    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
H
Hu Tao 已提交
3175 3176

    /* Create an empty file with appropriate ownership.  */
3177
    if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
3178
        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
3179 3180
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
3181 3182
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
3183 3184 3185
            goto cleanup;
        }
    }
E
Eric Blake 已提交
3186 3187 3188 3189 3190 3191
    /* Core dumps usually imply last-ditch analysis efforts are
     * desired, so we intentionally do not unlink even if a file was
     * created.  */
    if ((fd = qemuOpenFile(driver, path,
                           O_CREAT | O_TRUNC | O_WRONLY | directFlag,
                           NULL, NULL)) < 0)
H
Hu Tao 已提交
3192 3193
        goto cleanup;

3194
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags)))
3195 3196
        goto cleanup;

3197 3198 3199 3200 3201 3202 3203 3204 3205
    if (dump_flags & VIR_DUMP_MEMORY_ONLY) {
        ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP);
    } else {
        ret = qemuMigrationToFile(driver, vm, fd, 0, path,
                                  qemuCompressProgramName(compress), false,
                                  QEMU_ASYNC_JOB_DUMP);
    }

    if (ret < 0)
3206 3207
        goto cleanup;

H
Hu Tao 已提交
3208 3209
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
3210
                             _("unable to close file %s"),
H
Hu Tao 已提交
3211 3212 3213
                             path);
        goto cleanup;
    }
J
Jiri Denemark 已提交
3214
    if (virFileWrapperFdClose(wrapperFd) < 0)
3215
        goto cleanup;
H
Hu Tao 已提交
3216

3217
    ret = 0;
H
Hu Tao 已提交
3218 3219

cleanup:
3220
    VIR_FORCE_CLOSE(fd);
3221
    if (ret != 0)
H
Hu Tao 已提交
3222
        unlink(path);
3223
    virFileWrapperFdFree(wrapperFd);
H
Hu Tao 已提交
3224 3225 3226
    return ret;
}

3227
static virQEMUSaveFormat
3228
getCompressionType(virQEMUDriverPtr driver)
3229
{
3230 3231
    int ret = QEMU_SAVE_FORMAT_RAW;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3232

3233 3234 3235 3236
    /*
     * We reuse "save" flag for "dump" here. Then, we can support the same
     * format in "save" and "dump".
     */
3237 3238
    if (cfg->dumpImageFormat) {
        ret = qemuSaveCompressionTypeFromString(cfg->dumpImageFormat);
3239 3240 3241
        /* Use "raw" as the format if the specified format is not valid,
         * or the compress program is not available.
         */
3242
        if (ret < 0) {
3243 3244
            VIR_WARN("%s", _("Invalid dump image format specified in "
                             "configuration file, using raw"));
3245 3246
            ret = QEMU_SAVE_FORMAT_RAW;
            goto cleanup;
3247
        }
3248
        if (!qemuCompressProgramAvailable(ret)) {
3249 3250 3251
            VIR_WARN("%s", _("Compression program for dump image format "
                             "in configuration file isn't available, "
                             "using raw"));
3252 3253
            ret = QEMU_SAVE_FORMAT_RAW;
            goto cleanup;
3254
        }
3255
    }
3256 3257 3258
cleanup:
    virObjectUnref(cfg);
    return ret;
3259 3260
}

3261 3262 3263
static int qemuDomainCoreDump(virDomainPtr dom,
                              const char *path,
                              unsigned int flags)
3264
{
3265
    virQEMUDriverPtr driver = dom->conn->privateData;
3266
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
3267
    qemuDomainObjPrivatePtr priv;
3268
    int resume = 0, paused = 0;
H
Hu Tao 已提交
3269
    int ret = -1;
3270 3271
    virDomainEventPtr event = NULL;

M
Michal Privoznik 已提交
3272
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH |
3273 3274
                  VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET |
                  VIR_DUMP_MEMORY_ONLY, -1);
3275

3276
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
P
Paolo Bonzini 已提交
3277 3278 3279 3280

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3281 3282
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
3283 3284 3285
        goto cleanup;
    }

3286 3287
    if (qemuDomainObjBeginAsyncJob(driver, vm,
                                   QEMU_ASYNC_JOB_DUMP) < 0)
3288 3289
        goto cleanup;

D
Daniel P. Berrange 已提交
3290
    if (!virDomainObjIsActive(vm)) {
3291 3292
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3293
        goto endjob;
P
Paolo Bonzini 已提交
3294 3295
    }

P
Paolo Bonzini 已提交
3296 3297
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
J
Jiri Denemark 已提交
3298
    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
3299 3300

    /* Pause domain for non-live dump */
J
Jiri Denemark 已提交
3301 3302
    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3303 3304
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP,
                                QEMU_ASYNC_JOB_DUMP) < 0)
3305
            goto endjob;
P
Paolo Bonzini 已提交
3306
        paused = 1;
3307 3308

        if (!virDomainObjIsActive(vm)) {
3309 3310
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
3311 3312
            goto endjob;
        }
P
Paolo Bonzini 已提交
3313 3314
    }

3315
    ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags);
3316 3317 3318 3319
    if (ret < 0)
        goto endjob;

    paused = 1;
3320 3321

endjob:
3322
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
3323
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
3324
        virDomainAuditStop(vm, "crashed");
3325 3326 3327 3328 3329
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
3330 3331 3332
    /* Since the monitor is always attached to a pty for libvirt, it
       will support synchronous operations so we always get here after
       the migration is complete.  */
M
Michal Privoznik 已提交
3333 3334 3335 3336
    else if (((resume && paused) || (flags & VIR_DUMP_RESET)) &&
             virDomainObjIsActive(vm)) {
        if ((ret == 0) && (flags & VIR_DUMP_RESET)) {
            priv =  vm->privateData;
3337
            qemuDomainObjEnterMonitor(driver, vm);
M
Michal Privoznik 已提交
3338
            ret = qemuMonitorSystemReset(priv->mon);
3339
            qemuDomainObjExitMonitor(driver, vm);
M
Michal Privoznik 已提交
3340 3341 3342 3343 3344
        }

        if (resume && qemuProcessStartCPUs(driver, vm, dom->conn,
                                           VIR_DOMAIN_RUNNING_UNPAUSED,
                                           QEMU_ASYNC_JOB_DUMP) < 0) {
3345 3346 3347
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
3348
            if (virGetLastError() == NULL)
3349 3350
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3351 3352
        }
    }
3353

3354
    if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3355
        vm = NULL;
3356
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
3357
        qemuDomainRemoveInactive(driver, vm);
3358 3359
        vm = NULL;
    }
3360 3361

cleanup:
P
Paolo Bonzini 已提交
3362
    if (vm)
3363
        virObjectUnlock(vm);
3364 3365
    if (event)
        qemuDomainEventQueue(driver, event);
P
Paolo Bonzini 已提交
3366 3367 3368
    return ret;
}

3369 3370 3371 3372
static char *
qemuDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
3373
                     unsigned int flags)
3374
{
3375
    virQEMUDriverPtr driver = dom->conn->privateData;
3376 3377 3378 3379 3380
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *tmp = NULL;
    int tmp_fd = -1;
    char *ret = NULL;
E
Eric Blake 已提交
3381
    bool unlink_tmp = false;
3382
    virQEMUDriverConfigPtr cfg = NULL;
3383

E
Eric Blake 已提交
3384 3385
    virCheckFlags(0, NULL);

3386
    if (!(vm = qemuDomObjFromDomain(dom)))
3387 3388 3389
        goto cleanup;

    priv = vm->privateData;
3390
    cfg = virQEMUDriverGetConfig(driver);
3391

3392
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3393 3394 3395
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
3396 3397
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3398 3399 3400 3401 3402 3403
        goto endjob;
    }

    /* Well, even if qemu allows multiple graphic cards, heads, whatever,
     * screenshot command does not */
    if (screen) {
3404 3405 3406
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("currently is supported only taking "
                               "screenshots of screen ID 0"));
3407 3408 3409
        goto endjob;
    }

3410
    if (virAsprintf(&tmp, "%s/qemu.screendump.XXXXXX", cfg->cacheDir) < 0) {
3411 3412 3413 3414
        virReportOOMError();
        goto endjob;
    }

3415 3416
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
3417 3418
        goto endjob;
    }
E
Eric Blake 已提交
3419
    unlink_tmp = true;
3420

3421
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
3422

3423
    qemuDomainObjEnterMonitor(driver, vm);
3424
    if (qemuMonitorScreendump(priv->mon, tmp) < 0) {
3425
        qemuDomainObjExitMonitor(driver, vm);
3426 3427
        goto endjob;
    }
3428
    qemuDomainObjExitMonitor(driver, vm);
3429 3430 3431 3432 3433 3434

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

E
Eric Blake 已提交
3435
    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
3436 3437
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to open stream"));
3438 3439 3440 3441 3442 3443 3444
        goto endjob;
    }

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

endjob:
    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
3445 3446
    if (unlink_tmp)
        unlink(tmp);
E
Eric Blake 已提交
3447
    VIR_FREE(tmp);
3448

3449
    if (qemuDomainObjEndJob(driver, vm) == 0)
3450 3451 3452 3453
        vm = NULL;

cleanup:
    if (vm)
3454
        virObjectUnlock(vm);
3455
    virObjectUnref(cfg);
3456 3457 3458
    return ret;
}

H
Hu Tao 已提交
3459 3460 3461
static void processWatchdogEvent(void *data, void *opaque)
{
    int ret;
3462
    struct qemuDomainWatchdogEvent *wdEvent = data;
3463
    virQEMUDriverPtr driver = opaque;
3464
    virQEMUDriverConfigPtr cfg;
H
Hu Tao 已提交
3465

3466
    virObjectLock(wdEvent->vm);
3467
    cfg = virQEMUDriverGetConfig(driver);
W
Wen Congyang 已提交
3468

H
Hu Tao 已提交
3469 3470 3471 3472
    switch (wdEvent->action) {
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;
3473
            unsigned int flags = 0;
H
Hu Tao 已提交
3474

E
Eric Blake 已提交
3475
            if (virAsprintf(&dumpfile, "%s/%s-%u",
3476
                            cfg->autoDumpPath,
H
Hu Tao 已提交
3477
                            wdEvent->vm->def->name,
E
Eric Blake 已提交
3478 3479
                            (unsigned int)time(NULL)) < 0) {
                virReportOOMError();
W
Wen Congyang 已提交
3480
                goto unlock;
E
Eric Blake 已提交
3481
            }
H
Hu Tao 已提交
3482

3483
            if (qemuDomainObjBeginAsyncJob(driver, wdEvent->vm,
3484
                                                     QEMU_ASYNC_JOB_DUMP) < 0) {
W
Wen Congyang 已提交
3485 3486 3487
                VIR_FREE(dumpfile);
                goto unlock;
            }
H
Hu Tao 已提交
3488 3489

            if (!virDomainObjIsActive(wdEvent->vm)) {
3490 3491
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
W
Wen Congyang 已提交
3492 3493
                VIR_FREE(dumpfile);
                goto endjob;
H
Hu Tao 已提交
3494 3495
            }

3496
            flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
3497
            ret = doCoreDump(driver, wdEvent->vm, dumpfile,
3498
                             getCompressionType(driver), flags);
H
Hu Tao 已提交
3499
            if (ret < 0)
3500 3501
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Dump failed"));
H
Hu Tao 已提交
3502

J
Jiri Denemark 已提交
3503
            ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL,
3504 3505
                                       VIR_DOMAIN_RUNNING_UNPAUSED,
                                       QEMU_ASYNC_JOB_DUMP);
H
Hu Tao 已提交
3506 3507

            if (ret < 0)
3508 3509
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Resuming after dump failed"));
H
Hu Tao 已提交
3510 3511 3512 3513

            VIR_FREE(dumpfile);
        }
        break;
W
Wen Congyang 已提交
3514 3515
    default:
        goto unlock;
H
Hu Tao 已提交
3516 3517
    }

W
Wen Congyang 已提交
3518 3519 3520 3521
endjob:
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleWatchdog().
     */
3522
    ignore_value(qemuDomainObjEndAsyncJob(driver, wdEvent->vm));
W
Wen Congyang 已提交
3523 3524

unlock:
3525
    virObjectUnlock(wdEvent->vm);
3526
    virObjectUnref(wdEvent->vm);
H
Hu Tao 已提交
3527
    VIR_FREE(wdEvent);
3528
    virObjectUnref(cfg);
H
Hu Tao 已提交
3529
}
P
Paolo Bonzini 已提交
3530

3531
static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
3532 3533
                                  virDomainObjPtr vm,
                                  unsigned int nvcpus)
3534 3535
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3536
    int i, rc = 1;
3537
    int ret = -1;
3538
    int oldvcpus = vm->def->vcpus;
E
Eric Blake 已提交
3539
    int vcpus = oldvcpus;
3540 3541
    pid_t *cpupids = NULL;
    int ncpupids;
3542 3543
    virCgroupPtr cgroup = NULL;
    virCgroupPtr cgroup_vcpu = NULL;
3544
    bool cgroup_available = false;
3545

3546
    qemuDomainObjEnterMonitor(driver, vm);
3547

3548 3549 3550
    /* 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 已提交
3551 3552
    if (nvcpus > vcpus) {
        for (i = vcpus ; i < nvcpus ; i++) {
3553 3554 3555 3556 3557 3558 3559
            /* Online new CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3560
            vcpus++;
3561 3562
        }
    } else {
E
Eric Blake 已提交
3563
        for (i = vcpus - 1 ; i >= nvcpus ; i--) {
3564 3565 3566 3567 3568 3569 3570
            /* Offline old CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3571
            vcpus--;
3572 3573 3574
        }
    }

3575 3576
    /* hotplug succeeded */

3577 3578
    ret = 0;

3579 3580 3581 3582 3583 3584 3585 3586 3587 3588
    /* 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;
    }

3589 3590 3591 3592 3593 3594 3595 3596 3597
    /* 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;
    }

3598
    if (ncpupids != vcpus) {
3599 3600 3601 3602
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("got wrong number of vCPU pids from QEMU monitor. "
                         "got %d, wanted %d"),
                       ncpupids, vcpus);
3603 3604 3605 3606
        ret = -1;
        goto cleanup;
    }

3607 3608
    cgroup_available = (virCgroupForDomain(driver->cgroup, vm->def->name,
                                           &cgroup, 0) == 0);
3609

3610 3611 3612 3613
    if (nvcpus > oldvcpus) {
        for (i = oldvcpus; i < nvcpus; i++) {
            if (cgroup_available) {
                int rv = -1;
3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632
                /* Create cgroup for the onlined vcpu */
                rv = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 1);
                if (rv < 0) {
                    virReportSystemError(-rv,
                                         _("Unable to create vcpu cgroup for %s(vcpu:"
                                           " %d)"),
                                         vm->def->name, i);
                    goto cleanup;
                }

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

3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668
            /* Inherit def->cpuset */
            if (vm->def->cpumask) {
                /* vm->def->cputune.vcpupin can't be NULL if
                 * vm->def->cpumask is not NULL.
                 */
                virDomainVcpuPinDefPtr vcpupin = NULL;

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

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

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

                if (cgroup_available) {
                    if (qemuSetupCgroupVcpuPin(cgroup_vcpu,
                                               vm->def->cputune.vcpupin,
                                               vm->def->cputune.nvcpupin, i) < 0) {
                        virReportError(VIR_ERR_OPERATION_INVALID,
                                       _("failed to set cpuset.cpus in cgroup"
                                         " for vcpu %d"), i);
                        ret = -1;
                        goto cleanup;
                    }
                } else {
3669 3670
                    if (virProcessSetAffinity(cpupids[i],
                                              vcpupin->cpumask) < 0) {
3671 3672 3673 3674 3675 3676 3677
                        virReportError(VIR_ERR_SYSTEM_ERROR,
                                       _("failed to set cpu affinity for vcpu %d"),
                                       i);
                        ret = -1;
                        goto cleanup;
                    }
                }
3678
            }
3679 3680

            virCgroupFree(&cgroup_vcpu);
G
Guido Günther 已提交
3681
        }
3682 3683 3684 3685 3686 3687 3688
    } else {
        for (i = oldvcpus - 1; i >= nvcpus; i--) {
            virDomainVcpuPinDefPtr vcpupin = NULL;

            if (cgroup_available) {
                int rv = -1;

3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702
                rv = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 0);
                if (rv < 0) {
                    virReportSystemError(-rv,
                                         _("Unable to access vcpu cgroup for %s(vcpu:"
                                           " %d)"),
                                         vm->def->name, i);
                    goto cleanup;
                }

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

3703 3704 3705 3706 3707
            /* Free vcpupin setting */
            if ((vcpupin = virDomainLookupVcpuPin(vm->def, i))) {
                VIR_FREE(vcpupin);
            }
        }
3708 3709
    }

3710 3711 3712 3713 3714
    priv->nvcpupids = ncpupids;
    VIR_FREE(priv->vcpupids);
    priv->vcpupids = cpupids;
    cpupids = NULL;

3715
cleanup:
3716
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
3717
    vm->def->vcpus = vcpus;
3718
    VIR_FREE(cpupids);
3719
    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
3720 3721 3722 3723
    if (cgroup)
        virCgroupFree(&cgroup);
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
3724 3725 3726
    return ret;

unsupported:
3727 3728
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("cannot change vcpu count of this domain"));
3729 3730 3731 3732
    goto cleanup;
}


3733
static int
3734 3735
qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3736
{
3737
    virQEMUDriverPtr driver = dom->conn->privateData;
3738
    virDomainObjPtr vm = NULL;
3739
    virDomainDefPtr persistentDef;
3740 3741
    const char * type;
    int max;
3742
    int ret = -1;
3743
    bool maximum;
3744
    virQEMUDriverConfigPtr cfg = NULL;
3745
    virCapsPtr caps = NULL;
3746

3747 3748
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
3749 3750 3751
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
3752 3753
        virReportError(VIR_ERR_INVALID_ARG,
                       _("argument out of range: %d"), nvcpus);
3754 3755 3756
        return -1;
    }

3757
    cfg = virQEMUDriverGetConfig(driver);
3758 3759
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;
3760

3761
    if (!(vm = qemuDomObjFromDomain(dom)))
3762
        goto cleanup;
3763

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

3767 3768 3769
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

3770
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
3771 3772
                                        &persistentDef) < 0)
        goto endjob;
3773 3774 3775

    /* MAXIMUM cannot be mixed with LIVE.  */
    if (maximum && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
3776 3777
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("cannot adjust maximum on running domain"));
3778 3779 3780
        goto endjob;
    }

3781
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
3782 3783 3784
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
3785 3786 3787
        goto endjob;
    }

3788
    if ((max = qemuGetMaxVCPUs(NULL, type)) < 0) {
3789 3790
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
3791 3792 3793
        goto endjob;
    }

3794
    if (!maximum && vm->def->maxvcpus < max) {
3795 3796 3797
        max = vm->def->maxvcpus;
    }

3798
    if (nvcpus > max) {
3799 3800 3801
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), nvcpus, max);
3802 3803 3804
        goto endjob;
    }

3805
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3806
        if (qemuDomainHotplugVcpus(driver, vm, nvcpus) < 0)
3807 3808 3809 3810
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
3811 3812 3813 3814 3815 3816 3817
        if (maximum) {
            persistentDef->maxvcpus = nvcpus;
            if (nvcpus < persistentDef->vcpus)
                persistentDef->vcpus = nvcpus;
        } else {
            persistentDef->vcpus = nvcpus;
        }
3818

3819
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
3820
            goto endjob;
3821
    }
3822

3823
    ret = 0;
3824

3825
endjob:
3826
    if (qemuDomainObjEndJob(driver, vm) == 0)
3827
        vm = NULL;
3828

3829
cleanup:
3830
    if (vm)
3831
        virObjectUnlock(vm);
3832
    virObjectUnref(caps);
3833
    virObjectUnref(cfg);
3834
    return ret;
3835 3836
}

3837
static int
3838
qemuDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3839
{
3840
    return qemuDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
3841 3842
}

3843 3844

static int
3845 3846 3847 3848 3849
qemuDomainPinVcpuFlags(virDomainPtr dom,
                       unsigned int vcpu,
                       unsigned char *cpumap,
                       int maplen,
                       unsigned int flags) {
3850

3851
    virQEMUDriverPtr driver = dom->conn->privateData;
3852
    virDomainObjPtr vm;
3853
    virDomainDefPtr persistentDef = NULL;
3854 3855
    virCgroupPtr cgroup_dom = NULL;
    virCgroupPtr cgroup_vcpu = NULL;
3856
    int ret = -1;
3857
    qemuDomainObjPrivatePtr priv;
3858
    bool doReset = false;
3859 3860
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
3861
    virBitmapPtr pcpumap = NULL;
3862
    virQEMUDriverConfigPtr cfg = NULL;
3863
    virCapsPtr caps = NULL;
3864

3865 3866 3867
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

3868 3869
    cfg = virQEMUDriverGetConfig(driver);

3870
    if (!(vm = qemuDomObjFromDomain(dom)))
3871 3872
        goto cleanup;

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

3876
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
3877
                                        &persistentDef) < 0)
3878
        goto cleanup;
3879

3880 3881 3882
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
3883 3884 3885
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu number out of range %d > %d"),
                       vcpu, priv->nvcpupids);
3886
        goto cleanup;
3887 3888
    }

3889 3890 3891 3892
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

3893 3894 3895
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
3896 3897
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
3898

3899
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3900

3901
        if (priv->vcpupids == NULL) {
3902 3903
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
3904 3905 3906
            goto cleanup;
        }

3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921
        if (vm->def->cputune.vcpupin) {
            newVcpuPin = virDomainVcpuPinDefCopy(vm->def->cputune.vcpupin,
                                                 vm->def->cputune.nvcpupin);
            if (!newVcpuPin)
                goto cleanup;

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

3922
        if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, vcpu) < 0) {
3923 3924
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to update vcpupin"));
H
Hu Tao 已提交
3925
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936
            goto cleanup;
        }

        /* Configure the corresponding cpuset cgroup before set affinity. */
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup_dom, 0) == 0 &&
                virCgroupForVcpu(cgroup_dom, vcpu, &cgroup_vcpu, 0) == 0 &&
                qemuSetupCgroupVcpuPin(cgroup_vcpu, newVcpuPin, newVcpuPinNum, vcpu) < 0) {
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("failed to set cpuset.cpus in cgroup"
                                 " for vcpu %d"), vcpu);
3937 3938 3939
                goto cleanup;
            }
        } else {
3940
            if (virProcessSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) {
3941 3942 3943 3944
                virReportError(VIR_ERR_SYSTEM_ERROR,
                               _("failed to set cpu affinity for vcpu %d"),
                               vcpu);
                goto cleanup;
H
Hu Tao 已提交
3945
            }
3946 3947
        }

3948
        if (doReset) {
3949
            if (virDomainVcpuPinDel(vm->def, vcpu) < 0) {
3950
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3951
                               _("failed to delete vcpupin xml of "
3952
                                 "a running domain"));
3953 3954
                goto cleanup;
            }
3955 3956
        } else {
            if (vm->def->cputune.vcpupin)
H
Hu Tao 已提交
3957
                virDomainVcpuPinDefArrayFree(vm->def->cputune.vcpupin, vm->def->cputune.nvcpupin);
3958 3959 3960 3961

            vm->def->cputune.vcpupin = newVcpuPin;
            vm->def->cputune.nvcpupin = newVcpuPinNum;
            newVcpuPin = NULL;
3962 3963
        }

3964
        if (newVcpuPin)
H
Hu Tao 已提交
3965
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
3966

3967
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
3968
            goto cleanup;
3969
    }
3970

3971 3972
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

3973
        if (doReset) {
E
Eric Blake 已提交
3974
            if (virDomainVcpuPinDel(persistentDef, vcpu) < 0) {
3975 3976 3977
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to delete vcpupin xml of "
                                 "a persistent domain"));
3978 3979 3980
                goto cleanup;
            }
        } else {
H
Hu Tao 已提交
3981 3982 3983 3984 3985 3986 3987
            if (!persistentDef->cputune.vcpupin) {
                if (VIR_ALLOC(persistentDef->cputune.vcpupin) < 0) {
                    virReportOOMError();
                    goto cleanup;
                }
                persistentDef->cputune.nvcpupin = 0;
            }
3988
            if (virDomainVcpuPinAdd(&persistentDef->cputune.vcpupin,
H
Hu Tao 已提交
3989 3990 3991 3992
                                    &persistentDef->cputune.nvcpupin,
                                    cpumap,
                                    maplen,
                                    vcpu) < 0) {
3993 3994 3995
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update or add vcpupin xml of "
                                 "a persistent domain"));
3996 3997
                goto cleanup;
            }
3998
        }
3999

4000
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
4001 4002 4003
        goto cleanup;
    }

4004
    ret = 0;
4005

4006
cleanup:
4007 4008 4009 4010
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
    if (cgroup_dom)
        virCgroupFree(&cgroup_dom);
4011
    if (vm)
4012
        virObjectUnlock(vm);
4013
    virBitmapFree(pcpumap);
4014
    virObjectUnref(caps);
4015
    virObjectUnref(cfg);
4016
    return ret;
4017 4018
}

4019
static int
4020
qemuDomainPinVcpu(virDomainPtr dom,
4021 4022 4023
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
4024 4025
    return qemuDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                  VIR_DOMAIN_AFFECT_LIVE);
4026 4027
}

4028
static int
4029 4030 4031 4032 4033
qemuDomainGetVcpuPinInfo(virDomainPtr dom,
                         int ncpumaps,
                         unsigned char *cpumaps,
                         int maplen,
                         unsigned int flags) {
4034

4035
    virQEMUDriverPtr driver = dom->conn->privateData;
E
Eric Blake 已提交
4036
    virDomainObjPtr vm = NULL;
4037 4038 4039 4040
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, vcpu, pcpu;
    int n;
E
Eric Blake 已提交
4041
    virDomainVcpuPinDefPtr *vcpupin_list;
H
Hu Tao 已提交
4042
    virBitmapPtr cpumask = NULL;
4043
    unsigned char *cpumap;
H
Hu Tao 已提交
4044
    bool pinned;
4045
    virCapsPtr caps = NULL;
4046 4047 4048 4049

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4050
    if (!(vm = qemuDomObjFromDomain(dom)))
4051 4052
        goto cleanup;

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

4056
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4057 4058
                                        &targetDef) < 0)
        goto cleanup;
4059 4060 4061 4062 4063

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

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

4067
    if ((hostcpus = nodeGetCPUCount()) < 0)
4068
        goto cleanup;
4069

4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097
    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 已提交
4098 4099 4100
            if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
                goto cleanup;
            if (!pinned)
4101 4102 4103 4104 4105 4106 4107
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

cleanup:
    if (vm)
4108
        virObjectUnlock(vm);
4109
    virObjectUnref(caps);
4110 4111 4112
    return ret;
}

H
Hu Tao 已提交
4113
static int
4114 4115 4116 4117
qemuDomainPinEmulator(virDomainPtr dom,
                      unsigned char *cpumap,
                      int maplen,
                      unsigned int flags)
H
Hu Tao 已提交
4118
{
4119
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4120 4121 4122 4123 4124 4125 4126
    virDomainObjPtr vm;
    virCgroupPtr cgroup_dom = NULL;
    virCgroupPtr cgroup_emulator = NULL;
    pid_t pid;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
4127
    bool doReset = false;
H
Hu Tao 已提交
4128 4129
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4130
    virBitmapPtr pcpumap = NULL;
4131
    virQEMUDriverConfigPtr cfg = NULL;
4132
    virCapsPtr caps = NULL;
H
Hu Tao 已提交
4133 4134 4135 4136

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4137 4138
    cfg = virQEMUDriverGetConfig(driver);

4139
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4140 4141
        goto cleanup;

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

4145 4146 4147 4148 4149 4150 4151
    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;
    }

4152
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
H
Hu Tao 已提交
4153 4154 4155 4156 4157
                                        &persistentDef) < 0)
        goto cleanup;

    priv = vm->privateData;

4158 4159 4160 4161
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

H
Hu Tao 已提交
4162 4163 4164
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4165 4166
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
H
Hu Tao 已提交
4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177

    pid = vm->pid;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {

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

4178
            if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, -1) < 0) {
H
Hu Tao 已提交
4179 4180
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update vcpupin"));
H
Hu Tao 已提交
4181
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193
                goto cleanup;
            }

            if (qemuCgroupControllerActive(driver,
                                           VIR_CGROUP_CONTROLLER_CPUSET)) {
                /*
                 * Configure the corresponding cpuset cgroup.
                 * If no cgroup for domain or hypervisor exists, do nothing.
                 */
                if (virCgroupForDomain(driver->cgroup, vm->def->name,
                                       &cgroup_dom, 0) == 0) {
                    if (virCgroupForEmulator(cgroup_dom, &cgroup_emulator, 0) == 0) {
4194 4195
                        if (qemuSetupCgroupEmulatorPin(cgroup_emulator,
                                                       newVcpuPin[0]->cpumask) < 0) {
H
Hu Tao 已提交
4196 4197 4198 4199 4200 4201 4202 4203
                            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                           _("failed to set cpuset.cpus in cgroup"
                                             " for emulator threads"));
                            goto cleanup;
                        }
                    }
                }
            } else {
4204
                if (virProcessSetAffinity(pid, pcpumap) < 0) {
H
Hu Tao 已提交
4205 4206 4207 4208 4209 4210 4211
                    virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
                                   _("failed to set cpu affinity for "
                                     "emulator threads"));
                    goto cleanup;
                }
            }

4212
            if (doReset) {
H
Hu Tao 已提交
4213 4214 4215 4216 4217 4218 4219
                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 已提交
4220
                virDomainVcpuPinDefFree(vm->def->cputune.emulatorpin);
H
Hu Tao 已提交
4221 4222 4223 4224 4225
                vm->def->cputune.emulatorpin = newVcpuPin[0];
                VIR_FREE(newVcpuPin);
            }

            if (newVcpuPin)
H
Hu Tao 已提交
4226
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4227 4228 4229 4230 4231 4232
        } else {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
            goto cleanup;
        }

4233
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
H
Hu Tao 已提交
4234 4235 4236 4237 4238
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

4239
        if (doReset) {
H
Hu Tao 已提交
4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254
            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;
            }
        }

4255
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
H
Hu Tao 已提交
4256 4257 4258 4259 4260 4261 4262 4263 4264 4265
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (cgroup_emulator)
        virCgroupFree(&cgroup_emulator);
    if (cgroup_dom)
        virCgroupFree(&cgroup_dom);
4266
    virBitmapFree(pcpumap);
4267
    virObjectUnref(caps);
H
Hu Tao 已提交
4268
    if (vm)
4269
        virObjectUnlock(vm);
4270
    virObjectUnref(cfg);
H
Hu Tao 已提交
4271 4272 4273 4274
    return ret;
}

static int
4275 4276 4277 4278
qemuDomainGetEmulatorPinInfo(virDomainPtr dom,
                             unsigned char *cpumaps,
                             int maplen,
                             unsigned int flags)
H
Hu Tao 已提交
4279
{
4280
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4281 4282 4283 4284
    virDomainObjPtr vm = NULL;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, pcpu;
H
Hu Tao 已提交
4285 4286
    virBitmapPtr cpumask = NULL;
    bool pinned;
4287
    virCapsPtr caps = NULL;
H
Hu Tao 已提交
4288 4289 4290 4291

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4292
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4293 4294
        goto cleanup;

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

4298
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
4299
                                        vm, &flags, &targetDef) < 0)
H
Hu Tao 已提交
4300 4301 4302 4303 4304 4305 4306 4307
        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);

4308
    if ((hostcpus = nodeGetCPUCount()) < 0)
H
Hu Tao 已提交
4309
        goto cleanup;
4310

H
Hu Tao 已提交
4311 4312 4313 4314 4315 4316 4317 4318 4319 4320
    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

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

4321 4322 4323 4324 4325
    if (targetDef->cputune.emulatorpin) {
        cpumask = targetDef->cputune.emulatorpin->cpumask;
    } else if (targetDef->cpumask) {
        cpumask = targetDef->cpumask;
    } else {
H
Hu Tao 已提交
4326 4327 4328 4329 4330
        ret = 0;
        goto cleanup;
    }

    for (pcpu = 0; pcpu < maxcpu; pcpu++) {
H
Hu Tao 已提交
4331 4332 4333
        if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
            goto cleanup;
        if (!pinned)
H
Hu Tao 已提交
4334 4335 4336 4337 4338 4339 4340
            VIR_UNUSE_CPU(cpumaps, pcpu);
    }

    ret = 1;

cleanup:
    if (vm)
4341
        virObjectUnlock(vm);
4342
    virObjectUnref(caps);
H
Hu Tao 已提交
4343 4344 4345
    return ret;
}

4346
static int
4347 4348 4349 4350 4351
qemuDomainGetVcpus(virDomainPtr dom,
                   virVcpuInfoPtr info,
                   int maxinfo,
                   unsigned char *cpumaps,
                   int maplen) {
4352
    virDomainObjPtr vm;
4353
    int i, v, maxcpu, hostcpus;
4354
    int ret = -1;
4355
    qemuDomainObjPrivatePtr priv;
4356

4357
    if (!(vm = qemuDomObjFromDomain(dom)))
4358 4359
        goto cleanup;

D
Daniel P. Berrange 已提交
4360
    if (!virDomainObjIsActive(vm)) {
4361 4362 4363
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s",
                       _("cannot list vcpu pinning for an inactive domain"));
4364
        goto cleanup;
4365 4366
    }

4367 4368
    priv = vm->privateData;

4369
    if ((hostcpus = nodeGetCPUCount()) < 0)
4370
        goto cleanup;
4371 4372

    maxcpu = maplen * 8;
4373 4374
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
4375 4376

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

4380 4381 4382 4383 4384 4385
    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;
4386

4387
                if (priv->vcpupids != NULL &&
4388 4389 4390 4391 4392
                    qemuGetProcessInfo(&(info[i].cpuTime),
                                       &(info[i].cpu),
                                       NULL,
                                       vm->pid,
                                       priv->vcpupids[i]) < 0) {
4393
                    virReportSystemError(errno, "%s",
4394 4395 4396
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
4397
            }
4398 4399
        }

4400 4401
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
4402
            if (priv->vcpupids != NULL) {
4403 4404
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
4405 4406 4407
                    virBitmapPtr map = NULL;
                    unsigned char *tmpmap = NULL;
                    int tmpmapLen = 0;
4408

4409 4410
                    if (virProcessGetAffinity(priv->vcpupids[v],
                                              &map, maxcpu) < 0)
4411
                        goto cleanup;
4412 4413 4414 4415 4416 4417 4418
                    virBitmapToData(map, &tmpmap, &tmpmapLen);
                    if (tmpmapLen > maplen)
                        tmpmapLen = maplen;
                    memcpy(cpumap, tmpmap, tmpmapLen);

                    VIR_FREE(tmpmap);
                    virBitmapFree(map);
4419
                }
4420
            } else {
4421 4422
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("cpu affinity is not available"));
4423
                goto cleanup;
4424 4425 4426
            }
        }
    }
4427
    ret = maxinfo;
4428

4429
cleanup:
4430
    if (vm)
4431
        virObjectUnlock(vm);
4432
    return ret;
4433 4434 4435
}


4436
static int
4437
qemuDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
4438
{
4439
    virQEMUDriverPtr driver = dom->conn->privateData;
4440
    virDomainObjPtr vm;
4441
    virDomainDefPtr def;
4442
    int ret = -1;
4443
    virCapsPtr caps = NULL;
4444

4445 4446
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4447 4448
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

4449
    if (!(vm = qemuDomObjFromDomain(dom)))
4450
        goto cleanup;
4451

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

4455
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
4456
                                        vm, &flags, &def) < 0)
4457
        goto cleanup;
4458

4459
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4460
        def = vm->def;
4461 4462
    }

4463
    ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
4464

4465
cleanup:
4466
    if (vm)
4467
        virObjectUnlock(vm);
4468
    virObjectUnref(caps);
4469 4470 4471
    return ret;
}

4472
static int
4473
qemuDomainGetMaxVcpus(virDomainPtr dom)
4474
{
4475 4476
    return qemuDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
4477 4478
}

4479
static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
4480
{
4481
    virQEMUDriverPtr driver = dom->conn->privateData;
4482 4483 4484
    virDomainObjPtr vm;
    int ret = -1;

4485
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
4486

4487 4488
    memset(seclabel, 0, sizeof(*seclabel));

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

4497
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
4498 4499 4500
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517
        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 已提交
4518
    if (virDomainObjIsActive(vm)) {
4519
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
4520
                                              vm->def, vm->pid, seclabel) < 0) {
4521 4522
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
4523
            goto cleanup;
4524 4525 4526 4527 4528 4529 4530
        }
    }

    ret = 0;

cleanup:
    if (vm)
4531
        virObjectUnlock(vm);
4532 4533 4534
    return ret;
}

M
Marcelo Cerri 已提交
4535 4536 4537
static int qemuDomainGetSecurityLabelList(virDomainPtr dom,
                                          virSecurityLabelPtr* seclabels)
{
4538
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Marcelo Cerri 已提交
4539 4540 4541 4542
    virDomainObjPtr vm;
    int i, ret = -1;

    /* Protect domain data with qemu lock */
4543
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
M
Marcelo Cerri 已提交
4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560

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

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

    /*
4561
     * Check the comment in qemuDomainGetSecurityLabel function.
M
Marcelo Cerri 已提交
4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601
     */
    if (!virDomainObjIsActive(vm)) {
        /* No seclabels */
        *seclabels = NULL;
        ret = 0;
    } else {
        int len = 0;
        virSecurityManagerPtr* mgrs = virSecurityManagerGetNested(
                                            driver->securityManager);
        if (!mgrs)
            goto cleanup;

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

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

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

cleanup:
    if (vm)
4602
        virObjectUnlock(vm);
M
Marcelo Cerri 已提交
4603 4604
    return ret;
}
4605 4606


4607 4608
static int qemuNodeGetSecurityModel(virConnectPtr conn,
                                    virSecurityModelPtr secmodel)
4609
{
4610
    virQEMUDriverPtr driver = conn->privateData;
4611
    char *p;
4612
    int ret = 0;
4613
    virCapsPtr caps = NULL;
4614

4615 4616
    memset(secmodel, 0, sizeof(*secmodel));

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

4620
    /* We treat no driver as success, but simply return no data in *secmodel */
4621 4622
    if (caps->host.nsecModels == 0 ||
        caps->host.secModels[0].model == NULL)
4623
        goto cleanup;
4624

4625
    p = caps->host.secModels[0].model;
4626
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
4627 4628 4629
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN-1);
4630 4631
        ret = -1;
        goto cleanup;
4632 4633 4634
    }
    strcpy(secmodel->model, p);

4635
    p = caps->host.secModels[0].doi;
4636
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
4637 4638 4639
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
4640 4641
        ret = -1;
        goto cleanup;
4642 4643
    }
    strcpy(secmodel->doi, p);
4644 4645

cleanup:
4646
    virObjectUnref(caps);
4647
    return ret;
4648 4649
}

E
Eric Blake 已提交
4650
/* Return -1 on most failures after raising error, -2 if edit was specified
4651 4652 4653
 * but xmlin and state (-1 for no change, 0 for paused, 1 for running) do
 * not represent any changes (no error raised), -3 if corrupt image was
 * unlinked (no error raised), and opened fd on success.  */
4654
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
4655
qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
4656 4657
                        const char *path,
                        virDomainDefPtr *ret_def,
4658
                        virQEMUSaveHeaderPtr ret_header,
J
Jiri Denemark 已提交
4659 4660
                        bool bypass_cache,
                        virFileWrapperFdPtr *wrapperFd,
4661 4662
                        const char *xmlin, int state, bool edit,
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
4663
{
W
Wen Congyang 已提交
4664
    int fd = -1;
4665
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
4666 4667
    char *xml = NULL;
    virDomainDefPtr def = NULL;
4668
    int oflags = edit ? O_RDWR : O_RDONLY;
4669
    virCapsPtr caps = NULL;
4670

4671
    if (bypass_cache) {
4672
        int directFlag = virFileDirectFdFlag();
4673
        if (directFlag < 0) {
4674 4675
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
4676 4677
            goto error;
        }
4678
        oflags |= directFlag;
4679
    }
4680

4681 4682 4683
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto error;

E
Eric Blake 已提交
4684 4685
    if ((fd = qemuOpenFile(driver, path, oflags, NULL, NULL)) < 0)
        goto error;
J
Jiri Denemark 已提交
4686 4687 4688
    if (bypass_cache &&
        !(*wrapperFd = virFileWrapperFdNew(&fd, path,
                                           VIR_FILE_WRAPPER_BYPASS_CACHE)))
4689
        goto error;
4690 4691

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
4692 4693 4694 4695 4696 4697 4698 4699 4700
        if (unlink_corrupt) {
            if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove corrupt file: %s"),
                                     path);
                goto error;
            }
            return -3;
        }
4701 4702
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
4703
        goto error;
4704 4705
    }

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

4709
        if (memcmp(header.magic, QEMU_SAVE_PARTIAL,
E
Eric Blake 已提交
4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721
                   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;
            }
        }
4722
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", msg);
J
Jiri Denemark 已提交
4723
        goto error;
4724 4725
    }

4726
    if (header.version > QEMU_SAVE_VERSION) {
4727 4728 4729 4730
        /* convert endianess and try again */
        bswap_header(&header);
    }

4731
    if (header.version > QEMU_SAVE_VERSION) {
4732 4733
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("image version is not supported (%d > %d)"),
4734
                       header.version, QEMU_SAVE_VERSION);
J
Jiri Denemark 已提交
4735
        goto error;
4736 4737
    }

4738
    if (header.xml_len <= 0) {
4739 4740
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
4741
        goto error;
4742 4743
    }

4744 4745
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
J
Jiri Denemark 已提交
4746
        goto error;
4747 4748 4749
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
4750 4751
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
4752
        goto error;
4753 4754
    }

4755 4756
    if (edit && STREQ(xml, xmlin) &&
        (state < 0 || state == header.was_running)) {
4757 4758 4759 4760 4761 4762 4763
        VIR_FREE(xml);
        if (VIR_CLOSE(fd) < 0) {
            virReportSystemError(errno, _("cannot close file: %s"), path);
            goto error;
        }
        return -2;
    }
4764 4765
    if (state >= 0)
        header.was_running = state;
4766

4767
    /* Create a domain from this XML */
4768
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
4769
                                        QEMU_EXPECTED_VIRT_TYPES,
4770
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
4771
        goto error;
4772 4773 4774
    if (xmlin) {
        virDomainDefPtr def2 = NULL;

4775
        if (!(def2 = virDomainDefParseString(xmlin, caps, driver->xmlopt,
4776 4777 4778 4779 4780 4781 4782 4783 4784 4785
                                             QEMU_EXPECTED_VIRT_TYPES,
                                             VIR_DOMAIN_XML_INACTIVE)))
            goto error;
        if (!virDomainDefCheckABIStability(def, def2)) {
            virDomainDefFree(def2);
            goto error;
        }
        virDomainDefFree(def);
        def = def2;
    }
4786

J
Jiri Denemark 已提交
4787
    VIR_FREE(xml);
4788

J
Jiri Denemark 已提交
4789 4790
    *ret_def = def;
    *ret_header = header;
4791

4792 4793
    virObjectUnref(caps);

J
Jiri Denemark 已提交
4794
    return fd;
4795

J
Jiri Denemark 已提交
4796 4797 4798
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
4799
    VIR_FORCE_CLOSE(fd);
4800
    virObjectUnref(caps);
J
Jiri Denemark 已提交
4801 4802 4803 4804

    return -1;
}

4805 4806
static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6)
qemuDomainSaveImageStartVM(virConnectPtr conn,
4807
                           virQEMUDriverPtr driver,
4808 4809
                           virDomainObjPtr vm,
                           int *fd,
4810
                           const virQEMUSaveHeaderPtr header,
4811 4812
                           const char *path,
                           bool start_paused)
J
Jiri Denemark 已提交
4813 4814 4815 4816
{
    int ret = -1;
    virDomainEventPtr event;
    int intermediatefd = -1;
4817
    virCommandPtr cmd = NULL;
4818
    char *errbuf = NULL;
4819
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
J
Jiri Denemark 已提交
4820

4821 4822 4823
    if ((header->version == 2) &&
        (header->compressed != QEMU_SAVE_FORMAT_RAW)) {
        if (!(cmd = qemuCompressGetCommand(header->compressed)))
4824
            goto cleanup;
4825

4826 4827
        intermediatefd = *fd;
        *fd = -1;
4828

4829 4830 4831 4832
        virCommandSetInputFD(cmd, intermediatefd);
        virCommandSetOutputFD(cmd, fd);
        virCommandSetErrorBuffer(cmd, &errbuf);
        virCommandDoAsyncIO(cmd);
4833

4834 4835 4836
        if (virCommandRunAsync(cmd, NULL) < 0) {
            *fd = intermediatefd;
            goto cleanup;
4837 4838
        }
    }
J
Jiri Denemark 已提交
4839

4840
    /* Set the migration source and start it up. */
4841 4842 4843
    ret = qemuProcessStart(conn, driver, vm, "stdio", *fd, path, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
                           VIR_QEMU_PROCESS_START_PAUSED);
J
Jiri Denemark 已提交
4844

4845
    if (intermediatefd != -1) {
4846
        if (ret < 0) {
4847 4848 4849
            /* if there was an error setting up qemu, the intermediate
             * process will wait forever to write to stdout, so we
             * must manually kill it.
4850 4851
             */
            VIR_FORCE_CLOSE(intermediatefd);
4852
            VIR_FORCE_CLOSE(*fd);
4853 4854
        }

4855 4856
        if (virCommandWait(cmd, NULL) < 0) {
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
4857
            ret = -1;
4858
        }
4859
        VIR_DEBUG("Decompression binary stderr: %s", NULLSTR(errbuf));
4860
    }
4861
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
4862

4863 4864 4865
    if (VIR_CLOSE(*fd) < 0) {
        virReportSystemError(errno, _("cannot close file: %s"), path);
        ret = -1;
4866
    }
J
Jiri Denemark 已提交
4867

4868
    if (ret < 0) {
4869
        virDomainAuditStart(vm, "restored", false);
4870
        goto cleanup;
4871
    }
4872

4873 4874 4875
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
4876
    virDomainAuditStart(vm, "restored", true);
J
Jiri Denemark 已提交
4877 4878 4879
    if (event)
        qemuDomainEventQueue(driver, event);

4880

4881 4882
    /* If it was running before, resume it now unless caller requested pause. */
    if (header->was_running && !start_paused) {
J
Jiri Denemark 已提交
4883
        if (qemuProcessStartCPUs(driver, vm, conn,
4884 4885
                                 VIR_DOMAIN_RUNNING_RESTORED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
4886
            if (virGetLastError() == NULL)
4887 4888
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("failed to resume domain"));
4889
            goto cleanup;
4890
        }
4891
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
4892
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
4893
            goto cleanup;
4894
        }
4895 4896 4897 4898 4899 4900 4901 4902
    } else {
        int detail = (start_paused ? VIR_DOMAIN_EVENT_SUSPENDED_PAUSED :
                      VIR_DOMAIN_EVENT_SUSPENDED_RESTORED);
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         detail);
        if (event)
            qemuDomainEventQueue(driver, event);
4903
    }
J
Jiri Denemark 已提交
4904

4905
    ret = 0;
4906

4907
cleanup:
4908
    virCommandFree(cmd);
4909
    VIR_FREE(errbuf);
4910
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
4911
                                                 vm->def, path) < 0)
4912
        VIR_WARN("failed to restore save state label on %s", path);
4913
    virObjectUnref(cfg);
J
Jiri Denemark 已提交
4914 4915 4916
    return ret;
}

4917
static int
4918 4919 4920 4921
qemuDomainRestoreFlags(virConnectPtr conn,
                       const char *path,
                       const char *dxml,
                       unsigned int flags)
4922
{
4923
    virQEMUDriverPtr driver = conn->privateData;
J
Jiri Denemark 已提交
4924 4925 4926 4927
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    int ret = -1;
4928
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
4929
    virFileWrapperFdPtr wrapperFd = NULL;
4930
    int state = -1;
J
Jiri Denemark 已提交
4931

4932 4933 4934
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
4935

J
Jiri Denemark 已提交
4936

4937 4938 4939 4940 4941
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

4942 4943
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
J
Jiri Denemark 已提交
4944
                                 &wrapperFd, dxml, state, false, false);
J
Jiri Denemark 已提交
4945 4946 4947
    if (fd < 0)
        goto cleanup;

4948
    if (!(vm = virDomainObjListAdd(driver->domains, def,
4949
                                   driver->xmlopt,
4950 4951 4952
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jiri Denemark 已提交
4953 4954 4955
        goto cleanup;
    def = NULL;

4956
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
4957 4958
        goto cleanup;

4959 4960
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     false);
J
Jiri Denemark 已提交
4961
    if (virFileWrapperFdClose(wrapperFd) < 0)
4962
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
4963

4964
    if (qemuDomainObjEndJob(driver, vm) == 0)
4965
        vm = NULL;
J
Jiri Denemark 已提交
4966
    else if (ret < 0 && !vm->persistent) {
4967
        qemuDomainRemoveInactive(driver, vm);
J
Jiri Denemark 已提交
4968 4969
        vm = NULL;
    }
4970

4971 4972
cleanup:
    virDomainDefFree(def);
4973
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
4974
    virFileWrapperFdFree(wrapperFd);
4975
    if (vm)
4976
        virObjectUnlock(vm);
4977
    return ret;
D
Daniel P. Berrange 已提交
4978 4979
}

4980 4981 4982 4983 4984 4985 4986
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

4987 4988 4989 4990
static char *
qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
                              unsigned int flags)
{
4991
    virQEMUDriverPtr driver = conn->privateData;
4992 4993 4994
    char *ret = NULL;
    virDomainDefPtr def = NULL;
    int fd = -1;
4995
    virQEMUSaveHeader header;
4996 4997 4998 4999 5000

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

    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5001
                                 NULL, -1, false, false);
5002 5003 5004 5005

    if (fd < 0)
        goto cleanup;

5006
    ret = qemuDomainDefFormatXML(driver, def, flags);
5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017

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

static int
qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
                             const char *dxml, unsigned int flags)
{
5018
    virQEMUDriverPtr driver = conn->privateData;
5019 5020 5021
    int ret = -1;
    virDomainDefPtr def = NULL;
    int fd = -1;
5022
    virQEMUSaveHeader header;
5023 5024
    char *xml = NULL;
    size_t len;
5025
    int state = -1;
5026

5027 5028
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5029

5030 5031 5032 5033 5034
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

5035
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5036
                                 dxml, state, true, false);
5037 5038 5039 5040 5041 5042 5043 5044

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

5045 5046
    xml = qemuDomainDefFormatXML(driver, def,
                                 VIR_DOMAIN_XML_INACTIVE |
5047 5048
                                 VIR_DOMAIN_XML_SECURE |
                                 VIR_DOMAIN_XML_MIGRATABLE);
5049 5050 5051 5052 5053
    if (!xml)
        goto cleanup;
    len = strlen(xml) + 1;

    if (len > header.xml_len) {
5054 5055
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("new xml too large to fit in file"));
5056 5057 5058 5059 5060 5061 5062
        goto cleanup;
    }
    if (VIR_EXPAND_N(xml, len, header.xml_len - len) < 0) {
        virReportOOMError();
        goto cleanup;
    }

5063
    if (lseek(fd, 0, SEEK_SET) != 0) {
5064 5065 5066
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
5067 5068
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082
        VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("failed to write xml to '%s'"), path);
        goto cleanup;
    }

    ret = 0;

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

E
Eric Blake 已提交
5083 5084
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
5085 5086
static int
qemuDomainObjRestore(virConnectPtr conn,
5087
                     virQEMUDriverPtr driver,
5088
                     virDomainObjPtr vm,
5089
                     const char *path,
5090
                     bool start_paused,
5091
                     bool bypass_cache)
J
Jiri Denemark 已提交
5092 5093 5094 5095
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    int ret = -1;
5096
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5097
    virFileWrapperFdPtr wrapperFd = NULL;
J
Jiri Denemark 已提交
5098

5099
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
J
Jiri Denemark 已提交
5100
                                 bypass_cache, &wrapperFd, NULL, -1, false,
5101
                                 true);
E
Eric Blake 已提交
5102 5103 5104
    if (fd < 0) {
        if (fd == -3)
            ret = 1;
J
Jiri Denemark 已提交
5105
        goto cleanup;
E
Eric Blake 已提交
5106
    }
J
Jiri Denemark 已提交
5107 5108 5109 5110 5111 5112 5113

    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);
5114 5115 5116 5117 5118
        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 已提交
5119 5120 5121
        goto cleanup;
    }

5122
    virDomainObjAssignDef(vm, def, true, NULL);
J
Jiri Denemark 已提交
5123 5124
    def = NULL;

5125 5126
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     start_paused);
J
Jiri Denemark 已提交
5127
    if (virFileWrapperFdClose(wrapperFd) < 0)
5128
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5129 5130 5131

cleanup:
    virDomainDefFree(def);
5132
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5133
    virFileWrapperFdFree(wrapperFd);
J
Jiri Denemark 已提交
5134 5135 5136
    return ret;
}

D
Daniel P. Berrange 已提交
5137

5138
static char *qemuDomainGetXMLDesc(virDomainPtr dom,
5139 5140
                                  unsigned int flags)
{
5141
    virQEMUDriverPtr driver = dom->conn->privateData;
5142 5143
    virDomainObjPtr vm;
    char *ret = NULL;
5144
    unsigned long long balloon;
5145
    int err = 0;
5146
    qemuDomainObjPrivatePtr priv;
5147

5148
    /* Flags checked by virDomainDefFormat */
5149

5150
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
5151

D
Daniel P. Berrange 已提交
5152
    if (!vm) {
5153 5154
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5155 5156
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
5157
        goto cleanup;
D
Daniel P. Berrange 已提交
5158 5159
    }

5160 5161
    priv = vm->privateData;

5162 5163 5164
    /* Refresh current memory based on balloon info if supported */
    if ((vm->def->memballoon != NULL) &&
        (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
5165
        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT) &&
5166
        (virDomainObjIsActive(vm))) {
5167 5168
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
5169
        if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
5170
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
5171 5172
                goto cleanup;

5173
            if (!virDomainObjIsActive(vm)) {
5174 5175
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
5176 5177 5178
                goto endjob;
            }

5179
            qemuDomainObjEnterMonitor(driver, vm);
5180
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
5181
            qemuDomainObjExitMonitor(driver, vm);
5182 5183

endjob:
5184
            if (qemuDomainObjEndJob(driver, vm) == 0) {
5185 5186 5187
                vm = NULL;
                goto cleanup;
            }
5188 5189 5190
            if (err < 0)
                goto cleanup;
            if (err > 0)
5191
                vm->def->mem.cur_balloon = balloon;
5192 5193
            /* err == 0 indicates no balloon support, so ignore it */
        }
5194
    }
5195

5196 5197 5198 5199
    if ((flags & VIR_DOMAIN_XML_MIGRATABLE))
        flags |= QEMU_DOMAIN_FORMAT_LIVE_FLAGS;

    ret = qemuDomainFormatXML(driver, vm, flags);
5200 5201

cleanup:
5202
    if (vm)
5203
        virObjectUnlock(vm);
5204
    return ret;
D
Daniel P. Berrange 已提交
5205 5206 5207
}


5208 5209 5210
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
E
Eric Blake 已提交
5211 5212
                                     unsigned int flags)
{
5213
    virQEMUDriverPtr driver = conn->privateData;
5214 5215
    virDomainDefPtr def = NULL;
    char *xml = NULL;
5216
    virCapsPtr caps = NULL;
5217

E
Eric Blake 已提交
5218 5219
    virCheckFlags(0, NULL);

5220
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5221 5222
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5223 5224 5225
        goto cleanup;
    }

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

5229
    def = qemuParseCommandLineString(caps, driver->xmlopt, config,
5230
                                     NULL, NULL, NULL);
5231 5232 5233
    if (!def)
        goto cleanup;

5234 5235 5236 5237 5238 5239
    if (!def->name &&
        !(def->name = strdup("unnamed"))) {
        virReportOOMError();
        goto cleanup;
    }

5240
    xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE);
5241 5242 5243

cleanup:
    virDomainDefFree(def);
5244
    virObjectUnref(caps);
5245 5246 5247
    return xml;
}

5248 5249 5250
static char *qemuDomainXMLToNative(virConnectPtr conn,
                                   const char *format,
                                   const char *xmlData,
E
Eric Blake 已提交
5251 5252
                                   unsigned int flags)
{
5253
    virQEMUDriverPtr driver = conn->privateData;
5254
    virDomainDefPtr def = NULL;
5255
    virDomainChrSourceDef monConfig;
5256
    virQEMUCapsPtr qemuCaps = NULL;
T
tangchen 已提交
5257
    bool monitor_json = false;
E
Eric Blake 已提交
5258
    virCommandPtr cmd = NULL;
5259 5260
    char *ret = NULL;
    int i;
5261
    virQEMUDriverConfigPtr cfg;
5262
    virCapsPtr caps = NULL;
5263

E
Eric Blake 已提交
5264 5265
    virCheckFlags(0, NULL);

5266
    cfg = virQEMUDriverGetConfig(driver);
5267

5268
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5269 5270
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5271 5272 5273
        goto cleanup;
    }

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

5277
    def = virDomainDefParseString(xmlData, caps, driver->xmlopt,
M
Matthias Bolte 已提交
5278
                                  QEMU_EXPECTED_VIRT_TYPES, 0);
5279 5280 5281
    if (!def)
        goto cleanup;

5282
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
5283 5284
        goto cleanup;

5285 5286
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
5287 5288 5289 5290 5291
     * directly. We convert those configs into generic 'ethernet'
     * config and assume the user has suitable 'ifup-qemu' scripts
     */
    for (i = 0 ; i < def->nnets ; i++) {
        virDomainNetDefPtr net = def->nets[i];
5292
        int bootIndex = net->info.bootIndex;
5293 5294
        char *model = net->model;

5295 5296 5297 5298
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

5299
            VIR_FREE(net->data.network.name);
5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311
            VIR_FREE(net->data.network.portgroup);
            if ((actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
                (brname = virDomainNetGetActualBridgeName(net))) {

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

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

5312
                memset(net, 0, sizeof(*net));
5313 5314

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5315
                net->script = NULL;
5316 5317 5318 5319 5320 5321 5322
                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);
5323
                memset(net, 0, sizeof(*net));
5324 5325

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5326
                net->script = NULL;
5327 5328 5329 5330 5331
                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);
5332

5333
            memset(net, 0, sizeof(*net));
5334 5335

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5336
            net->script = NULL;
5337 5338 5339
            net->data.ethernet.dev = NULL;
            net->data.ethernet.ipaddr = NULL;
        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
5340
            char *script = net->script;
5341 5342 5343
            char *brname = net->data.bridge.brname;
            char *ipaddr = net->data.bridge.ipaddr;

5344
            memset(net, 0, sizeof(*net));
5345 5346

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5347
            net->script = script;
5348 5349 5350
            net->data.ethernet.dev = brname;
            net->data.ethernet.ipaddr = ipaddr;
        }
5351

5352
        VIR_FREE(net->virtPortProfile);
5353
        net->info.bootIndex = bootIndex;
5354
        net->model = model;
5355 5356
    }

5357
    monitor_json = virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON);
T
tangchen 已提交
5358

5359
    if (qemuProcessPrepareMonitorChr(cfg, &monConfig, def->name) < 0)
5360
        goto cleanup;
5361

5362
    if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
5363 5364
        goto cleanup;

5365
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
5366
                                     &monConfig, monitor_json, qemuCaps,
5367
                                     NULL, -1, NULL, VIR_NETDEV_VPORT_PROFILE_OP_NO_OP)))
5368 5369
        goto cleanup;

E
Eric Blake 已提交
5370
    ret = virCommandToString(cmd);
5371 5372 5373

cleanup:

5374
    virObjectUnref(qemuCaps);
E
Eric Blake 已提交
5375
    virCommandFree(cmd);
5376
    virDomainDefFree(def);
5377
    virObjectUnref(caps);
5378
    virObjectUnref(cfg);
5379 5380 5381 5382
    return ret;
}


5383 5384
static int qemuListDefinedDomains(virConnectPtr conn,
                                  char **const names, int nnames) {
5385
    virQEMUDriverPtr driver = conn->privateData;
5386
    int n;
5387

5388
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames);
5389
    return n;
D
Daniel P. Berrange 已提交
5390 5391
}

5392
static int qemuNumDefinedDomains(virConnectPtr conn) {
5393
    virQEMUDriverPtr driver = conn->privateData;
5394
    int n;
5395

5396
    n = virDomainObjListNumOfDomains(driver->domains, 0);
5397

5398
    return n;
D
Daniel P. Berrange 已提交
5399 5400 5401
}


5402 5403
static int
qemuDomainObjStart(virConnectPtr conn,
5404
                   virQEMUDriverPtr driver,
5405
                   virDomainObjPtr vm,
5406
                   unsigned int flags)
J
Jiri Denemark 已提交
5407 5408 5409
{
    int ret = -1;
    char *managed_save;
5410 5411 5412 5413
    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;
5414 5415 5416
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;

    start_flags |= start_paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
5417
    start_flags |= autodestroy ? VIR_QEMU_PROCESS_START_AUTODESTROY : 0;
J
Jiri Denemark 已提交
5418 5419 5420

    /*
     * If there is a managed saved state restore it instead of starting
5421
     * from scratch. The old state is removed once the restoring succeeded.
J
Jiri Denemark 已提交
5422 5423
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
5424 5425 5426 5427

    if (!managed_save)
        goto cleanup;

E
Eric Blake 已提交
5428
    if (virFileExists(managed_save)) {
5429 5430 5431 5432 5433 5434 5435
        if (force_boot) {
            if (unlink(managed_save) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove managed save file %s"),
                                     managed_save);
                goto cleanup;
            }
5436
            vm->hasManagedSave = false;
5437 5438
        } else {
            ret = qemuDomainObjRestore(conn, driver, vm, managed_save,
5439
                                       start_paused, bypass_cache);
J
Jiri Denemark 已提交
5440

5441 5442 5443 5444 5445 5446 5447
            if (ret == 0) {
                if (unlink(managed_save) < 0)
                    VIR_WARN("Failed to remove the managed state %s", managed_save);
                else
                    vm->hasManagedSave = false;
            }

E
Eric Blake 已提交
5448 5449 5450 5451
            if (ret > 0)
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
            else
                goto cleanup;
5452
        }
J
Jiri Denemark 已提交
5453 5454
    }

5455 5456
    ret = qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_CREATE, start_flags);
5457
    virDomainAuditStart(vm, "booted", ret >= 0);
5458
    if (ret >= 0) {
J
Jiri Denemark 已提交
5459 5460 5461 5462
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
5463
        if (event) {
J
Jiri Denemark 已提交
5464
            qemuDomainEventQueue(driver, event);
5465 5466 5467 5468 5469 5470 5471 5472
            if (start_paused) {
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
                if (event)
                    qemuDomainEventQueue(driver, event);
            }
        }
J
Jiri Denemark 已提交
5473 5474 5475 5476 5477 5478 5479
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

5480
static int
5481
qemuDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
5482
{
5483
    virQEMUDriverPtr driver = dom->conn->privateData;
5484 5485
    virDomainObjPtr vm;
    int ret = -1;
5486

5487
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
5488
                  VIR_DOMAIN_START_AUTODESTROY |
5489 5490
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
5491

5492
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
5493

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

5502
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
5503 5504 5505
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
5506 5507
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is already running"));
5508 5509 5510
        goto endjob;
    }

5511
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
5512 5513 5514
        goto endjob;

    ret = 0;
5515

5516
endjob:
5517
    if (qemuDomainObjEndJob(driver, vm) == 0)
5518
        vm = NULL;
5519

5520
cleanup:
5521
    if (vm)
5522
        virObjectUnlock(vm);
5523
    return ret;
D
Daniel P. Berrange 已提交
5524 5525
}

5526
static int
5527
qemuDomainStart(virDomainPtr dom)
5528
{
5529
    return qemuDomainStartWithFlags(dom, 0);
5530 5531
}

5532
static virDomainPtr qemuDomainDefine(virConnectPtr conn, const char *xml) {
5533
    virQEMUDriverPtr driver = conn->privateData;
5534
    virDomainDefPtr def = NULL;
5535
    virDomainDefPtr oldDef = NULL;
5536
    virDomainObjPtr vm = NULL;
5537
    virDomainPtr dom = NULL;
5538
    virDomainEventPtr event = NULL;
5539
    virQEMUCapsPtr qemuCaps = NULL;
5540
    virQEMUDriverConfigPtr cfg;
5541
    virCapsPtr caps = NULL;
5542

5543
    cfg = virQEMUDriverGetConfig(driver);
5544 5545 5546 5547

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

5548
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
5549
                                        QEMU_EXPECTED_VIRT_TYPES,
5550
                                        VIR_DOMAIN_XML_INACTIVE)))
5551
        goto cleanup;
5552

5553
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
5554 5555
        goto cleanup;

5556
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
5557 5558
        goto cleanup;

5559
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
5560 5561
        goto cleanup;

5562
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
5563 5564
        goto cleanup;

5565
    if (!(vm = virDomainObjListAdd(driver->domains, def,
5566
                                   driver->xmlopt,
5567
                                   0, &oldDef)))
5568 5569
        goto cleanup;

5570
    def = NULL;
E
Eric Blake 已提交
5571 5572 5573
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
5574
        virDomainObjAssignDef(vm, NULL, false, NULL);
E
Eric Blake 已提交
5575 5576
        goto cleanup;
    }
5577
    vm->persistent = 1;
5578

5579
    if (virDomainSaveConfig(cfg->configDir,
5580
                            vm->newDef ? vm->newDef : vm->def) < 0) {
5581
        if (oldDef) {
M
Michal Privoznik 已提交
5582 5583 5584 5585
            /* 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))
5586
                vm->newDef = oldDef;
M
Michal Privoznik 已提交
5587
            else
5588 5589
                vm->def = oldDef;
            oldDef = NULL;
M
Michal Privoznik 已提交
5590 5591 5592 5593 5594 5595
        } else {
            /* Brand new domain. Remove it */
            VIR_INFO("Deleting domain '%s'", vm->def->name);
            qemuDomainRemoveInactive(driver, vm);
            vm = NULL;
        }
5596
        goto cleanup;
5597 5598
    }

5599 5600
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
5601
                                     !oldDef ?
5602 5603
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
5604

5605
    VIR_INFO("Creating domain '%s'", vm->def->name);
5606
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
5607
    if (dom) dom->id = vm->def->id;
5608 5609

cleanup:
5610
    virDomainDefFree(oldDef);
5611
    virDomainDefFree(def);
5612
    if (vm)
5613
        virObjectUnlock(vm);
5614 5615
    if (event)
        qemuDomainEventQueue(driver, event);
5616
    virObjectUnref(qemuCaps);
5617
    virObjectUnref(caps);
5618
    virObjectUnref(cfg);
5619
    return dom;
D
Daniel P. Berrange 已提交
5620 5621
}

5622 5623
static int
qemuDomainUndefineFlags(virDomainPtr dom,
5624
                        unsigned int flags)
5625
{
5626
    virQEMUDriverPtr driver = dom->conn->privateData;
5627
    virDomainObjPtr vm;
5628
    virDomainEventPtr event = NULL;
5629
    char *name = NULL;
5630
    int ret = -1;
5631
    int nsnapshots;
5632
    virQEMUDriverConfigPtr cfg = NULL;
D
Daniel P. Berrange 已提交
5633

5634 5635
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
5636

5637
    cfg = virQEMUDriverGetConfig(driver);
5638
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
5639

D
Daniel P. Berrange 已提交
5640
    if (!vm) {
5641 5642
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5643 5644
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
5645
        goto cleanup;
D
Daniel P. Berrange 已提交
5646 5647
    }

5648
    if (!vm->persistent) {
5649 5650
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
5651 5652 5653
        goto cleanup;
    }

5654
    if (!virDomainObjIsActive(vm) &&
5655
        (nsnapshots = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0))) {
5656
        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
5657 5658 5659 5660
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("cannot delete inactive domain with %d "
                             "snapshots"),
                           nsnapshots);
5661 5662
            goto cleanup;
        }
5663
        if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0)
5664
            goto cleanup;
5665 5666
    }

5667 5668 5669 5670 5671 5672 5673
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
5674 5675 5676
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed "
                                 "save image"));
5677 5678 5679
                goto cleanup;
            }
        } else {
5680 5681 5682
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
5683 5684 5685 5686
            goto cleanup;
        }
    }

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

5690 5691 5692
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
5693

5694
    VIR_INFO("Undefining domain '%s'", vm->def->name);
5695 5696 5697 5698 5699 5700 5701 5702

    /* 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 {
5703
        qemuDomainRemoveInactive(driver, vm);
5704 5705 5706
        vm = NULL;
    }

5707
    ret = 0;
D
Daniel P. Berrange 已提交
5708

5709
cleanup:
5710
    VIR_FREE(name);
5711
    if (vm)
5712
        virObjectUnlock(vm);
5713 5714
    if (event)
        qemuDomainEventQueue(driver, event);
5715
    virObjectUnref(cfg);
5716
    return ret;
D
Daniel P. Berrange 已提交
5717 5718
}

5719
static int
5720
qemuDomainUndefine(virDomainPtr dom)
5721 5722 5723 5724
{
    return qemuDomainUndefineFlags(dom, 0);
}

5725
static int
5726
qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
5727
                               virQEMUDriverPtr driver,
5728
                               virDomainObjPtr vm,
5729
                               virDomainDeviceDefPtr dev)
5730 5731
{
    virDomainDiskDefPtr disk = dev->data.disk;
5732 5733 5734
    virDomainDiskDefPtr orig_disk = NULL;
    virDomainDeviceDefPtr dev_copy = NULL;
    virDomainDiskDefPtr tmp = NULL;
5735
    virCgroupPtr cgroup = NULL;
5736
    virCapsPtr caps = NULL;
5737
    int ret = -1;
5738

5739
    if (disk->driverName != NULL && !STREQ(disk->driverName, "qemu")) {
5740 5741 5742
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unsupported driver name '%s' for disk '%s'"),
                       disk->driverName, disk->src);
5743 5744 5745
        goto end;
    }

5746 5747 5748 5749 5750 5751
    if (qemuAddSharedDisk(driver, disk, vm->def->name) < 0)
        goto end;

    if (qemuSetUnprivSGIO(disk) < 0)
        goto end;

5752 5753 5754
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto end;

5755 5756
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
5757 5758 5759
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to find cgroup for %s"),
                           vm->def->name);
5760 5761
            goto end;
        }
5762
        if (qemuSetupDiskCgroup(vm, cgroup, disk) < 0)
5763 5764
            goto end;
    }
5765

5766 5767 5768
    switch (disk->device)  {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783
        if (!(orig_disk = virDomainDiskFindByBusAndDst(vm->def,
                                                       disk->bus, disk->dst))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("No device with bus '%s' and target '%s'"),
                           virDomainDiskBusTypeToString(disk->bus),
                           disk->dst);
            goto end;
        }

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

        tmp = dev->data.disk;
        dev->data.disk = orig_disk;

5784 5785
        if (!(dev_copy = virDomainDeviceDefCopy(dev, vm->def,
                                                caps, driver->xmlopt))) {
5786 5787 5788 5789 5790 5791
            dev->data.disk = tmp;
            goto end;
        }
        dev->data.disk = tmp;

        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, orig_disk, false);
5792 5793 5794
        /* 'disk' must not be accessed now - it has been free'd.
         * 'orig_disk' now points to the new disk, while 'dev_copy'
         * now points to the old disk */
5795 5796 5797 5798

        /* Need to remove the shared disk entry for the original disk src
         * if the operation is either ejecting or updating.
         */
5799
        if (ret == 0)
5800 5801
            ignore_value(qemuRemoveSharedDisk(driver, dev_copy->data.disk,
                                              vm->def->name));
5802 5803
        break;
    case VIR_DOMAIN_DISK_DEVICE_DISK:
5804
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5805 5806
        if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
5807 5808
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("disk device='lun' is not supported for usb bus"));
5809 5810
                break;
            }
5811
            ret = qemuDomainAttachUsbMassstorageDevice(conn, driver, vm,
5812
                                                       disk);
5813
        } else if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
5814
            ret = qemuDomainAttachVirtioDiskDevice(conn, driver, vm, disk);
5815
        } else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
5816
            ret = qemuDomainAttachSCSIDisk(conn, driver, vm, disk);
5817
        } else {
5818 5819 5820
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(disk->bus));
5821
        }
5822 5823
        break;
    default:
5824 5825 5826
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk device type '%s' cannot be hotplugged"),
                       virDomainDiskDeviceTypeToString(disk->device));
5827 5828 5829 5830
        break;
    }

    if (ret != 0 && cgroup) {
5831
        if (qemuTeardownDiskCgroup(vm, cgroup, disk) < 0)
5832 5833 5834
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(disk->src));
    }
5835

5836
end:
5837 5838
    if (ret != 0)
        ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));
5839 5840
    if (cgroup)
        virCgroupFree(&cgroup);
5841 5842
    virObjectUnref(caps);
    virDomainDeviceDefFree(dev_copy);
5843 5844 5845 5846
    return ret;
}

static int
5847
qemuDomainAttachDeviceControllerLive(virQEMUDriverPtr driver,
5848
                                     virDomainObjPtr vm,
5849
                                     virDomainDeviceDefPtr dev)
5850 5851 5852 5853 5854 5855
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5856
        ret = qemuDomainAttachPciControllerDevice(driver, vm, cont);
5857 5858
        break;
    default:
5859 5860 5861
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk controller bus '%s' cannot be hotplugged."),
                       virDomainControllerTypeToString(cont->type));
5862 5863 5864 5865 5866 5867 5868 5869
        break;
    }
    return ret;
}

static int
qemuDomainAttachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5870
                           virDomainPtr dom)
5871
{
5872
    virQEMUDriverPtr driver = dom->conn->privateData;
5873 5874 5875 5876
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5877
        qemuDomainObjCheckDiskTaint(driver, vm, dev->data.disk, -1);
5878
        ret = qemuDomainAttachDeviceDiskLive(dom->conn, driver, vm, dev);
5879 5880 5881 5882 5883
        if (!ret)
            dev->data.disk = NULL;
        break;

    case VIR_DOMAIN_DEVICE_CONTROLLER:
5884
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
5885 5886 5887 5888
        if (!ret)
            dev->data.controller = NULL;
        break;

5889 5890 5891 5892 5893 5894 5895
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

5896
    case VIR_DOMAIN_DEVICE_NET:
5897
        qemuDomainObjCheckNetTaint(driver, vm, dev->data.net, -1);
5898
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
5899
                                        dev->data.net);
5900 5901 5902 5903 5904 5905
        if (!ret)
            dev->data.net = NULL;
        break;

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = qemuDomainAttachHostDevice(driver, vm,
5906
                                         dev->data.hostdev);
5907 5908 5909 5910
        if (!ret)
            dev->data.hostdev = NULL;
        break;

5911 5912 5913 5914 5915 5916 5917
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

5918
    default:
5919 5920 5921
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
5922 5923 5924 5925 5926 5927 5928
        break;
    }

    return ret;
}

static int
5929
qemuDomainDetachDeviceDiskLive(virQEMUDriverPtr driver,
5930
                               virDomainObjPtr vm,
5931
                               virDomainDeviceDefPtr dev)
5932 5933 5934 5935 5936 5937
{
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_DISK:
5938
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5939
        if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
5940
            ret = qemuDomainDetachVirtioDiskDevice(driver, vm, dev);
O
Osier Yang 已提交
5941 5942
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                 disk->bus == VIR_DOMAIN_DISK_BUS_USB)
5943
            ret = qemuDomainDetachDiskDevice(driver, vm, dev);
5944
        else
5945 5946
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("This type of disk cannot be hot unplugged"));
5947 5948
        break;
    default:
5949 5950
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk device type '%s' cannot be detached"),
5951
                       virDomainDiskDeviceTypeToString(disk->device));
5952 5953
        break;
    }
5954

5955 5956
    if (ret == 0)
        ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));
5957

5958 5959 5960 5961
    return ret;
}

static int
5962
qemuDomainDetachDeviceControllerLive(virQEMUDriverPtr driver,
5963
                                     virDomainObjPtr vm,
5964
                                     virDomainDeviceDefPtr dev)
5965 5966 5967 5968 5969 5970
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5971
        ret = qemuDomainDetachPciControllerDevice(driver, vm, dev);
5972 5973
        break;
    default :
5974 5975 5976
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk controller bus '%s' cannot be hotunplugged."),
                       virDomainControllerTypeToString(cont->type));
5977 5978 5979 5980 5981 5982 5983
    }
    return ret;
}

static int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5984
                           virDomainPtr dom)
5985
{
5986
    virQEMUDriverPtr driver = dom->conn->privateData;
5987 5988 5989 5990
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5991
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
5992 5993
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5994
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
5995
        break;
5996 5997 5998
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
5999
    case VIR_DOMAIN_DEVICE_NET:
6000
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
6001 6002
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
6003
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
6004 6005
        break;
    default:
6006 6007
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("This type of device cannot be hot unplugged"));
6008 6009 6010 6011 6012 6013
        break;
    }

    return ret;
}

6014 6015 6016
static int
qemuDomainChangeDiskMediaLive(virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev,
6017
                              virQEMUDriverPtr driver,
6018 6019 6020
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
6021 6022
    virDomainDiskDefPtr orig_disk = NULL;
    virDomainDiskDefPtr tmp = NULL;
6023
    virCgroupPtr cgroup = NULL;
6024 6025
    virDomainDeviceDefPtr dev_copy = NULL;
    virCapsPtr caps = NULL;
6026
    int ret = -1;
6027

6028 6029 6030
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto end;

6031 6032
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup,
6033
                               vm->def->name, &cgroup, 0) != 0) {
6034 6035 6036
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to find cgroup for %s"),
                           vm->def->name);
6037 6038
            goto end;
        }
6039
        if (qemuSetupDiskCgroup(vm, cgroup, disk) < 0)
6040 6041 6042 6043 6044 6045
            goto end;
    }

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060
        if (!(orig_disk = virDomainDiskFindByBusAndDst(vm->def,
                                                       disk->bus, disk->dst))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("No device with bus '%s' and target '%s'"),
                           virDomainDiskBusTypeToString(disk->bus),
                           disk->dst);
            goto end;
        }

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

        tmp = dev->data.disk;
        dev->data.disk = orig_disk;

6061 6062
        if (!(dev_copy = virDomainDeviceDefCopy(dev, vm->def,
                                                caps, driver->xmlopt))) {
6063 6064 6065 6066 6067
            dev->data.disk = tmp;
            goto end;
        }
        dev->data.disk = tmp;

6068 6069 6070 6071
        /* Add the new disk src into shared disk hash table */
        if (qemuAddSharedDisk(driver, dev->data.disk, vm->def->name) < 0)
            goto end;

6072
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, orig_disk, force);
6073 6074 6075 6076 6077 6078 6079
        /* 'disk' must not be accessed now - it has been freed.
         * 'orig_disk' now points to the new disk, while 'dev_copy'
         * now points to the old disk */

        /* Need to remove the shared disk entry for the original
         * disk src if the operation is either ejecting or updating.
         */
6080
        if (ret == 0) {
6081
            dev->data.disk = NULL;
6082 6083
            ignore_value(qemuRemoveSharedDisk(driver, dev_copy->data.disk,
                                              vm->def->name));
6084
        }
6085 6086
        break;
    default:
6087 6088 6089
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk bus '%s' cannot be updated."),
                       virDomainDiskBusTypeToString(disk->bus));
6090 6091 6092 6093
        break;
    }

    if (ret != 0 && cgroup) {
6094
        if (qemuTeardownDiskCgroup(vm, cgroup, disk) < 0)
6095 6096 6097 6098 6099 6100
             VIR_WARN("Failed to teardown cgroup for disk path %s",
                      NULLSTR(disk->src));
    }
end:
    if (cgroup)
        virCgroupFree(&cgroup);
6101 6102
    virObjectUnref(caps);
    virDomainDeviceDefFree(dev_copy);
6103 6104 6105 6106 6107 6108 6109 6110 6111
    return ret;
}

static int
qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
                           virDomainPtr dom,
                           bool force)
{
6112
    virQEMUDriverPtr driver = dom->conn->privateData;
6113 6114 6115 6116
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6117
        ret = qemuDomainChangeDiskMediaLive(vm, dev, driver, force);
6118 6119 6120 6121
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;
6122
    case VIR_DOMAIN_DEVICE_NET:
6123
        ret = qemuDomainChangeNet(driver, vm, dom, dev);
6124
        break;
6125
    default:
6126 6127 6128
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be updated"),
                       virDomainDeviceTypeToString(dev->type));
6129 6130 6131 6132 6133 6134
        break;
    }

    return ret;
}

6135
static int
6136
qemuDomainAttachDeviceConfig(virQEMUCapsPtr qemuCaps,
6137
                             virDomainDefPtr vmdef,
6138 6139
                             virDomainDeviceDefPtr dev)
{
6140
    virDomainDiskDefPtr disk;
6141
    virDomainNetDefPtr net;
6142
    virDomainHostdevDefPtr hostdev;
6143
    virDomainLeaseDefPtr lease;
6144
    virDomainControllerDefPtr controller;
6145

6146
    switch (dev->type) {
6147 6148
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6149
        if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
6150 6151
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("target %s already exists"), disk->dst);
6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162
            return -1;
        }
        if (virDomainDiskInsert(vmdef, disk)) {
            virReportOOMError();
            return -1;
        }
        /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
        dev->data.disk = NULL;
        if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO)
            if (virDomainDefAddImplicitControllers(vmdef) < 0)
                return -1;
6163
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6164 6165 6166
            return -1;
        break;

6167 6168 6169 6170 6171 6172 6173
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
        if (virDomainNetInsert(vmdef, net)) {
            virReportOOMError();
            return -1;
        }
        dev->data.net = NULL;
6174
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6175 6176
            return -1;
        break;
6177

6178 6179 6180
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        hostdev = dev->data.hostdev;
        if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
6181
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6182
                           _("device is already in the domain configuration"));
6183 6184 6185 6186 6187 6188 6189
            return -1;
        }
        if (virDomainHostdevInsert(vmdef, hostdev)) {
            virReportOOMError();
            return -1;
        }
        dev->data.hostdev = NULL;
6190
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6191 6192 6193
            return -1;
        break;

6194 6195 6196
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
        if (virDomainLeaseIndex(vmdef, lease) >= 0) {
6197
            virReportError(VIR_ERR_OPERATION_INVALID,
6198 6199
                           _("Lease %s in lockspace %s already exists"),
                           lease->key, NULLSTR(lease->lockspace));
6200 6201 6202 6203 6204 6205 6206 6207 6208
            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;

6209 6210 6211 6212
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        controller = dev->data.controller;
        if (virDomainControllerFind(vmdef, controller->type,
                                    controller->idx) > 0) {
6213
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6214 6215 6216 6217 6218 6219 6220 6221
                           _("Target already exists"));
            return -1;
        }

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

6222
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6223 6224 6225
            return -1;
        break;

6226
    default:
6227 6228
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
6229 6230 6231 6232 6233 6234 6235
         return -1;
    }
    return 0;
}


static int
6236
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
6237 6238
                             virDomainDeviceDefPtr dev)
{
6239
    virDomainDiskDefPtr disk, det_disk;
6240
    virDomainNetDefPtr net;
6241
    virDomainHostdevDefPtr hostdev, det_hostdev;
6242
    virDomainLeaseDefPtr lease, det_lease;
6243 6244
    virDomainControllerDefPtr cont, det_cont;
    int idx;
6245
    char mac[VIR_MAC_STRING_BUFLEN];
6246

6247
    switch (dev->type) {
6248 6249
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6250
        if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
6251 6252
            virReportError(VIR_ERR_INVALID_ARG,
                           _("no target device %s"), disk->dst);
6253 6254
            return -1;
        }
6255
        virDomainDiskDefFree(det_disk);
6256
        break;
6257

6258 6259
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6260 6261 6262 6263 6264 6265 6266 6267 6268
        idx = virDomainNetFindIdx(vmdef, net);
        if (idx == -2) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("multiple devices matching mac address %s found"),
                           virMacAddrFormat(&net->mac, mac));
            return -1;
        } else if (idx < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("no matching network device was found"));
6269 6270
            return -1;
        }
6271 6272
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
6273
        break;
6274

6275 6276 6277
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        hostdev = dev->data.hostdev;
        if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
6278 6279
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device not present in domain configuration"));
6280 6281 6282 6283 6284 6285 6286
            return -1;
        }
        virDomainHostdevRemove(vmdef, idx);
        virDomainHostdevDefFree(det_hostdev);
        break;
    }

6287 6288
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
6289
        if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) {
6290 6291 6292
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Lease %s in lockspace %s does not exist"),
                           lease->key, NULLSTR(lease->lockspace));
6293 6294
            return -1;
        }
6295
        virDomainLeaseDefFree(det_lease);
6296 6297
        break;

6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310
    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;

6311
    default:
6312 6313
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent detach of device is not supported"));
6314 6315 6316 6317 6318 6319
        return -1;
    }
    return 0;
}

static int
6320
qemuDomainUpdateDeviceConfig(virQEMUCapsPtr qemuCaps,
6321
                             virDomainDefPtr vmdef,
6322 6323
                             virDomainDeviceDefPtr dev)
{
6324
    virDomainDiskDefPtr orig, disk;
6325
    virDomainNetDefPtr net;
6326
    int pos;
6327 6328
    char mac[VIR_MAC_STRING_BUFLEN];

6329

6330
    switch (dev->type) {
6331 6332
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6333
        pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
6334
        if (pos < 0) {
6335 6336
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s doesn't exist."), disk->dst);
6337 6338 6339 6340 6341
            return -1;
        }
        orig = vmdef->disks[pos];
        if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
            !(orig->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)) {
6342 6343
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("this disk doesn't support update"));
6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358
            return -1;
        }
        /*
         * Update 'orig'
         * We allow updating src/type//driverType/cachemode/
         */
        VIR_FREE(orig->src);
        orig->src = disk->src;
        orig->type = disk->type;
        orig->cachemode = disk->cachemode;
        if (disk->driverName) {
            VIR_FREE(orig->driverName);
            orig->driverName = disk->driverName;
            disk->driverName = NULL;
        }
6359 6360
        if (disk->format)
            orig->format = disk->format;
6361 6362
        disk->src = NULL;
        break;
6363 6364 6365

    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377
        pos = virDomainNetFindIdx(vmdef, net);
        if (pos == -2) {
            virMacAddrFormat(&net->mac, mac);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("couldn't find matching device "
                             "with mac address %s"), mac);
            return -1;
        } else if (pos < 0) {
            virMacAddrFormat(&net->mac, mac);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("couldn't find matching device "
                             "with mac address %s"), mac);
6378 6379 6380
            return -1;
        }

6381
        virDomainNetDefFree(vmdef->nets[pos]);
6382 6383 6384 6385

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

6386
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6387 6388 6389
            return -1;
        break;

6390
    default:
6391 6392
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
6393 6394 6395 6396 6397
        return -1;
    }
    return 0;
}

6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408
/* Actions for qemuDomainModifyDeviceFlags */
enum {
    QEMU_DEVICE_ATTACH,
    QEMU_DEVICE_DETACH,
    QEMU_DEVICE_UPDATE,
};


static int
qemuDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags, int action)
6409
{
6410
    virQEMUDriverPtr driver = dom->conn->privateData;
6411
    virDomainObjPtr vm = NULL;
6412
    virDomainDefPtr vmdef = NULL;
6413
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
6414
    bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
6415
    int ret = -1;
6416
    unsigned int affect;
6417
    virQEMUCapsPtr qemuCaps = NULL;
6418
    qemuDomainObjPrivatePtr priv;
6419
    virQEMUDriverConfigPtr cfg = NULL;
6420
    virCapsPtr caps = NULL;
6421

6422 6423
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
6424 6425 6426
                  (action == QEMU_DEVICE_UPDATE ?
                   VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);

6427 6428
    cfg = virQEMUDriverGetConfig(driver);

6429 6430
    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

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

6434
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
6435 6436 6437
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6438 6439
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
6440 6441
        goto cleanup;
    }
6442
    priv = vm->privateData;
6443

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

6447
    if (virDomainObjIsActive(vm)) {
6448
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6449
            flags |= VIR_DOMAIN_AFFECT_LIVE;
6450
    } else {
6451
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6452
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
6453
        /* check consistency between flags and the vm state */
6454
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6455
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6456 6457
                           _("cannot do live update a device on "
                             "inactive domain"));
6458 6459
            goto endjob;
        }
6460
    }
6461

6462
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
6463 6464
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
6465 6466
         goto endjob;
    }
6467

6468 6469
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                             caps, driver->xmlopt,
6470 6471 6472 6473 6474 6475 6476 6477 6478 6479
                                             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.
         */
6480
        dev_copy = virDomainDeviceDefCopy(dev, vm->def, caps, driver->xmlopt);
6481
        if (!dev_copy)
6482
            goto endjob;
6483
    }
6484

6485 6486 6487
    if (priv->qemuCaps)
        qemuCaps = virObjectRef(priv->qemuCaps);
    else if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, vm->def->emulator)))
6488 6489
        goto cleanup;

6490
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6491
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
6492 6493
            goto endjob;

6494
        /* Make a copy for updated domain. */
6495
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
6496 6497 6498 6499
        if (!vmdef)
            goto endjob;
        switch (action) {
        case QEMU_DEVICE_ATTACH:
6500
            ret = qemuDomainAttachDeviceConfig(qemuCaps, vmdef, dev);
6501 6502 6503 6504 6505
            break;
        case QEMU_DEVICE_DETACH:
            ret = qemuDomainDetachDeviceConfig(vmdef, dev);
            break;
        case QEMU_DEVICE_UPDATE:
6506
            ret = qemuDomainUpdateDeviceConfig(qemuCaps, vmdef, dev);
6507 6508
            break;
        default:
6509 6510
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown domain modify action %d"), action);
6511 6512
            break;
        }
6513

6514 6515 6516 6517 6518
        if (ret == -1)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6519 6520 6521
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto endjob;

6522 6523
        switch (action) {
        case QEMU_DEVICE_ATTACH:
6524
            ret = qemuDomainAttachDeviceLive(vm, dev_copy, dom);
6525 6526
            break;
        case QEMU_DEVICE_DETACH:
6527
            ret = qemuDomainDetachDeviceLive(vm, dev_copy, dom);
6528 6529
            break;
        case QEMU_DEVICE_UPDATE:
6530
            ret = qemuDomainUpdateDeviceLive(vm, dev_copy, dom, force);
6531 6532
            break;
        default:
6533 6534
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown domain modify action %d"), action);
6535
            ret = -1;
6536 6537
            break;
        }
6538 6539 6540

        if (ret == -1)
            goto endjob;
6541 6542
        /*
         * update domain status forcibly because the domain status may be
6543 6544
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
6545
         */
6546
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
6547
            ret = -1;
6548 6549
            goto endjob;
        }
6550
    }
6551

6552
    /* Finally, if no error until here, we can save config. */
6553
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6554
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
6555
        if (!ret) {
6556
            virDomainObjAssignDef(vm, vmdef, false, NULL);
6557 6558 6559
            vmdef = NULL;
        }
    }
6560 6561

endjob:
6562
    if (qemuDomainObjEndJob(driver, vm) == 0)
6563 6564 6565
        vm = NULL;

cleanup:
6566
    virObjectUnref(qemuCaps);
6567
    virDomainDefFree(vmdef);
6568 6569
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
6570 6571
    virDomainDeviceDefFree(dev);
    if (vm)
6572
        virObjectUnlock(vm);
6573
    virObjectUnref(caps);
6574
    virObjectUnref(cfg);
6575 6576 6577
    return ret;
}

6578 6579 6580 6581 6582 6583
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_ATTACH);
}

6584 6585 6586
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
6587
                                       VIR_DOMAIN_AFFECT_LIVE);
6588
}
6589

6590

6591 6592 6593 6594
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
6595
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_UPDATE);
6596 6597
}

6598 6599 6600
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
6601
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_DETACH);
6602 6603
}

6604 6605 6606
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
6607
                                       VIR_DOMAIN_AFFECT_LIVE);
6608 6609
}

6610 6611
static int qemuDomainGetAutostart(virDomainPtr dom,
                                  int *autostart) {
6612 6613
    virDomainObjPtr vm;
    int ret = -1;
6614

6615
    if (!(vm = qemuDomObjFromDomain(dom)))
6616
        goto cleanup;
6617 6618

    *autostart = vm->autostart;
6619
    ret = 0;
6620

6621
cleanup:
6622
    if (vm)
6623
        virObjectUnlock(vm);
6624
    return ret;
6625 6626
}

6627 6628
static int qemuDomainSetAutostart(virDomainPtr dom,
                                  int autostart) {
6629
    virQEMUDriverPtr driver = dom->conn->privateData;
6630
    virDomainObjPtr vm;
6631 6632
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
6633
    virQEMUDriverConfigPtr cfg = NULL;
6634

6635
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
6636
    cfg = virQEMUDriverGetConfig(driver);
6637
    if (!vm) {
6638 6639
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6640 6641
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
6642
        goto cleanup;
6643 6644
    }

6645
    if (!vm->persistent) {
6646 6647
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
6648
        goto cleanup;
6649 6650
    }

6651 6652
    autostart = (autostart != 0);

6653
    if (vm->autostart != autostart) {
6654
        if ((configFile = virDomainConfigFile(cfg->configDir, vm->def->name)) == NULL)
6655
            goto cleanup;
6656
        if ((autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)) == NULL)
6657
            goto cleanup;
6658

6659
        if (autostart) {
6660
            if (virFileMakePath(cfg->autostartDir) < 0) {
6661
                virReportSystemError(errno,
6662
                                     _("cannot create autostart directory %s"),
6663
                                     cfg->autostartDir);
6664 6665
                goto cleanup;
            }
6666

6667
            if (symlink(configFile, autostartLink) < 0) {
6668
                virReportSystemError(errno,
6669 6670
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
6671 6672 6673 6674
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
6675
                virReportSystemError(errno,
6676 6677
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
6678 6679
                goto cleanup;
            }
6680 6681
        }

6682
        vm->autostart = autostart;
6683
    }
6684
    ret = 0;
6685

6686 6687 6688
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
6689
    if (vm)
6690
        virObjectUnlock(vm);
6691
    virObjectUnref(cfg);
6692
    return ret;
6693 6694
}

6695

6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728
/*
 * check whether the host supports CFS bandwidth
 *
 * Return 1 when CFS bandwidth is supported, 0 when CFS bandwidth is not
 * supported, -1 on error.
 */
static int qemuGetCpuBWStatus(virCgroupPtr cgroup)
{
    char *cfs_period_path = NULL;
    int ret = -1;

    if (!cgroup)
        return 0;

    if (virCgroupPathOfController(cgroup, VIR_CGROUP_CONTROLLER_CPU,
                                  "cpu.cfs_period_us", &cfs_period_path) < 0) {
        VIR_INFO("cannot get the path of cgroup CPU controller");
        ret = 0;
        goto cleanup;
    }

    if (access(cfs_period_path, F_OK) < 0) {
        ret = 0;
    } else {
        ret = 1;
    }

cleanup:
    VIR_FREE(cfs_period_path);
    return ret;
}


6729 6730 6731
static char *qemuGetSchedulerType(virDomainPtr dom,
                                  int *nparams)
{
6732
    virQEMUDriverPtr driver = dom->conn->privateData;
6733
    char *ret = NULL;
6734
    int rc;
6735

6736
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
6737 6738
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
6739
        goto cleanup;
6740 6741
    }

6742 6743 6744 6745 6746 6747 6748
    if (nparams) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        else if (rc == 0)
            *nparams = 1;
        else
6749
            *nparams = 5;
6750
    }
6751 6752 6753

    ret = strdup("posix");
    if (!ret)
6754
        virReportOOMError();
6755 6756

cleanup:
6757 6758 6759
    return ret;
}

6760 6761 6762 6763
/* deviceWeightStr in the form of /device/path,weight,/device/path,weight
 * for example, /dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0,800
 */
static int
6764 6765
qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
                               virBlkioDeviceWeightPtr *dw, size_t *size)
6766 6767 6768 6769 6770 6771 6772
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
    int i;
    virBlkioDeviceWeightPtr result = NULL;

6773 6774 6775 6776 6777 6778
    *dw = NULL;
    *size = 0;

    if (STREQ(deviceWeightStr, ""))
        return 0;

6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839
    temp = deviceWeightStr;
    while (temp) {
        temp = strchr(temp, ',');
        if (temp) {
            temp++;
            nsep++;
        }
    }

    /* A valid string must have even number of fields, hence an odd
     * number of commas.  */
    if (!(nsep & 1))
        goto error;

    ndevices = (nsep + 1) / 2;

    if (VIR_ALLOC_N(result, ndevices) < 0) {
        virReportOOMError();
        return -1;
    }

    i = 0;
    temp = deviceWeightStr;
    while (temp) {
        char *p = temp;

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

        result[i].path = strndup(temp, p - temp);
        if (!result[i].path) {
            virReportOOMError();
            goto cleanup;
        }

        /* weight */
        temp = p + 1;

        if (virStrToLong_ui(temp, &p, 10, &result[i].weight) < 0)
            goto error;

        i++;

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

    if (!i)
        VIR_FREE(result);

    *dw = result;
    *size = i;

    return 0;

error:
6840 6841
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unable to parse device weight '%s'"), deviceWeightStr);
6842 6843 6844 6845 6846 6847
cleanup:
    virBlkioDeviceWeightArrayClear(result, ndevices);
    VIR_FREE(result);
    return -1;
}

6848 6849
/* Modify dest_array to reflect all device weight changes described in
 * src_array.  */
6850
static int
6851 6852 6853 6854
qemuDomainMergeDeviceWeights(virBlkioDeviceWeightPtr *dest_array,
                             size_t *dest_size,
                             virBlkioDeviceWeightPtr src_array,
                             size_t src_size)
6855 6856
{
    int i, j;
6857
    virBlkioDeviceWeightPtr dest, src;
6858

6859
    for (i = 0; i < src_size; i++) {
6860 6861
        bool found = false;

6862 6863 6864 6865
        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
6866
                found = true;
6867
                dest->weight = src->weight;
6868 6869 6870 6871
                break;
            }
        }
        if (!found) {
6872
            if (!src->weight)
6873
                continue;
6874
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0) {
6875 6876 6877
                virReportOOMError();
                return -1;
            }
6878 6879 6880 6881
            dest = &(*dest_array)[*dest_size - 1];
            dest->path = src->path;
            dest->weight = src->weight;
            src->path = NULL;
6882 6883 6884 6885 6886 6887
        }
    }

    return 0;
}

6888 6889 6890 6891 6892
static int
qemuDomainSetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
6893
{
6894
    virQEMUDriverPtr driver = dom->conn->privateData;
6895 6896 6897
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6898
    virDomainDefPtr persistentDef = NULL;
6899
    int ret = -1;
6900
    virQEMUDriverConfigPtr cfg = NULL;
6901
    virCapsPtr caps = NULL;
6902

6903 6904
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6905 6906 6907 6908 6909 6910 6911
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_BLKIO_WEIGHT,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                       VIR_TYPED_PARAM_STRING,
                                       NULL) < 0)
        return -1;
6912

6913
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
6914
    if (vm == NULL) {
6915 6916
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
6917 6918
        goto cleanup;
    }
6919
    cfg = virQEMUDriverGetConfig(driver);
6920 6921
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;
6922

6923
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
6924 6925
                                        &persistentDef) < 0)
        goto cleanup;
6926

6927 6928
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
6929 6930
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
6931 6932 6933 6934
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
6935 6936 6937
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
6938 6939 6940 6941
            goto cleanup;
        }
    }

6942
    ret = 0;
6943 6944
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        for (i = 0; i < nparams; i++) {
6945
            int rc;
6946 6947 6948 6949
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
6950 6951
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
6952 6953 6954
                    ret = -1;
                    continue;
                }
6955

6956 6957 6958 6959 6960 6961
                rc = virCgroupSetBlkioWeight(group, params[i].value.ui);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set blkio weight tunable"));
                    ret = -1;
                }
6962
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
6963
                size_t ndevices;
6964
                virBlkioDeviceWeightPtr devices = NULL;
6965 6966
                int j;

6967 6968 6969
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
6970 6971 6972
                    ret = -1;
                    continue;
                }
6973
                for (j = 0; j < ndevices; j++) {
6974
                    rc = virCgroupSetBlkioDeviceWeight(group,
6975 6976
                                                       devices[j].path,
                                                       devices[j].weight);
6977 6978 6979 6980
                    if (rc < 0) {
                        virReportSystemError(-rc,
                                             _("Unable to set io device weight "
                                               "for path %s"),
6981
                                             devices[j].path);
6982 6983 6984
                        break;
                    }
                }
6985 6986
                if (j != ndevices ||
                    qemuDomainMergeDeviceWeights(&vm->def->blkio.devices,
6987 6988 6989 6990 6991
                                                 &vm->def->blkio.ndevices,
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
6992
            }
6993
        }
E
Eric Blake 已提交
6994 6995 6996 6997
    }
    if (ret < 0)
        goto cleanup;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
6998 6999 7000
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

7001 7002 7003 7004 7005
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
7006 7007
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
7008 7009 7010 7011 7012
                    ret = -1;
                    continue;
                }

                persistentDef->blkio.weight = params[i].value.ui;
7013 7014
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
                virBlkioDeviceWeightPtr devices = NULL;
7015
                size_t ndevices;
7016

7017 7018 7019
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
7020 7021 7022
                    ret = -1;
                    continue;
                }
7023 7024
                if (qemuDomainMergeDeviceWeights(&persistentDef->blkio.devices,
                                                 &persistentDef->blkio.ndevices,
7025 7026 7027 7028
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
7029 7030
            }
        }
A
Alex Jia 已提交
7031

7032
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
A
Alex Jia 已提交
7033
            ret = -1;
7034 7035 7036 7037 7038
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
7039
        virObjectUnlock(vm);
7040
    virObjectUnref(caps);
7041
    virObjectUnref(cfg);
7042 7043 7044
    return ret;
}

7045 7046 7047 7048 7049
static int
qemuDomainGetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
7050
{
7051
    virQEMUDriverPtr driver = dom->conn->privateData;
7052
    int i, j;
7053 7054
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7055
    virDomainDefPtr persistentDef = NULL;
7056 7057 7058
    unsigned int val;
    int ret = -1;
    int rc;
7059
    virCapsPtr caps = NULL;
7060

7061
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7062 7063
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7064

7065 7066 7067
    /* 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.  */
7068 7069
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7070
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7071 7072

    if (vm == NULL) {
7073 7074
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7075 7076 7077
        goto cleanup;
    }

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

7081 7082 7083 7084 7085 7086 7087
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

7088
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7089 7090
                                        &persistentDef) < 0)
        goto cleanup;
7091

7092 7093
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
7094 7095
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
7096 7097 7098 7099
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7100 7101
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7102 7103 7104 7105 7106
            goto cleanup;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7107
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118
            virTypedParameterPtr param = &params[i];
            val = 0;

            switch (i) {
            case 0: /* fill blkio weight here */
                rc = virCgroupGetBlkioWeight(group, &val);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get blkio weight"));
                    goto cleanup;
                }
7119 7120
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
7121 7122
                    goto cleanup;
                break;
7123 7124 7125 7126
            case 1: /* blkiotune.device_weight */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;
7127

7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144
                    for (j = 0; j < vm->def->blkio.ndevices; j++) {
                        if (!vm->def->blkio.devices[j].weight)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%u",
                                          vm->def->blkio.devices[j].path,
                                          vm->def->blkio.devices[j].weight);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
7145 7146 7147 7148
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
7149 7150
                    goto cleanup;
                break;
7151 7152 7153 7154

            default:
                break;
                /* should not hit here */
7155
            }
7156 7157
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7158
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7159 7160 7161 7162 7163 7164 7165 7166
            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) {
7167 7168 7169
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_WEIGHT);
7170 7171 7172 7173
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
7174

7175 7176 7177
            case 1: /* blkiotune.device_weight */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
7178 7179
                    bool comma = false;

7180
                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
7181 7182 7183
                        if (!persistentDef->blkio.devices[j].weight)
                            continue;
                        if (comma)
7184
                            virBufferAddChar(&buf, ',');
7185 7186
                        else
                            comma = true;
7187 7188 7189 7190 7191 7192 7193 7194 7195
                        virBufferAsprintf(&buf, "%s,%u",
                                          persistentDef->blkio.devices[j].path,
                                          persistentDef->blkio.devices[j].weight);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
7196 7197
                }
                if (!param->value.s) {
7198 7199 7200 7201 7202 7203 7204 7205 7206
                    param->value.s = strdup("");
                    if (!param->value.s) {
                        virReportOOMError();
                        goto cleanup;
                    }
                }
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) == NULL) {
7207 7208 7209
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
7210 7211 7212 7213
                    goto cleanup;
                }
                break;

7214 7215 7216 7217
            default:
                break;
                /* should not hit here */
            }
7218 7219 7220
        }
    }

7221 7222
    if (QEMU_NB_BLKIO_PARAM < *nparams)
        *nparams = QEMU_NB_BLKIO_PARAM;
7223 7224 7225 7226 7227 7228
    ret = 0;

cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
7229
        virObjectUnlock(vm);
7230
    virObjectUnref(caps);
7231 7232
    return ret;
}
7233

7234 7235 7236 7237 7238
static int
qemuDomainSetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              unsigned int flags)
7239
{
7240
    virQEMUDriverPtr driver = dom->conn->privateData;
7241
    virDomainDefPtr persistentDef = NULL;
7242 7243
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7244 7245 7246 7247 7248 7249
    unsigned long long swap_hard_limit;
    unsigned long long memory_hard_limit;
    unsigned long long memory_soft_limit;
    bool set_swap_hard_limit = false;
    bool set_memory_hard_limit = false;
    bool set_memory_soft_limit = false;
7250
    virQEMUDriverConfigPtr cfg = NULL;
7251
    int ret = -1;
7252
    int rc;
7253
    virCapsPtr caps = NULL;
7254

7255 7256
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7257

7258 7259 7260 7261 7262 7263 7264 7265 7266
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       NULL) < 0)
        return -1;
7267 7268


7269 7270
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
7271

7272 7273
    cfg = virQEMUDriverGetConfig(driver);

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

7277
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7278 7279
                                        &persistentDef) < 0)
        goto cleanup;
7280

7281
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7282
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7283 7284
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7285 7286 7287 7288
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7289 7290
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7291 7292 7293 7294
            goto cleanup;
        }
    }

7295
#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE)                                \
7296
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0)  \
7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307
        goto cleanup;                                                        \
                                                                             \
    if (rc == 1)                                                             \
        set_ ## VALUE = true;

    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, swap_hard_limit)
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_HARD_LIMIT, memory_hard_limit)
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SOFT_LIMIT, memory_soft_limit)

#undef VIR_GET_LIMIT_PARAMETER

7308 7309

    /* It will fail if hard limit greater than swap hard limit anyway */
7310 7311
    if (set_swap_hard_limit && set_memory_hard_limit &&
        memory_hard_limit > swap_hard_limit) {
7312
        virReportError(VIR_ERR_INVALID_ARG, "%s",
7313 7314
                       _("memory hard_limit tunable value must be lower than "
                         "swap_hard_limit"));
7315 7316 7317
        goto cleanup;
    }

7318
    if (set_swap_hard_limit) {
7319 7320 7321 7322 7323 7324 7325
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            if ((rc = virCgroupSetMemSwapHardLimit(group, swap_hard_limit)) < 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory swap_hard_limit tunable"));
                goto cleanup;
            }
            vm->def->mem.swap_hard_limit = swap_hard_limit;
7326
        }
7327

7328 7329
        if (flags & VIR_DOMAIN_AFFECT_CONFIG)
            persistentDef->mem.swap_hard_limit = swap_hard_limit;
7330 7331
    }

7332
    if (set_memory_hard_limit) {
7333 7334 7335 7336 7337 7338 7339
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            if ((rc = virCgroupSetMemoryHardLimit(group, memory_hard_limit)) < 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory hard_limit tunable"));
                goto cleanup;
            }
            vm->def->mem.hard_limit = memory_hard_limit;
7340
        }
7341

7342 7343 7344
        if (flags & VIR_DOMAIN_AFFECT_CONFIG)
            persistentDef->mem.hard_limit = memory_hard_limit;
    }
7345

7346
    if (set_memory_soft_limit) {
7347 7348 7349 7350 7351 7352 7353
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            if ((rc = virCgroupSetMemorySoftLimit(group, memory_soft_limit)) < 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory soft_limit tunable"));
                goto cleanup;
            }
            vm->def->mem.soft_limit = memory_soft_limit;
7354 7355
        }

7356 7357
        if (flags & VIR_DOMAIN_AFFECT_CONFIG)
            persistentDef->mem.soft_limit = memory_soft_limit;
7358 7359
    }

7360 7361 7362 7363 7364 7365
    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
        goto cleanup;

    ret = 0;

7366 7367
cleanup:
    virCgroupFree(&group);
7368
    virObjectUnlock(vm);
7369
    virObjectUnref(caps);
7370
    virObjectUnref(cfg);
7371 7372 7373
    return ret;
}

7374 7375 7376 7377 7378
static int
qemuDomainGetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int *nparams,
                              unsigned int flags)
7379
{
7380
    virQEMUDriverPtr driver = dom->conn->privateData;
7381 7382 7383
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7384
    virDomainDefPtr persistentDef = NULL;
7385 7386
    int ret = -1;
    int rc;
7387
    virCapsPtr caps = NULL;
7388

7389
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7390 7391
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7392

7393 7394 7395
    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7396
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7397 7398

    if (vm == NULL) {
7399 7400
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7401 7402 7403
        goto cleanup;
    }

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

7407
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7408 7409
                                        &persistentDef) < 0)
        goto cleanup;
7410

7411
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7412
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7413 7414
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7415 7416 7417 7418
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7419 7420
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7421 7422 7423 7424
            goto cleanup;
        }
    }

7425 7426 7427 7428 7429 7430 7431
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

7432
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7433
        for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
7434 7435 7436 7437
            virMemoryParameterPtr param = &params[i];

            switch (i) {
            case 0: /* fill memory hard limit here */
7438 7439 7440 7441
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.hard_limit) < 0)
7442 7443 7444 7445
                    goto cleanup;
                break;

            case 1: /* fill memory soft limit here */
7446 7447 7448 7449
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.soft_limit) < 0)
7450 7451 7452 7453
                    goto cleanup;
                break;

            case 2: /* fill swap hard limit here */
7454 7455 7456 7457
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.swap_hard_limit) < 0)
7458 7459 7460 7461 7462 7463 7464 7465 7466
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
7467 7468
    }

7469
    for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
7470
        virTypedParameterPtr param = &params[i];
7471
        unsigned long long val = 0;
7472

7473 7474 7475
        /* Coverity does not realize that if we get here, group is set.  */
        sa_assert(group);

7476
        switch (i) {
7477 7478 7479 7480 7481
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
7482
                goto cleanup;
7483
            }
7484 7485 7486
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7487
                goto cleanup;
7488 7489 7490 7491 7492 7493 7494
            break;

        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
7495
                goto cleanup;
7496
            }
7497 7498 7499
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7500
                goto cleanup;
7501 7502 7503
            break;

        case 2: /* fill swap hard limit here */
7504
            rc = virCgroupGetMemSwapHardLimit(group, &val);
7505 7506 7507
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
7508
                goto cleanup;
7509
            }
7510 7511 7512
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7513
                goto cleanup;
7514 7515 7516 7517 7518 7519 7520 7521
            break;

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

7522
out:
7523 7524
    if (QEMU_NB_MEM_PARAM < *nparams)
        *nparams = QEMU_NB_MEM_PARAM;
7525 7526
    ret = 0;

7527 7528 7529 7530
cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
7531
        virObjectUnlock(vm);
7532
    virObjectUnref(caps);
7533 7534 7535
    return ret;
}

7536 7537 7538 7539 7540 7541
static int
qemuDomainSetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
7542
    virQEMUDriverPtr driver = dom->conn->privateData;
7543 7544 7545 7546 7547
    int i;
    virDomainDefPtr persistentDef = NULL;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
7548
    virQEMUDriverConfigPtr cfg = NULL;
7549
    virCapsPtr caps = NULL;
7550 7551 7552

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7553 7554 7555 7556 7557 7558 7559
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_NUMA_MODE,
                                       VIR_TYPED_PARAM_INT,
                                       VIR_DOMAIN_NUMA_NODESET,
                                       VIR_TYPED_PARAM_STRING,
                                       NULL) < 0)
        return -1;
7560

7561
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7562 7563

    if (vm == NULL) {
7564 7565
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7566 7567
        goto cleanup;
    }
7568
    cfg = virQEMUDriverGetConfig(driver);
7569

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

7573
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7574 7575 7576 7577 7578
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
7579 7580
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup cpuset controller is not mounted"));
7581 7582 7583 7584
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7585 7586 7587
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598
            goto cleanup;
        }
    }

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

        if (STREQ(param->field, VIR_DOMAIN_NUMA_MODE)) {
            if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
                vm->def->numatune.memory.mode != params[i].value.i) {
7599 7600
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("can't change numa mode for running domain"));
7601 7602 7603 7604 7605 7606 7607 7608 7609
                ret = -1;
                goto cleanup;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                persistentDef->numatune.memory.mode = params[i].value.i;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) {
            int rc;
7610
            virBitmapPtr nodeset = NULL;
7611 7612
            char *nodeset_str = NULL;

7613 7614 7615
            if (virBitmapParse(params[i].value.s,
                               0, &nodeset,
                               VIR_DOMAIN_CPUMASK_LEN) < 0) {
7616 7617 7618 7619 7620
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to parse nodeset"));
                ret = -1;
                continue;
            }
7621 7622 7623 7624

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                if (vm->def->numatune.memory.mode !=
                    VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
7625 7626 7627
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("change of nodeset for running domain "
                                     "requires strict numa mode"));
7628
                    virBitmapFree(nodeset);
7629 7630 7631
                    ret = -1;
                    continue;
                }
7632 7633

                /* Ensure the cpuset string is formated before passing to cgroup */
7634
                if (!(nodeset_str = virBitmapFormat(nodeset))) {
7635 7636
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("Failed to format nodeset"));
7637
                    virBitmapFree(nodeset);
7638 7639 7640 7641 7642
                    ret = -1;
                    continue;
                }

                if ((rc = virCgroupSetCpusetMems(group, nodeset_str) != 0)) {
7643 7644
                    virReportSystemError(-rc, "%s",
                                         _("unable to set numa tunable"));
7645
                    virBitmapFree(nodeset);
7646
                    VIR_FREE(nodeset_str);
7647 7648 7649
                    ret = -1;
                    continue;
                }
7650
                VIR_FREE(nodeset_str);
7651 7652 7653

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

7656
                vm->def->numatune.memory.placement_mode =
G
Gao feng 已提交
7657
                    VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
7658
                vm->def->numatune.memory.nodemask = virBitmapNewCopy(nodeset);
7659 7660 7661
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7662
                virBitmapFree(persistentDef->numatune.memory.nodemask);
7663 7664

                persistentDef->numatune.memory.nodemask = nodeset;
7665
                persistentDef->numatune.memory.placement_mode =
G
Gao feng 已提交
7666
                    VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
7667
                nodeset = NULL;
7668
            }
7669
            virBitmapFree(nodeset);
7670 7671 7672 7673
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7674 7675
        if (!persistentDef->numatune.memory.placement_mode)
            persistentDef->numatune.memory.placement_mode =
G
Gao feng 已提交
7676
                VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO;
7677
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
7678 7679 7680 7681 7682 7683
            ret = -1;
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
7684
        virObjectUnlock(vm);
7685
    virObjectUnref(caps);
7686
    virObjectUnref(cfg);
7687 7688 7689 7690 7691 7692 7693 7694 7695
    return ret;
}

static int
qemuDomainGetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
7696
    virQEMUDriverPtr driver = dom->conn->privateData;
7697 7698 7699 7700 7701 7702 7703
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    char *nodeset = NULL;
    int ret = -1;
    int rc;
7704
    virCapsPtr caps = NULL;
7705 7706 7707 7708 7709 7710 7711 7712 7713 7714

    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;

7715
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7716 7717

    if (vm == NULL) {
7718 7719
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7720 7721 7722
        goto cleanup;
    }

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

7726
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737
                                        &persistentDef) < 0)
        goto cleanup;

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7738 7739
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7740 7741 7742 7743
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7744 7745 7746
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7747 7748 7749 7750 7751 7752 7753 7754 7755
            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 */
7756 7757
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
7758 7759 7760 7761 7762 7763 7764 7765 7766
                goto cleanup;
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                param->value.i = persistentDef->numatune.memory.mode;
            else
                param->value.i = vm->def->numatune.memory.mode;
            break;

        case 1: /* fill numa nodeset here */
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7767 7768
                nodeset = virBitmapFormat(persistentDef->numatune.memory.nodemask);
                if (!nodeset)
7769 7770 7771 7772 7773 7774 7775 7776 7777
                    nodeset = strdup("");
            } else {
                rc = virCgroupGetCpusetMems(group, &nodeset);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get numa nodeset"));
                    goto cleanup;
                }
            }
7778 7779
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
7780
                goto cleanup;
S
Stefan Berger 已提交
7781 7782 7783

            nodeset = NULL;

7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796
            break;

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

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

cleanup:
S
Stefan Berger 已提交
7797
    VIR_FREE(nodeset);
7798 7799
    virCgroupFree(&group);
    if (vm)
7800
        virObjectUnlock(vm);
7801
    virObjectUnref(caps);
7802 7803 7804
    return ret;
}

7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816
static int
qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                   unsigned long long period, long long quota)
{
    int i;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virCgroupPtr cgroup_vcpu = NULL;
    int rc;

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

W
Wen Congyang 已提交
7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836
    /* If we does not know VCPU<->PID mapping or all vcpu runs in the same
     * thread, we cannot control each vcpu. So we only modify cpu bandwidth
     * when each vcpu has a separated thread.
     */
    if (priv->nvcpupids != 0 && priv->vcpupids[0] != vm->pid) {
        for (i = 0; i < priv->nvcpupids; i++) {
            rc = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 0);
            if (rc < 0) {
                virReportSystemError(-rc,
                                     _("Unable to find vcpu cgroup for %s(vcpu:"
                                       " %d)"),
                                     vm->def->name, i);
                goto cleanup;
            }

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

            virCgroupFree(&cgroup_vcpu);
        }
7837 7838 7839 7840 7841 7842 7843 7844 7845
    }

    return 0;

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

7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879
static int
qemuSetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                             unsigned long long period, long long quota)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virCgroupPtr cgroup_emulator = NULL;
    int rc;

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

    if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
        return 0;
    }

    rc = virCgroupForEmulator(cgroup, &cgroup_emulator, 0);
    if (rc < 0) {
        virReportSystemError(-rc,
                             _("Unable to find emulator cgroup for %s"),
                             vm->def->name);
        goto cleanup;
    }

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

    virCgroupFree(&cgroup_emulator);
    return 0;

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

7880 7881 7882 7883 7884 7885 7886 7887 7888
#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;                                                       \
    }

7889 7890 7891 7892 7893
static int
qemuSetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int nparams,
                                unsigned int flags)
7894
{
7895
    virQEMUDriverPtr driver = dom->conn->privateData;
7896 7897 7898
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7899
    virDomainDefPtr vmdef = NULL;
7900 7901
    unsigned long long value_ul;
    long long value_l;
7902
    int ret = -1;
7903
    int rc;
7904
    virQEMUDriverConfigPtr cfg = NULL;
7905
    virCapsPtr caps = NULL;
7906

7907 7908
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7909 7910 7911 7912 7913 7914 7915
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                       VIR_TYPED_PARAM_LLONG,
7916 7917 7918 7919
                                       VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                                       VIR_TYPED_PARAM_LLONG,
7920 7921
                                       NULL) < 0)
        return -1;
7922

7923
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7924 7925

    if (vm == NULL) {
7926 7927
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7928 7929 7930
        goto cleanup;
    }

7931 7932
    cfg = virQEMUDriverGetConfig(driver);

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

7936
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7937 7938
                                        &vmdef) < 0)
        goto cleanup;
7939

7940 7941
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
7942
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
7943 7944
        if (!vmdef)
            goto cleanup;
7945 7946
    }

7947
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7948
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
7949 7950
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
7951 7952 7953
            goto cleanup;
        }
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7954 7955 7956
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7957 7958 7959 7960
            goto cleanup;
        }
    }

7961
    for (i = 0; i < nparams; i++) {
7962
        virTypedParameterPtr param = &params[i];
7963 7964
        value_ul = param->value.ul;
        value_l = param->value.l;
7965

7966
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
7967
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7968
                if ((rc = virCgroupSetCpuShares(group, value_ul))) {
7969 7970 7971 7972
                    virReportSystemError(-rc, "%s",
                                         _("unable to set cpu shares tunable"));
                    goto cleanup;
                }
7973
                vm->def->cputune.shares = value_ul;
7974
            }
7975

7976 7977 7978
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.shares = value_ul;

7979
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
7980 7981 7982
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

7983 7984
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
                if ((rc = qemuSetVcpusBWLive(vm, group, value_ul, 0)))
7985
                    goto cleanup;
7986

7987
                vm->def->cputune.period = value_ul;
7988 7989
            }

7990
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
7991
                vmdef->cputune.period = params[i].value.ul;
7992

7993
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
7994 7995 7996
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

7997 7998
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
                if ((rc = qemuSetVcpusBWLive(vm, group, 0, value_l)))
7999
                    goto cleanup;
8000

8001
                vm->def->cputune.quota = value_l;
8002 8003
            }

8004 8005 8006
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.quota = value_l;

8007
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD)) {
8008 8009 8010
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

8011 8012
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
                if ((rc = qemuSetEmulatorBandwidthLive(vm, group, value_ul, 0)))
8013 8014
                    goto cleanup;

8015
                vm->def->cputune.emulator_period = value_ul;
8016 8017
            }

8018 8019 8020
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_period = value_ul;

8021
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA)) {
8022 8023 8024
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

8025 8026
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
                if ((rc = qemuSetEmulatorBandwidthLive(vm, group, 0, value_l)))
8027 8028
                    goto cleanup;

8029
                vm->def->cputune.emulator_quota = value_l;
8030 8031
            }

8032 8033
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_quota = value_l;
8034 8035
        }
    }
8036

8037
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
8038 8039 8040 8041
        goto cleanup;


    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8042
        rc = virDomainSaveConfig(cfg->configDir, vmdef);
8043 8044 8045
        if (rc < 0)
            goto cleanup;

8046
        virDomainObjAssignDef(vm, vmdef, false, NULL);
8047 8048 8049
        vmdef = NULL;
    }

8050 8051 8052
    ret = 0;

cleanup:
8053
    virDomainDefFree(vmdef);
8054 8055
    virCgroupFree(&group);
    if (vm)
8056
        virObjectUnlock(vm);
8057
    virObjectUnref(caps);
8058
    virObjectUnref(cfg);
8059 8060
    return ret;
}
8061
#undef SCHED_RANGE_CHECK
8062

8063 8064 8065 8066
static int
qemuSetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int nparams)
8067 8068 8069 8070
{
    return qemuSetSchedulerParametersFlags(dom,
                                           params,
                                           nparams,
8071
                                           VIR_DOMAIN_AFFECT_CURRENT);
8072 8073
}

8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138
static int
qemuGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                  long long *quota)
{
    int rc;

    rc = virCgroupGetCpuCfsPeriod(cgroup, period);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth period tunable"));
        return -1;
    }

    rc = virCgroupGetCpuCfsQuota(cgroup, quota);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth tunable"));
        return -1;
    }

    return 0;
}

static int
qemuGetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                   unsigned long long *period, long long *quota)
{
    virCgroupPtr cgroup_vcpu = NULL;
    qemuDomainObjPrivatePtr priv = NULL;
    int rc;
    int ret = -1;

    priv = vm->privateData;
    if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
        /* We do not create sub dir for each vcpu */
        rc = qemuGetVcpuBWLive(cgroup, period, quota);
        if (rc < 0)
            goto cleanup;

        if (*quota > 0)
            *quota /= vm->def->vcpus;
        goto out;
    }

    /* get period and quota for vcpu0 */
    rc = virCgroupForVcpu(cgroup, 0, &cgroup_vcpu, 0);
    if (!cgroup_vcpu) {
        virReportSystemError(-rc,
                             _("Unable to find vcpu cgroup for %s(vcpu: 0)"),
                             vm->def->name);
        goto cleanup;
    }

    rc = qemuGetVcpuBWLive(cgroup_vcpu, period, quota);
    if (rc < 0)
        goto cleanup;

out:
    ret = 0;

cleanup:
    virCgroupFree(&cgroup_vcpu);
    return ret;
}

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
static int
qemuGetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                             unsigned long long *period, long long *quota)
{
    virCgroupPtr cgroup_emulator = NULL;
    qemuDomainObjPrivatePtr priv = NULL;
    int rc;
    int ret = -1;

    priv = vm->privateData;
    if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
        /* We don't create sub dir for each vcpu */
        *period = 0;
        *quota = 0;
        return 0;
    }

    /* get period and quota for emulator */
    rc = virCgroupForEmulator(cgroup, &cgroup_emulator, 0);
    if (!cgroup_emulator) {
        virReportSystemError(-rc,
                             _("Unable to find emulator cgroup for %s"),
                             vm->def->name);
        goto cleanup;
    }

    rc = qemuGetVcpuBWLive(cgroup_emulator, period, quota);
    if (rc < 0)
        goto cleanup;

    ret = 0;

cleanup:
    virCgroupFree(&cgroup_emulator);
    return ret;
}

8176 8177 8178 8179 8180
static int
qemuGetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int *nparams,
                                unsigned int flags)
8181
{
8182
    virQEMUDriverPtr driver = dom->conn->privateData;
8183 8184
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
8185 8186 8187
    unsigned long long shares;
    unsigned long long period;
    long long quota;
8188 8189
    unsigned long long emulator_period;
    long long emulator_quota;
8190 8191
    int ret = -1;
    int rc;
8192
    bool cpu_bw_status = false;
8193
    int saved_nparams = 0;
8194
    virDomainDefPtr persistentDef;
8195
    virCapsPtr caps = NULL;
8196

8197
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
8198 8199
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
8200

8201 8202 8203
    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

8204 8205 8206 8207 8208 8209 8210
    if (*nparams > 1) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        cpu_bw_status = !!rc;
    }

8211
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
8212 8213

    if (vm == NULL) {
8214 8215
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8216 8217 8218
        goto cleanup;
    }

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

8222
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8223 8224
                                        &persistentDef) < 0)
        goto cleanup;
8225

8226
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8227 8228 8229 8230
        shares = persistentDef->cputune.shares;
        if (*nparams > 1 && cpu_bw_status) {
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
8231 8232
            emulator_period = persistentDef->cputune.emulator_period;
            emulator_quota = persistentDef->cputune.emulator_quota;
8233
        }
8234
        goto out;
8235 8236
    }

8237
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8238 8239
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
8240 8241 8242
        goto cleanup;
    }

8243
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
8244 8245
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
8246 8247 8248
        goto cleanup;
    }

8249
    rc = virCgroupGetCpuShares(group, &shares);
8250
    if (rc != 0) {
8251
        virReportSystemError(-rc, "%s",
8252 8253 8254
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
8255 8256 8257 8258 8259 8260

    if (*nparams > 1 && cpu_bw_status) {
        rc = qemuGetVcpusBWLive(vm, group, &period, &quota);
        if (rc != 0)
            goto cleanup;
    }
8261 8262 8263 8264 8265 8266 8267 8268

    if (*nparams > 3 && cpu_bw_status) {
        rc = qemuGetEmulatorBandwidthLive(vm, group, &emulator_period,
                                          &emulator_quota);
        if (rc != 0)
            goto cleanup;
    }

8269
out:
8270 8271
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
8272
        goto cleanup;
8273 8274 8275 8276
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
8277 8278 8279
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
8280 8281 8282 8283 8284
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
8285 8286 8287
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
8288 8289 8290
                goto cleanup;
            saved_nparams++;
        }
8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308

        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++;
        }
8309 8310 8311 8312
    }

    *nparams = saved_nparams;

8313 8314 8315 8316 8317
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
8318
        virObjectUnlock(vm);
8319
    virObjectUnref(caps);
8320 8321 8322
    return ret;
}

8323 8324 8325 8326 8327 8328
static int
qemuGetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int *nparams)
{
    return qemuGetSchedulerParametersFlags(dom, params, nparams,
8329
                                           VIR_DOMAIN_AFFECT_CURRENT);
8330
}
8331

8332 8333 8334 8335 8336 8337 8338
/**
 * 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 已提交
8339 8340 8341 8342
qemuDomainBlockResize(virDomainPtr dom,
                      const char *path,
                      unsigned long long size,
                      unsigned int flags)
8343
{
8344
    virQEMUDriverPtr driver = dom->conn->privateData;
8345 8346 8347 8348 8349 8350
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1, i;
    char *device = NULL;
    virDomainDiskDefPtr disk = NULL;

E
Eric Blake 已提交
8351
    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
8352 8353

    if (path[0] == '\0') {
8354 8355
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("empty path"));
8356 8357 8358
        return -1;
    }

E
Eric Blake 已提交
8359 8360 8361
    /* We prefer operating on bytes.  */
    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
        if (size > ULLONG_MAX / 1024) {
8362 8363 8364
            virReportError(VIR_ERR_OVERFLOW,
                           _("size must be less than %llu"),
                           ULLONG_MAX / 1024);
E
Eric Blake 已提交
8365 8366 8367
            return -1;
        }
        size *= 1024;
8368 8369
    }

8370
    if (!(vm = qemuDomObjFromDomain(dom)))
8371 8372 8373 8374 8375 8376 8377 8378
        goto cleanup;

    priv = vm->privateData;

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

    if (!virDomainObjIsActive(vm)) {
8379 8380
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8381 8382 8383 8384
        goto endjob;
    }

    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8385 8386
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
8387
        goto endjob;
8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412
    }
    disk = vm->def->disks[i];

    if (virAsprintf(&device, "%s%s", QEMU_DRIVE_HOST_PREFIX,
                    disk->info.alias) < 0) {
        virReportOOMError();
        goto endjob;
    }

    qemuDomainObjEnterMonitor(driver, vm);
    if (qemuMonitorBlockResize(priv->mon, device, size) < 0) {
        qemuDomainObjExitMonitor(driver, vm);
        goto endjob;
    }
    qemuDomainObjExitMonitor(driver, vm);

    ret = 0;

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

cleanup:
    VIR_FREE(device);
    if (vm)
8413
        virObjectUnlock(vm);
8414 8415 8416
    return ret;
}

8417 8418 8419 8420 8421
/* 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
8422 8423 8424
qemuDomainBlockStats(virDomainPtr dom,
                     const char *path,
                     struct _virDomainBlockStats *stats)
8425
{
8426
    virQEMUDriverPtr driver = dom->conn->privateData;
8427
    int i, ret = -1;
8428
    virDomainObjPtr vm;
8429
    virDomainDiskDefPtr disk = NULL;
8430
    qemuDomainObjPrivatePtr priv;
8431

8432
    if (!(vm = qemuDomObjFromDomain(dom)))
8433
        goto cleanup;
8434

8435
    if (!virDomainObjIsActive(vm)) {
8436 8437
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8438 8439 8440
        goto cleanup;
    }

8441
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8442 8443
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
8444
        goto cleanup;
8445
    }
8446
    disk = vm->def->disks[i];
8447

8448
    if (!disk->info.alias) {
8449 8450
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
8451
        goto cleanup;
8452
    }
8453

8454
    priv = vm->privateData;
8455 8456
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;
8457

8458
    if (!virDomainObjIsActive(vm)) {
8459 8460
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8461 8462
        goto endjob;
    }
8463

8464
    qemuDomainObjEnterMonitor(driver, vm);
8465 8466 8467 8468
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
8469
                                       NULL,
8470 8471
                                       &stats->wr_req,
                                       &stats->wr_bytes,
8472 8473 8474
                                       NULL,
                                       NULL,
                                       NULL,
8475 8476
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
8477

8478
endjob:
8479 8480
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
8481

8482
cleanup:
8483
    if (vm)
8484
        virObjectUnlock(vm);
8485
    return ret;
8486 8487
}

8488
static int
8489 8490 8491 8492 8493
qemuDomainBlockStatsFlags(virDomainPtr dom,
                          const char *path,
                          virTypedParameterPtr params,
                          int *nparams,
                          unsigned int flags)
8494
{
8495
    virQEMUDriverPtr driver = dom->conn->privateData;
8496 8497 8498 8499 8500 8501
    int i, tmp, ret = -1;
    virDomainObjPtr vm;
    virDomainDiskDefPtr disk = NULL;
    qemuDomainObjPrivatePtr priv;
    long long rd_req, rd_bytes, wr_req, wr_bytes, rd_total_times;
    long long wr_total_times, flush_req, flush_total_times, errs;
8502
    virTypedParameterPtr param;
8503

8504 8505 8506 8507
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

8509
    if (!(vm = qemuDomObjFromDomain(dom)))
8510 8511
        goto cleanup;

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

8515
    if (!virDomainObjIsActive(vm)) {
8516 8517
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8518
        goto endjob;
8519 8520 8521
    }

    if (*nparams != 0) {
8522
        if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8523 8524
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
8525
            goto endjob;
8526
        }
8527
        disk = vm->def->disks[i];
8528 8529

        if (!disk->info.alias) {
8530 8531 8532
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("missing disk device alias name for %s"),
                            disk->dst);
8533
             goto endjob;
8534 8535 8536 8537 8538 8539 8540 8541 8542 8543
        }
    }

    priv = vm->privateData;
    VIR_DEBUG("priv=%p, params=%p, flags=%x", priv, params, flags);

    qemuDomainObjEnterMonitor(driver, vm);
    tmp = *nparams;
    ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);

8544
    if (tmp == 0 || ret < 0) {
8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565
        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;

8566 8567
    tmp = 0;
    ret = -1;
8568

8569 8570
    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
8571 8572
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
8573 8574 8575
            goto endjob;
        tmp++;
    }
8576

8577
    if (tmp < *nparams && wr_req != -1) {
8578
        param = &params[tmp];
8579 8580
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
8581 8582 8583
            goto endjob;
        tmp++;
    }
8584

8585
    if (tmp < *nparams && rd_bytes != -1) {
8586
        param = &params[tmp];
8587 8588
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
8589 8590 8591
            goto endjob;
        tmp++;
    }
8592

8593
    if (tmp < *nparams && rd_req != -1) {
8594
        param = &params[tmp];
8595 8596
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
8597 8598 8599
            goto endjob;
        tmp++;
    }
8600

8601
    if (tmp < *nparams && flush_req != -1) {
8602
        param = &params[tmp];
8603 8604
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ,
                                    VIR_TYPED_PARAM_LLONG, flush_req) < 0)
8605 8606 8607
            goto endjob;
        tmp++;
    }
8608

8609
    if (tmp < *nparams && wr_total_times != -1) {
8610
        param = &params[tmp];
8611 8612 8613
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, wr_total_times) < 0)
8614 8615 8616
            goto endjob;
        tmp++;
    }
8617

8618
    if (tmp < *nparams && rd_total_times != -1) {
8619
        param = &params[tmp];
8620 8621 8622
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, rd_total_times) < 0)
8623 8624 8625
            goto endjob;
        tmp++;
    }
8626

8627
    if (tmp < *nparams && flush_total_times != -1) {
8628
        param = &params[tmp];
8629 8630 8631 8632
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG,
                                    flush_total_times) < 0)
8633 8634
            goto endjob;
        tmp++;
8635 8636
    }

8637 8638 8639 8640 8641
    /* Field 'errs' is meaningless for QEMU, won't set it. */

    ret = 0;
    *nparams = tmp;

8642 8643 8644 8645 8646 8647
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

cleanup:
    if (vm)
8648
        virObjectUnlock(vm);
8649 8650 8651
    return ret;
}

8652
#ifdef __linux__
8653
static int
8654 8655 8656
qemuDomainInterfaceStats(virDomainPtr dom,
                         const char *path,
                         struct _virDomainInterfaceStats *stats)
8657
{
8658
    virDomainObjPtr vm;
8659
    int i;
8660
    int ret = -1;
8661

8662
    if (!(vm = qemuDomObjFromDomain(dom)))
8663
        goto cleanup;
8664

D
Daniel P. Berrange 已提交
8665
    if (!virDomainObjIsActive(vm)) {
8666 8667
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8668
        goto cleanup;
8669 8670 8671
    }

    /* Check the path is one of the domain's network interfaces. */
8672 8673
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
8674
            STREQ(vm->def->nets[i]->ifname, path)) {
8675 8676 8677
            ret = 0;
            break;
        }
8678 8679
    }

8680
    if (ret == 0)
8681
        ret = linuxDomainInterfaceStats(path, stats);
8682
    else
8683 8684
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path, '%s' is not a known interface"), path);
8685

8686
cleanup:
8687
    if (vm)
8688
        virObjectUnlock(vm);
8689 8690
    return ret;
}
8691
#else
8692
static int
E
Eric Blake 已提交
8693
qemuDomainInterfaceStats(virDomainPtr dom ATTRIBUTE_UNUSED,
8694 8695
                         const char *path ATTRIBUTE_UNUSED,
                         struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
8696
{
8697 8698
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("interface stats not implemented on this platform"));
8699 8700
    return -1;
}
8701
#endif
8702

8703 8704 8705 8706 8707 8708 8709
static int
qemuDomainSetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 unsigned int flags)
{
8710
    virQEMUDriverPtr driver = dom->conn->privateData;
8711 8712 8713 8714 8715 8716
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    virDomainNetDefPtr net = NULL, persistentNet = NULL;
8717
    virNetDevBandwidthPtr bandwidth = NULL, newBandwidth = NULL;
8718
    virQEMUDriverConfigPtr cfg = NULL;
8719
    virCapsPtr caps = NULL;
8720 8721 8722

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                       VIR_TYPED_PARAM_UINT,
                                       NULL) < 0)
        return -1;
8738

8739
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
8740 8741

    if (vm == NULL) {
8742 8743
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8744 8745 8746
        goto cleanup;
    }

8747 8748
    cfg = virQEMUDriverGetConfig(driver);

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

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        net = virDomainNetFind(vm->def, device);
        if (!net) {
8759 8760
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
8761 8762 8763 8764 8765 8766
            goto cleanup;
        }
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        persistentNet = virDomainNetFind(persistentDef, device);
        if (!persistentNet) {
8767 8768
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
8769 8770 8771 8772
            goto cleanup;
        }
    }

8773 8774 8775
    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
        (VIR_ALLOC(bandwidth->out) < 0)) {
8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797
        virReportOOMError();
        goto cleanup;
    }

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

        if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_AVERAGE)) {
            bandwidth->in->average = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_PEAK)) {
            bandwidth->in->peak = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_BURST)) {
            bandwidth->in->burst = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE)) {
            bandwidth->out->average = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_PEAK)) {
            bandwidth->out->peak = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_BURST)) {
            bandwidth->out->burst = params[i].value.ui;
        }
    }

8798
    /* average is mandatory, peak and burst are optional. So if no
8799
     * average is given, we free inbound/outbound here which causes
8800
     * inbound/outbound to not be set. */
8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815
    if (!bandwidth->in->average) {
        VIR_FREE(bandwidth->in);
    }
    if (!bandwidth->out->average) {
        VIR_FREE(bandwidth->out);
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (VIR_ALLOC(newBandwidth) < 0) {
            virReportOOMError();
            goto cleanup;
        }

        /* virNetDevBandwidthSet() will clear any previous value of
         * bandwidth parameters, so merge with old bandwidth parameters
8816
         * here to prevent them from being lost. */
8817 8818
        if (bandwidth->in ||
            (net->bandwidth && net->bandwidth->in)) {
8819 8820 8821 8822
            if (VIR_ALLOC(newBandwidth->in) < 0) {
                virReportOOMError();
                goto cleanup;
            }
8823 8824 8825 8826 8827 8828 8829

            memcpy(newBandwidth->in,
                   bandwidth->in ? bandwidth->in : net->bandwidth->in,
                   sizeof(*newBandwidth->in));
        }
        if (bandwidth->out ||
            (net->bandwidth && net->bandwidth->out)) {
8830 8831 8832 8833
            if (VIR_ALLOC(newBandwidth->out) < 0) {
                virReportOOMError();
                goto cleanup;
            }
8834 8835 8836 8837

            memcpy(newBandwidth->out,
                   bandwidth->out ? bandwidth->out : net->bandwidth->out,
                   sizeof(*newBandwidth->out));
8838 8839
        }

8840
        if (virNetDevBandwidthSet(net->ifname, newBandwidth, false) < 0) {
8841 8842 8843
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot set bandwidth limits on %s"),
                           device);
8844 8845 8846 8847 8848
            goto cleanup;
        }

        virNetDevBandwidthFree(net->bandwidth);
        net->bandwidth = newBandwidth;
E
Eric Blake 已提交
8849
        newBandwidth = NULL;
8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!persistentNet->bandwidth) {
            persistentNet->bandwidth = bandwidth;
            bandwidth = NULL;
        } else {
            if (bandwidth->in) {
                VIR_FREE(persistentNet->bandwidth->in);
                persistentNet->bandwidth->in = bandwidth->in;
                bandwidth->in = NULL;
            }
            if (bandwidth->out) {
                VIR_FREE(persistentNet->bandwidth->out);
                persistentNet->bandwidth->out = bandwidth->out;
                bandwidth->out = NULL;
            }
        }

8868
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
8869 8870 8871 8872 8873 8874
            goto cleanup;
    }

    ret = 0;
cleanup:
    virNetDevBandwidthFree(bandwidth);
8875
    virNetDevBandwidthFree(newBandwidth);
8876 8877
    virCgroupFree(&group);
    if (vm)
8878
        virObjectUnlock(vm);
8879
    virObjectUnref(caps);
8880
    virObjectUnref(cfg);
8881 8882 8883 8884 8885 8886 8887 8888 8889 8890
    return ret;
}

static int
qemuDomainGetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int *nparams,
                                 unsigned int flags)
{
8891
    virQEMUDriverPtr driver = dom->conn->privateData;
8892 8893 8894 8895 8896 8897 8898
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainDefPtr persistentDef = NULL;
    virDomainNetDefPtr net = NULL;
    int ret = -1;
8899
    virCapsPtr caps = NULL;
8900 8901 8902 8903 8904 8905 8906

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

8907
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
8908 8909

    if (vm == NULL) {
8910 8911
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8912 8913 8914
        goto cleanup;
    }

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

8918
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933
                                        &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) {
8934 8935
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Can't find device %s"), device);
8936 8937 8938 8939
        goto cleanup;
    }

    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
8940
        switch (i) {
8941
        case 0: /* inbound.average */
8942 8943 8944
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8945 8946 8947 8948 8949
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->average;
            break;
        case 1: /* inbound.peak */
8950 8951 8952
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8953 8954 8955 8956 8957
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->peak;
            break;
        case 2: /* inbound.burst */
8958 8959 8960
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8961 8962 8963 8964 8965
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->burst;
            break;
        case 3: /* outbound.average */
8966 8967 8968
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8969 8970 8971 8972 8973
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->average;
            break;
        case 4: /* outbound.peak */
8974 8975 8976
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8977 8978 8979 8980 8981
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->peak;
            break;
        case 5: /* outbound.burst */
8982 8983 8984
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->burst;
            break;
        default:
            break;
            /* should not hit here */
        }
    }

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

cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
9003
        virObjectUnlock(vm);
9004
    virObjectUnref(caps);
9005 9006 9007
    return ret;
}

9008
static int
9009 9010 9011 9012
qemuDomainMemoryStats(virDomainPtr dom,
                      struct _virDomainMemoryStat *stats,
                      unsigned int nr_stats,
                      unsigned int flags)
9013
{
9014
    virQEMUDriverPtr driver = dom->conn->privateData;
9015
    virDomainObjPtr vm;
M
Martin Kletzander 已提交
9016
    int ret = -1;
9017

9018 9019
    virCheckFlags(0, -1);

9020
    if (!(vm = qemuDomObjFromDomain(dom)))
9021 9022
        goto cleanup;

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

M
Martin Kletzander 已提交
9026
    if (!virDomainObjIsActive(vm)) {
9027 9028
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
M
Martin Kletzander 已提交
9029
    } else {
9030
        qemuDomainObjPrivatePtr priv = vm->privateData;
9031
        qemuDomainObjEnterMonitor(driver, vm);
9032
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
9033
        qemuDomainObjExitMonitor(driver, vm);
M
Martin Kletzander 已提交
9034 9035 9036

        if (ret >= 0 && ret < nr_stats) {
            long rss;
9037
            if (qemuGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) {
9038 9039
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("cannot get RSS for domain"));
M
Martin Kletzander 已提交
9040 9041 9042 9043 9044 9045 9046
            } else {
                stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
                stats[ret].val = rss;
                ret++;
            }

        }
9047 9048
    }

9049
    if (qemuDomainObjEndJob(driver, vm) == 0)
9050 9051
        vm = NULL;

9052 9053
cleanup:
    if (vm)
9054
        virObjectUnlock(vm);
9055 9056 9057
    return ret;
}

9058
static int
9059 9060 9061 9062 9063
qemuDomainBlockPeek(virDomainPtr dom,
                    const char *path,
                    unsigned long long offset, size_t size,
                    void *buffer,
                    unsigned int flags)
9064
{
9065
    virDomainObjPtr vm;
9066 9067
    int fd = -1, ret = -1;
    const char *actual;
9068

E
Eric Blake 已提交
9069 9070
    virCheckFlags(0, -1);

9071
    if (!(vm = qemuDomObjFromDomain(dom)))
9072
        goto cleanup;
9073 9074

    if (!path || path[0] == '\0') {
9075 9076
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
9077
        goto cleanup;
9078 9079
    }

9080 9081
    /* Check the path belongs to this domain.  */
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
9082 9083
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path '%s'"), path);
9084
        goto cleanup;
9085
    }
9086
    path = actual;
9087

9088 9089 9090 9091 9092 9093 9094
    /* The path is correct, now try to open it and get its size. */
    fd = open(path, O_RDONLY);
    if (fd == -1) {
        virReportSystemError(errno,
                             _("%s: failed to open"), path);
        goto cleanup;
    }
9095

9096 9097 9098 9099 9100 9101 9102 9103 9104
    /* 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;
9105 9106
    }

9107 9108
    ret = 0;

9109
cleanup:
9110
    VIR_FORCE_CLOSE(fd);
9111
    if (vm)
9112
        virObjectUnlock(vm);
9113 9114 9115
    return ret;
}

R
Richard W.M. Jones 已提交
9116
static int
9117 9118 9119 9120
qemuDomainMemoryPeek(virDomainPtr dom,
                     unsigned long long offset, size_t size,
                     void *buffer,
                     unsigned int flags)
R
Richard W.M. Jones 已提交
9121
{
9122
    virQEMUDriverPtr driver = dom->conn->privateData;
9123
    virDomainObjPtr vm;
9124
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
9125
    int fd = -1, ret = -1;
9126
    qemuDomainObjPrivatePtr priv;
9127
    virQEMUDriverConfigPtr cfg = NULL;
R
Richard W.M. Jones 已提交
9128

9129 9130
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

9131
    if (!(vm = qemuDomObjFromDomain(dom)))
9132 9133
        goto cleanup;

9134 9135
    cfg = virQEMUDriverGetConfig(driver);

9136
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
9137 9138
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
9139
        goto cleanup;
R
Richard W.M. Jones 已提交
9140 9141
    }

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

D
Daniel P. Berrange 已提交
9145
    if (!virDomainObjIsActive(vm)) {
9146 9147
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9148
        goto endjob;
R
Richard W.M. Jones 已提交
9149 9150
    }

9151
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", cfg->cacheDir) < 0) {
9152
        virReportOOMError();
9153
        goto endjob;
9154 9155
    }

R
Richard W.M. Jones 已提交
9156
    /* Create a temporary filename. */
9157
    if ((fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
9158
        virReportSystemError(errno,
9159
                             _("mkostemp(\"%s\") failed"), tmp);
9160
        goto endjob;
R
Richard W.M. Jones 已提交
9161 9162
    }

9163
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
9164

9165
    priv = vm->privateData;
9166
    qemuDomainObjEnterMonitor(driver, vm);
9167
    if (flags == VIR_MEMORY_VIRTUAL) {
9168
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
9169
            qemuDomainObjExitMonitor(driver, vm);
9170
            goto endjob;
9171
        }
9172
    } else {
9173
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
9174
            qemuDomainObjExitMonitor(driver, vm);
9175
            goto endjob;
9176
        }
R
Richard W.M. Jones 已提交
9177
    }
9178
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
9179 9180

    /* Read the memory file into buffer. */
9181
    if (saferead(fd, buffer, size) == (ssize_t) -1) {
9182 9183 9184
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
9185
        goto endjob;
R
Richard W.M. Jones 已提交
9186 9187 9188
    }

    ret = 0;
9189

9190
endjob:
9191
    if (qemuDomainObjEndJob(driver, vm) == 0)
9192
        vm = NULL;
9193

9194
cleanup:
9195
    VIR_FORCE_CLOSE(fd);
9196 9197
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
9198
    VIR_FREE(tmp);
9199
    if (vm)
9200
        virObjectUnlock(vm);
9201
    virObjectUnref(cfg);
R
Richard W.M. Jones 已提交
9202 9203 9204
    return ret;
}

9205

9206 9207 9208 9209
static int qemuDomainGetBlockInfo(virDomainPtr dom,
                                  const char *path,
                                  virDomainBlockInfoPtr info,
                                  unsigned int flags) {
9210
    virQEMUDriverPtr driver = dom->conn->privateData;
9211 9212 9213 9214
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
9215
    virStorageFileMetadata *meta = NULL;
9216
    virDomainDiskDefPtr disk = NULL;
9217
    struct stat sb;
9218
    int i;
9219
    int format;
9220
    virQEMUDriverConfigPtr cfg = NULL;
9221 9222 9223

    virCheckFlags(0, -1);

9224
    if (!(vm = qemuDomObjFromDomain(dom)))
9225 9226
        goto cleanup;

9227 9228
    cfg = virQEMUDriverGetConfig(driver);

9229
    if (!path || path[0] == '\0') {
9230 9231
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
9232 9233 9234 9235
        goto cleanup;
    }

    /* Check the path belongs to this domain. */
9236
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9237 9238
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path %s not assigned to domain"), path);
9239 9240
        goto cleanup;
    }
9241 9242
    disk = vm->def->disks[i];
    if (!disk->src) {
9243 9244 9245
        virReportError(VIR_ERR_INVALID_ARG,
                       _("disk %s does not currently have a source assigned"),
                       path);
9246 9247 9248
        goto cleanup;
    }
    path = disk->src;
9249 9250

    /* The path is correct, now try to open it and get its size. */
9251
    fd = open(path, O_RDONLY);
9252 9253 9254 9255 9256 9257 9258
    if (fd == -1) {
        virReportSystemError(errno,
                             _("failed to open path '%s'"), path);
        goto cleanup;
    }

    /* Probe for magic formats */
9259 9260
    if (disk->format) {
        format = disk->format;
9261
    } else {
9262 9263 9264 9265
        if (cfg->allowDiskFormatProbing) {
            if ((format = virStorageFileProbeFormat(disk->src,
                                                    cfg->user,
                                                    cfg->group)) < 0)
9266 9267
                goto cleanup;
        } else {
9268 9269 9270
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no disk format for %s and probing is disabled"),
                           disk->src);
9271
            goto cleanup;
9272
        }
9273 9274
    }

9275
    if (!(meta = virStorageFileGetMetadataFromFD(path, fd, format)))
9276 9277 9278 9279 9280 9281 9282 9283 9284 9285
        goto cleanup;

    /* Get info for normal formats */
    if (fstat(fd, &sb) < 0) {
        virReportSystemError(errno,
                             _("cannot stat file '%s'"), path);
        goto cleanup;
    }

    if (S_ISREG(sb.st_mode)) {
9286
#ifndef WIN32
9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299
        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.
         */
9300
        end = lseek(fd, 0, SEEK_END);
9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311
        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 */
9312 9313
    if (meta->capacity)
        info->capacity = meta->capacity;
9314

9315
    /* Set default value .. */
9316 9317
    info->allocation = info->physical;

9318 9319 9320
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
9321
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
9322
        format != VIR_STORAGE_FILE_RAW &&
9323 9324
        S_ISBLK(sb.st_mode) &&
        virDomainObjIsActive(vm)) {
9325
        qemuDomainObjPrivatePtr priv = vm->privateData;
9326

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

9330
        if (virDomainObjIsActive(vm)) {
9331
            qemuDomainObjEnterMonitor(driver, vm);
9332 9333 9334 9335
            ret = qemuMonitorGetBlockExtent(priv->mon,
                                            disk->info.alias,
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
9336
        } else {
9337
            ret = 0;
9338
        }
9339 9340 9341

        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
9342 9343 9344
    } else {
        ret = 0;
    }
9345 9346

cleanup:
9347
    virStorageFileFreeMetadata(meta);
9348
    VIR_FORCE_CLOSE(fd);
9349
    if (vm)
9350
        virObjectUnlock(vm);
9351
    virObjectUnref(cfg);
9352 9353 9354 9355
    return ret;
}


9356
static int
9357 9358 9359 9360
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
9361
{
9362
    virQEMUDriverPtr driver = conn->privateData;
9363 9364
    int ret;

9365 9366 9367
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
9368

9369
    return ret;
9370 9371
}

9372

9373
static int
9374 9375
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
9376
{
9377
    virQEMUDriverPtr driver = conn->privateData;
9378 9379
    int ret;

9380 9381 9382
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
9383

9384
    return ret;
9385 9386
}

9387 9388 9389 9390 9391 9392 9393 9394 9395

static int
qemuDomainEventRegisterAny(virConnectPtr conn,
                           virDomainPtr dom,
                           int eventID,
                           virConnectDomainEventGenericCallback callback,
                           void *opaque,
                           virFreeCallback freecb)
{
9396
    virQEMUDriverPtr driver = conn->privateData;
9397 9398
    int ret;

9399 9400 9401 9402
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
9403
        ret = -1;
9404 9405 9406 9407 9408 9409 9410 9411 9412

    return ret;
}


static int
qemuDomainEventDeregisterAny(virConnectPtr conn,
                             int callbackID)
{
9413
    virQEMUDriverPtr driver = conn->privateData;
9414 9415
    int ret;

9416 9417 9418
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
9419 9420 9421 9422 9423

    return ret;
}


9424 9425 9426
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
9427

C
Chris Lalancette 已提交
9428 9429 9430 9431 9432 9433
/* 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
9434 9435 9436 9437 9438 9439
qemuDomainMigratePrepareTunnel(virConnectPtr dconn,
                               virStreamPtr st,
                               unsigned long flags,
                               const char *dname,
                               unsigned long resource ATTRIBUTE_UNUSED,
                               const char *dom_xml)
C
Chris Lalancette 已提交
9440
{
9441
    virQEMUDriverPtr driver = dconn->privateData;
C
Chris Lalancette 已提交
9442
    int ret = -1;
9443

9444
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9445

C
Chris Lalancette 已提交
9446
    if (!dom_xml) {
9447 9448
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
9449 9450 9451
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9452 9453
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
C
Chris Lalancette 已提交
9454 9455 9456
        goto cleanup;
    }
    if (st == NULL) {
9457 9458
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
9459 9460 9461
        goto cleanup;
    }

9462
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9463 9464 9465
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9466 9467 9468
        goto cleanup;
    }

9469 9470
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
L
liguang 已提交
9471
                                     st, dname, dom_xml, flags);
9472

C
Chris Lalancette 已提交
9473 9474 9475 9476
cleanup:
    return ret;
}

D
Daniel Veillard 已提交
9477 9478 9479 9480
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
9481
static int ATTRIBUTE_NONNULL(5)
9482 9483 9484 9485 9486 9487 9488 9489 9490
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 已提交
9491
{
9492
    virQEMUDriverPtr driver = dconn->privateData;
9493
    int ret = -1;
9494

9495
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
9496

9497
    *uri_out = NULL;
D
Daniel Veillard 已提交
9498

9499
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9500 9501 9502
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9503 9504 9505
        goto cleanup;
    }

C
Chris Lalancette 已提交
9506 9507 9508 9509
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9510 9511
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
9512 9513 9514
        goto cleanup;
    }

D
Daniel Veillard 已提交
9515
    if (!dom_xml) {
9516 9517
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9518
        goto cleanup;
D
Daniel Veillard 已提交
9519 9520
    }

9521 9522 9523 9524
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
9525
    ret = qemuMigrationPrepareDirect(driver, dconn,
9526
                                     NULL, 0, NULL, NULL, /* No cookies */
9527
                                     uri_in, uri_out,
L
liguang 已提交
9528
                                     dname, dom_xml, flags);
D
Daniel Veillard 已提交
9529

9530 9531 9532
cleanup:
    return ret;
}
C
Chris Lalancette 已提交
9533

D
Daniel Veillard 已提交
9534

9535 9536
/* Perform is the second step, and it runs on the source host. */
static int
9537 9538 9539 9540 9541 9542 9543
qemuDomainMigratePerform(virDomainPtr dom,
                         const char *cookie,
                         int cookielen,
                         const char *uri,
                         unsigned long flags,
                         const char *dname,
                         unsigned long resource)
9544
{
9545
    virQEMUDriverPtr driver = dom->conn->privateData;
9546 9547
    virDomainObjPtr vm;
    int ret = -1;
9548
    const char *dconnuri = NULL;
9549

9550
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
9551

9552
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9553 9554 9555
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9556 9557 9558
        goto cleanup;
    }

9559
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
D
Daniel Veillard 已提交
9560
    if (!vm) {
9561 9562
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9563 9564
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9565
        goto cleanup;
D
Daniel Veillard 已提交
9566 9567
    }

9568 9569 9570 9571 9572
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

9573 9574 9575 9576 9577 9578
    /* 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
     */
9579
    ret = qemuMigrationPerform(driver, dom->conn, vm,
9580
                               NULL, dconnuri, uri, cookie, cookielen,
9581
                               NULL, NULL, /* No output cookies in v2 */
9582
                               flags, dname, resource, false);
9583

9584
cleanup:
9585
    return ret;
D
Daniel Veillard 已提交
9586 9587
}

9588

D
Daniel Veillard 已提交
9589 9590
/* Finish is the third and final step, and it runs on the destination host. */
static virDomainPtr
9591 9592 9593 9594 9595 9596 9597
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 已提交
9598
{
9599
    virQEMUDriverPtr driver = dconn->privateData;
9600 9601
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
9602

9603
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
9604

9605
    vm = virDomainObjListFindByName(driver->domains, dname);
D
Daniel Veillard 已提交
9606
    if (!vm) {
9607 9608
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
9609
        goto cleanup;
D
Daniel Veillard 已提交
9610 9611
    }

9612 9613 9614 9615
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
9616
    dom = qemuMigrationFinish(driver, dconn, vm,
9617
                              NULL, 0, NULL, NULL, /* No cookies */
9618
                              flags, retcode, false);
9619

9620 9621
cleanup:
    return dom;
D
Daniel Veillard 已提交
9622 9623
}

9624

9625 9626 9627 9628 9629 9630
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
9631
                        const char *xmlin,
9632 9633 9634
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
9635
                        const char *dname,
9636 9637
                        unsigned long resource ATTRIBUTE_UNUSED)
{
9638
    virQEMUDriverPtr driver = domain->conn->privateData;
9639 9640
    virDomainObjPtr vm;
    char *xml = NULL;
9641
    enum qemuDomainAsyncJob asyncJob;
9642

9643
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9644

9645
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
9646 9647 9648
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
9649 9650
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9651 9652 9653
        goto cleanup;
    }

9654 9655 9656
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cleanup;
9657
        asyncJob = QEMU_ASYNC_JOB_MIGRATION_OUT;
9658
    } else {
9659
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
9660
            goto cleanup;
9661
        asyncJob = QEMU_ASYNC_JOB_NONE;
9662 9663
    }

L
liguang 已提交
9664
    if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
9665 9666
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9667 9668 9669
        goto endjob;
    }

9670 9671 9672
    /* Check if there is any ejected media.
     * We don't want to require them on the destination.
     */
L
liguang 已提交
9673 9674
    if (!(flags & VIR_MIGRATE_OFFLINE) &&
        qemuDomainCheckEjectableMedia(driver, vm, asyncJob) < 0)
9675 9676
        goto endjob;

9677
    if (!(xml = qemuMigrationBegin(driver, vm, xmlin, dname,
9678 9679
                                   cookieout, cookieoutlen,
                                   flags)))
9680 9681 9682 9683 9684 9685 9686
        goto endjob;

    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        /* We keep the job active across API calls until the confirm() call.
         * This prevents any other APIs being invoked while migration is taking
         * place.
         */
9687 9688
        if (virQEMUCloseCallbacksSet(driver->closeCallbacks, vm, domain->conn,
                                     qemuMigrationCleanup) < 0)
9689
            goto endjob;
9690 9691
        if (qemuMigrationJobContinue(vm) == 0) {
            vm = NULL;
9692 9693
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("domain disappeared"));
9694 9695 9696 9697 9698 9699 9700
            VIR_FREE(xml);
            if (cookieout)
                VIR_FREE(*cookieout);
        }
    } else {
        goto endjob;
    }
9701 9702

cleanup:
9703
    if (vm)
9704
        virObjectUnlock(vm);
9705
    return xml;
9706 9707 9708 9709 9710 9711 9712 9713 9714 9715

endjob:
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobFinish(driver, vm) == 0)
            vm = NULL;
    } else {
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    }
    goto cleanup;
9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730
}

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)
{
9731
    virQEMUDriverPtr driver = dconn->privateData;
9732 9733
    int ret = -1;

9734
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9735 9736 9737 9738 9739 9740 9741

    *uri_out = NULL;

    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9742 9743
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Tunnelled migration requested but invalid RPC method called"));
9744 9745 9746 9747
        goto cleanup;
    }

    if (!dom_xml) {
9748 9749
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9750 9751 9752 9753 9754 9755 9756
        goto cleanup;
    }

    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
L
liguang 已提交
9757
                                     dname, dom_xml, flags);
9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775

cleanup:
    return ret;
}


static int
qemuDomainMigratePrepareTunnel3(virConnectPtr dconn,
                                virStreamPtr st,
                                const char *cookiein,
                                int cookieinlen,
                                char **cookieout,
                                int *cookieoutlen,
                                unsigned long flags,
                                const char *dname,
                                unsigned long resource ATTRIBUTE_UNUSED,
                                const char *dom_xml)
{
9776
    virQEMUDriverPtr driver = dconn->privateData;
9777 9778
    int ret = -1;

9779
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9780 9781

    if (!dom_xml) {
9782 9783
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9784 9785 9786
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9787 9788
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
9789 9790 9791
        goto cleanup;
    }
    if (st == NULL) {
9792 9793
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("tunnelled migration requested but NULL stream passed"));
9794 9795 9796 9797 9798 9799
        goto cleanup;
    }

    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
L
liguang 已提交
9800
                                     st, dname, dom_xml, flags);
9801 9802 9803 9804 9805 9806 9807 9808

cleanup:
    return ret;
}


static int
qemuDomainMigratePerform3(virDomainPtr dom,
9809
                          const char *xmlin,
9810 9811 9812 9813
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
9814
                          const char *dconnuri,
9815 9816 9817 9818 9819
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
9820
    virQEMUDriverPtr driver = dom->conn->privateData;
9821 9822 9823
    virDomainObjPtr vm;
    int ret = -1;

9824
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9825

9826
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
9827 9828 9829
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9830 9831
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9832 9833 9834
        goto cleanup;
    }

9835
    ret = qemuMigrationPerform(driver, dom->conn, vm, xmlin,
9836
                               dconnuri, uri, cookiein, cookieinlen,
9837
                               cookieout, cookieoutlen,
9838
                               flags, dname, resource, true);
9839 9840 9841 9842 9843 9844

cleanup:
    return ret;
}


9845
static virDomainPtr
9846 9847 9848 9849 9850 9851
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
9852
                         const char *dconnuri ATTRIBUTE_UNUSED,
9853 9854
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
9855
                         int cancelled)
9856
{
9857
    virQEMUDriverPtr driver = dconn->privateData;
9858
    virDomainObjPtr vm;
9859
    virDomainPtr dom = NULL;
9860

9861
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9862

9863
    vm = virDomainObjListFindByName(driver->domains, dname);
9864
    if (!vm) {
9865 9866
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
9867 9868 9869
        goto cleanup;
    }

9870 9871 9872 9873
    dom = qemuMigrationFinish(driver, dconn, vm,
                              cookiein, cookieinlen,
                              cookieout, cookieoutlen,
                              flags, cancelled, true);
9874 9875

cleanup:
9876
    return dom;
9877 9878 9879 9880 9881 9882 9883 9884 9885
}

static int
qemuDomainMigrateConfirm3(virDomainPtr domain,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned long flags,
                          int cancelled)
{
9886
    virQEMUDriverPtr driver = domain->conn->privateData;
9887 9888
    virDomainObjPtr vm;
    int ret = -1;
9889
    enum qemuMigrationJobPhase phase;
9890
    virQEMUDriverConfigPtr cfg = NULL;
9891

9892
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9893

9894
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
9895 9896 9897
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
9898 9899
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9900 9901 9902
        goto cleanup;
    }

9903 9904
    cfg = virQEMUDriverGetConfig(driver);

9905
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
9906 9907
        goto cleanup;

9908 9909 9910 9911 9912 9913
    if (cancelled)
        phase = QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED;
    else
        phase = QEMU_MIGRATION_PHASE_CONFIRM3;

    qemuMigrationJobStartPhase(driver, vm, phase);
9914 9915
    virQEMUCloseCallbacksUnset(driver->closeCallbacks, vm,
                               qemuMigrationCleanup);
9916

9917 9918
    ret = qemuMigrationConfirm(driver, domain->conn, vm,
                               cookiein, cookieinlen,
9919 9920
                               flags, cancelled);

9921
    if (qemuMigrationJobFinish(driver, vm) == 0) {
9922 9923 9924 9925
        vm = NULL;
    } else if (!virDomainObjIsActive(vm) &&
               (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE))) {
        if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
9926
            virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
9927
        qemuDomainRemoveInactive(driver, vm);
9928 9929 9930
        vm = NULL;
    }

9931
cleanup:
9932
    if (vm)
9933
        virObjectUnlock(vm);
9934
    virObjectUnref(cfg);
9935 9936 9937 9938
    return ret;
}


9939
static int
9940 9941 9942 9943 9944
qemuNodeDeviceGetPciInfo(virNodeDevicePtr dev,
                         unsigned *domain,
                         unsigned *bus,
                         unsigned *slot,
                         unsigned *function)
9945 9946 9947 9948 9949 9950 9951 9952 9953 9954
{
    virNodeDeviceDefPtr def = NULL;
    virNodeDevCapsDefPtr cap;
    char *xml = NULL;
    int ret = -1;

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto out;

9955
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972
    if (!def)
        goto out;

    cap = def->caps;
    while (cap) {
        if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) {
            *domain   = cap->data.pci_dev.domain;
            *bus      = cap->data.pci_dev.bus;
            *slot     = cap->data.pci_dev.slot;
            *function = cap->data.pci_dev.function;
            break;
        }

        cap = cap->next;
    }

    if (!cap) {
9973 9974
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device %s is not a PCI device"), dev->name);
9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
9986
qemuNodeDeviceDettach(virNodeDevicePtr dev)
9987
{
9988
    virQEMUDriverPtr driver = dev->conn->privateData;
9989
    virPCIDevicePtr pci;
9990 9991
    unsigned domain, bus, slot, function;
    int ret = -1;
9992
    bool in_inactive_list = false;
9993

9994
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
9995 9996
        return -1;

9997
    pci = virPCIDeviceNew(domain, bus, slot, function);
9998 9999 10000
    if (!pci)
        return -1;

10001 10002
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
10003
    in_inactive_list = virPCIDeviceListFind(driver->inactivePciHostdevs, pci);
10004

10005 10006
    if (virPCIDeviceDetach(pci, driver->activePciHostdevs,
                           driver->inactivePciHostdevs, "pci-stub") < 0)
10007 10008 10009 10010
        goto out;

    ret = 0;
out:
10011 10012
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
10013
    if (in_inactive_list)
10014
        virPCIDeviceFree(pci);
10015 10016 10017 10018
    return ret;
}

static int
10019
qemuNodeDeviceReAttach(virNodeDevicePtr dev)
10020
{
10021
    virQEMUDriverPtr driver = dev->conn->privateData;
10022 10023
    virPCIDevicePtr pci;
    virPCIDevicePtr other;
10024 10025 10026
    unsigned domain, bus, slot, function;
    int ret = -1;

10027
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
10028 10029
        return -1;

10030
    pci = virPCIDeviceNew(domain, bus, slot, function);
10031 10032 10033
    if (!pci)
        return -1;

10034 10035
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
10036
    other = virPCIDeviceListFind(driver->activePciHostdevs, pci);
10037
    if (other) {
10038
        const char *other_name = virPCIDeviceGetUsedBy(other);
10039 10040

        if (other_name)
10041 10042
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use by domain %s"),
10043
                           virPCIDeviceGetName(pci), other_name);
10044
        else
10045 10046
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use"),
10047
                           virPCIDeviceGetName(pci));
10048
        goto out;
10049 10050
    }

10051
    virPCIDeviceReattachInit(pci);
10052

10053 10054
    if (virPCIDeviceReattach(pci, driver->activePciHostdevs,
                             driver->inactivePciHostdevs, "pci-stub") < 0)
10055 10056 10057 10058
        goto out;

    ret = 0;
out:
10059 10060
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
10061
    virPCIDeviceFree(pci);
10062 10063 10064 10065
    return ret;
}

static int
10066
qemuNodeDeviceReset(virNodeDevicePtr dev)
10067
{
10068
    virQEMUDriverPtr driver = dev->conn->privateData;
10069
    virPCIDevicePtr pci;
10070 10071 10072
    unsigned domain, bus, slot, function;
    int ret = -1;

10073
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
10074 10075
        return -1;

10076
    pci = virPCIDeviceNew(domain, bus, slot, function);
10077 10078 10079
    if (!pci)
        return -1;

10080 10081
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
10082

10083 10084
    if (virPCIDeviceReset(pci, driver->activePciHostdevs,
                          driver->inactivePciHostdevs) < 0)
10085 10086 10087 10088
        goto out;

    ret = 0;
out:
10089 10090
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
10091
    virPCIDeviceFree(pci);
10092 10093 10094
    return ret;
}

10095 10096 10097
static int
qemuCPUCompare(virConnectPtr conn,
               const char *xmlDesc,
E
Eric Blake 已提交
10098
               unsigned int flags)
10099
{
10100
    virQEMUDriverPtr driver = conn->privateData;
10101
    int ret = VIR_CPU_COMPARE_ERROR;
10102
    virCapsPtr caps = NULL;
10103

E
Eric Blake 已提交
10104 10105
    virCheckFlags(0, VIR_CPU_COMPARE_ERROR);

10106 10107 10108 10109 10110
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!caps->host.cpu ||
        !caps->host.cpu->model) {
10111 10112
        VIR_WARN("cannot get host CPU capabilities");
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
E
Eric Blake 已提交
10113
    } else {
10114
        ret = cpuCompareXML(caps->host.cpu, xmlDesc);
E
Eric Blake 已提交
10115
    }
10116

10117 10118
cleanup:
    virObjectUnref(caps);
10119 10120 10121
    return ret;
}

10122

10123 10124 10125 10126
static char *
qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED,
                const char **xmlCPUs,
                unsigned int ncpus,
E
Eric Blake 已提交
10127
                unsigned int flags)
10128 10129 10130
{
    char *cpu;

E
Eric Blake 已提交
10131 10132
    virCheckFlags(0, NULL);

10133 10134 10135 10136 10137
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0);

    return cpu;
}

10138 10139 10140 10141 10142 10143 10144

static int qemuDomainGetJobInfo(virDomainPtr dom,
                                virDomainJobInfoPtr info) {
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

10145
    if (!(vm = qemuDomObjFromDomain(dom)))
10146 10147 10148 10149 10150
        goto cleanup;

    priv = vm->privateData;

    if (virDomainObjIsActive(vm)) {
10151
        if (priv->job.asyncJob && !priv->job.dump_memory_only) {
10152
            memcpy(info, &priv->job.info, sizeof(*info));
10153 10154 10155 10156 10157 10158

            /* 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
             */
10159
            if (virTimeMillisNow(&info->timeElapsed) < 0)
10160
                goto cleanup;
10161
            info->timeElapsed -= priv->job.start;
10162 10163 10164 10165 10166
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
10167 10168
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10169 10170 10171 10172 10173 10174 10175
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
10176
        virObjectUnlock(vm);
10177 10178 10179 10180
    return ret;
}


10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320
static int
qemuDomainGetJobStats(virDomainPtr dom,
                      int *type,
                      virTypedParameterPtr *params,
                      int *nparams,
                      unsigned int flags)
{
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    virTypedParameterPtr par = NULL;
    int maxpar = 0;
    int npar = 0;
    int ret = -1;

    virCheckFlags(0, -1);

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

    priv = vm->privateData;

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

    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
        *type = VIR_DOMAIN_JOB_NONE;
        *params = NULL;
        *nparams = 0;
        ret = 0;
        goto cleanup;
    }

    /* Refresh elapsed time again just to ensure it
     * is fully updated. This is primarily for benefit
     * of incoming migration which we don't currently
     * monitor actively in the background thread
     */
    if (virTimeMillisNow(&priv->job.info.timeElapsed) < 0)
        goto cleanup;
    priv->job.info.timeElapsed -= priv->job.start;

    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_TIME_ELAPSED,
                                priv->job.info.timeElapsed) < 0)
        goto cleanup;

    if (priv->job.info.type == VIR_DOMAIN_JOB_BOUNDED &&
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_TIME_REMAINING,
                                priv->job.info.timeRemaining) < 0)
        goto cleanup;

    if (priv->job.status.downtime_set &&
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DOWNTIME,
                                priv->job.status.downtime) < 0)
        goto cleanup;

    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DATA_TOTAL,
                                priv->job.info.dataTotal) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DATA_PROCESSED,
                                priv->job.info.dataProcessed) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DATA_REMAINING,
                                priv->job.info.dataRemaining) < 0)
        goto cleanup;

    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_MEMORY_TOTAL,
                                priv->job.info.memTotal) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_MEMORY_PROCESSED,
                                priv->job.info.memProcessed) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_MEMORY_REMAINING,
                                priv->job.info.memRemaining) < 0)
        goto cleanup;

    if (priv->job.status.ram_duplicate_set) {
        if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_MEMORY_CONSTANT,
                                    priv->job.status.ram_duplicate) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_MEMORY_NORMAL,
                                    priv->job.status.ram_normal) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
                                    priv->job.status.ram_normal_bytes) < 0)
            goto cleanup;
    }

    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DISK_TOTAL,
                                priv->job.info.fileTotal) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DISK_PROCESSED,
                                priv->job.info.fileProcessed) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DISK_REMAINING,
                                priv->job.info.fileRemaining) < 0)
        goto cleanup;

    if (priv->job.status.xbzrle_set) {
        if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_CACHE,
                                    priv->job.status.xbzrle_cache_size) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_BYTES,
                                    priv->job.status.xbzrle_bytes) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_PAGES,
                                    priv->job.status.xbzrle_pages) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
                                    priv->job.status.xbzrle_cache_miss) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
                                    priv->job.status.xbzrle_overflow) < 0)
            goto cleanup;
    }

    *type = priv->job.info.type;
    *params = par;
    *nparams = npar;
    ret = 0;

cleanup:
    if (vm)
        virObjectUnlock(vm);
    if (ret < 0)
        virTypedParamsFree(par, npar);
    return ret;
}


10321
static int qemuDomainAbortJob(virDomainPtr dom) {
10322
    virQEMUDriverPtr driver = dom->conn->privateData;
10323 10324 10325 10326
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

10327
    if (!(vm = qemuDomObjFromDomain(dom)))
10328 10329
        goto cleanup;

10330 10331
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
10332

10333
    if (!virDomainObjIsActive(vm)) {
10334 10335
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10336
        goto endjob;
10337 10338
    }

10339 10340
    priv = vm->privateData;

10341
    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
10342 10343
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no job is active on the domain"));
10344 10345
        goto endjob;
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
10346 10347 10348
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot abort incoming migration;"
                         " use virDomainDestroy instead"));
10349 10350 10351 10352
        goto endjob;
    }

    VIR_DEBUG("Cancelling job at client request");
10353
    qemuDomainObjAbortAsyncJob(vm);
10354
    qemuDomainObjEnterMonitor(driver, vm);
10355 10356 10357 10358 10359 10360
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

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

cleanup:
    if (vm)
10364
        virObjectUnlock(vm);
10365 10366 10367 10368
    return ret;
}


10369 10370 10371 10372 10373
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
10374
    virQEMUDriverPtr driver = dom->conn->privateData;
10375 10376 10377 10378
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

10379
    virCheckFlags(0, -1);
10380

10381 10382
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
10383

10384 10385 10386
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

10387
    if (!virDomainObjIsActive(vm)) {
10388 10389
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10390
        goto endjob;
10391 10392 10393 10394
    }

    priv = vm->privateData;

10395
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
10396 10397
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not being migrated"));
10398
        goto endjob;
10399 10400
    }

10401
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
10402
    qemuDomainObjEnterMonitor(driver, vm);
10403 10404 10405 10406 10407 10408
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

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

cleanup:
    if (vm)
10412
        virObjectUnlock(vm);
10413 10414 10415
    return ret;
}

10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520
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;

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

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

    priv = vm->privateData;

    qemuDomainObjEnterMonitor(driver, vm);

    ret = qemuMonitorGetMigrationCapability(
                priv->mon,
                QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);
    if (ret == 0) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Compressed migration is not supported by "
                         "QEMU binary"));
        ret = -1;
    } else if (ret > 0) {
        ret = qemuMonitorGetMigrationCacheSize(priv->mon, cacheSize);
    }

    qemuDomainObjExitMonitor(driver, vm);

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

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

static int
qemuDomainMigrateSetCompressionCache(virDomainPtr dom,
                                     unsigned long long cacheSize,
                                     unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

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

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

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

    priv = vm->privateData;

    qemuDomainObjEnterMonitor(driver, vm);

    ret = qemuMonitorGetMigrationCapability(
                priv->mon,
                QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);
    if (ret == 0) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Compressed migration is not supported by "
                         "QEMU binary"));
        ret = -1;
    } else if (ret > 0) {
        VIR_DEBUG("Setting compression cache to %llu B", cacheSize);
        ret = qemuMonitorSetMigrationCacheSize(priv->mon, cacheSize);
    }

    qemuDomainObjExitMonitor(driver, vm);

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

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

10521 10522 10523 10524 10525
static int
qemuDomainMigrateSetMaxSpeed(virDomainPtr dom,
                             unsigned long bandwidth,
                             unsigned int flags)
{
10526
    virQEMUDriverPtr driver = dom->conn->privateData;
10527 10528 10529 10530 10531 10532
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

10533 10534
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
10535 10536

    priv = vm->privateData;
10537 10538 10539
    if (virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
            goto cleanup;
10540

10541
        if (!virDomainObjIsActive(vm)) {
10542 10543
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is not running"));
10544 10545 10546
            goto endjob;
        }

10547 10548 10549 10550
        VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
        qemuDomainObjExitMonitor(driver, vm);
10551

10552 10553
        if (ret == 0)
            priv->migMaxBandwidth = bandwidth;
10554

10555
endjob:
10556 10557 10558 10559 10560 10561
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    } else {
        priv->migMaxBandwidth = bandwidth;
        ret = 0;
    }
10562 10563 10564

cleanup:
    if (vm)
10565
        virObjectUnlock(vm);
10566 10567 10568
    return ret;
}

10569 10570 10571 10572 10573 10574
static int
qemuDomainMigrateGetMaxSpeed(virDomainPtr dom,
                             unsigned long *bandwidth,
                             unsigned int flags)
{
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
10575
    qemuDomainObjPrivatePtr priv;
10576 10577 10578 10579
    int ret = -1;

    virCheckFlags(0, -1);

10580
    if (!(vm = qemuDomObjFromDomain(dom)))
10581 10582
        goto cleanup;

J
Jim Fehlig 已提交
10583 10584
    priv = vm->privateData;
    *bandwidth = priv->migMaxBandwidth;
10585 10586 10587 10588
    ret = 0;

cleanup:
    if (vm)
10589
        virObjectUnlock(vm);
10590 10591 10592
    return ret;
}

10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604
typedef enum {
    VIR_DISK_CHAIN_NO_ACCESS,
    VIR_DISK_CHAIN_READ_ONLY,
    VIR_DISK_CHAIN_READ_WRITE,
} qemuDomainDiskChainMode;

/* Several operations end up adding or removing a single element of a
 * disk backing file chain; this helper function ensures that the lock
 * manager, cgroup device controller, and security manager labelling
 * are all aware of each new file before it is added to a chain, and
 * can revoke access to a file no longer needed in a chain.  */
static int
10605
qemuDomainPrepareDiskChainElement(virQEMUDriverPtr driver,
10606 10607 10608
                                  virDomainObjPtr vm,
                                  virCgroupPtr cgroup,
                                  virDomainDiskDefPtr disk,
10609
                                  const char *file,
10610 10611 10612 10613 10614 10615 10616 10617 10618 10619
                                  qemuDomainDiskChainMode mode)
{
    /* The easiest way to label a single file with the same
     * permissions it would have as if part of the disk chain is to
     * temporarily modify the disk in place.  */
    char *origsrc = disk->src;
    int origformat = disk->format;
    virStorageFileMetadataPtr origchain = disk->backingChain;
    bool origreadonly = disk->readonly;
    int ret = -1;
10620
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
10621

10622
    disk->src = (char *) file; /* casting away const is safe here */
10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634
    disk->format = VIR_STORAGE_FILE_RAW;
    disk->backingChain = NULL;
    disk->readonly = mode == VIR_DISK_CHAIN_READ_ONLY;

    if (mode == VIR_DISK_CHAIN_NO_ACCESS) {
        if (virSecurityManagerRestoreImageLabel(driver->securityManager,
                                                vm->def, disk) < 0)
            VIR_WARN("Unable to restore security label on %s", disk->src);
        if (cgroup && qemuTeardownDiskCgroup(vm, cgroup, disk) < 0)
            VIR_WARN("Failed to teardown cgroup for disk path %s", disk->src);
        if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
            VIR_WARN("Unable to release lock on %s", disk->src);
10635
    } else if (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649
                                       vm, disk) < 0 ||
               (cgroup && qemuSetupDiskCgroup(vm, cgroup, disk) < 0) ||
               virSecurityManagerSetImageLabel(driver->securityManager,
                                               vm->def, disk) < 0) {
        goto cleanup;
    }

    ret = 0;

cleanup:
    disk->src = origsrc;
    disk->format = origformat;
    disk->backingChain = origchain;
    disk->readonly = origreadonly;
10650
    virObjectUnref(cfg);
10651 10652 10653 10654
    return ret;
}


10655
static int
10656
qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) {
10657 10658 10659 10660
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int freezed;

    if (priv->agentError) {
10661
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
10662 10663
                       _("QEMU guest agent is not "
                         "available due to an error"));
10664 10665 10666
        return -1;
    }
    if (!priv->agent) {
10667 10668
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
10669 10670 10671
        return -1;
    }

10672
    qemuDomainObjEnterAgent(vm);
10673
    freezed = qemuAgentFSFreeze(priv->agent);
10674
    qemuDomainObjExitAgent(vm);
10675 10676 10677 10678 10679

    return freezed;
}

static int
10680
qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report)
E
Eric Blake 已提交
10681
{
10682 10683
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int thawed;
E
Eric Blake 已提交
10684
    virErrorPtr err = NULL;
10685 10686

    if (priv->agentError) {
E
Eric Blake 已提交
10687
        if (report)
10688
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
10689 10690
                           _("QEMU guest agent is not "
                             "available due to an error"));
10691 10692 10693
        return -1;
    }
    if (!priv->agent) {
E
Eric Blake 已提交
10694
        if (report)
10695 10696
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
10697 10698 10699
        return -1;
    }

10700
    qemuDomainObjEnterAgent(vm);
E
Eric Blake 已提交
10701
    if (!report)
10702
        err = virSaveLastError();
10703
    thawed = qemuAgentFSThaw(priv->agent);
10704 10705
    if (!report)
        virSetError(err);
10706
    qemuDomainObjExitAgent(vm);
10707

10708
    virFreeError(err);
10709 10710 10711
    return thawed;
}

10712 10713
/* The domain is expected to be locked and inactive. */
static int
10714
qemuDomainSnapshotCreateInactiveInternal(virQEMUDriverPtr driver,
10715 10716
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap)
10717
{
E
Eric Blake 已提交
10718
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
10719 10720
}

10721 10722
/* The domain is expected to be locked and inactive. */
static int
10723
qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
10724 10725 10726 10727 10728 10729 10730 10731 10732
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap,
                                         bool reuse)
{
    int i;
    virDomainSnapshotDiskDefPtr snapdisk;
    virDomainDiskDefPtr defdisk;
    virCommandPtr cmd = NULL;
    const char *qemuImgPath;
10733 10734
    virBitmapPtr created = NULL;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
10735 10736 10737
    int ret = -1;

    if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
10738
        goto cleanup;
10739 10740 10741

    if (!(created = virBitmapNew(snap->def->ndisks))) {
        virReportOOMError();
10742
        goto cleanup;
10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771
    }

    /* If reuse is true, then qemuDomainSnapshotPrepare already
     * ensured that the new files exist, and it was up to the user to
     * create them correctly.  */
    for (i = 0; i < snap->def->ndisks && !reuse; i++) {
        snapdisk = &(snap->def->disks[i]);
        defdisk = snap->def->dom->disks[snapdisk->index];
        if (snapdisk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
            continue;

        if (!snapdisk->format)
            snapdisk->format = VIR_STORAGE_FILE_QCOW2;

        /* creates cmd line args: qemu-img create -f qcow2 -o */
        if (!(cmd = virCommandNewArgList(qemuImgPath,
                                         "create",
                                         "-f",
                                         virStorageFileFormatTypeToString(snapdisk->format),
                                         "-o",
                                         NULL)))
            goto cleanup;

        if (defdisk->format > 0) {
            /* adds cmd line arg: backing_file=/path/to/backing/file,backing_fmd=format */
            virCommandAddArgFormat(cmd, "backing_file=%s,backing_fmt=%s",
                                   defdisk->src,
                                   virStorageFileFormatTypeToString(defdisk->format));
        } else {
10772
            if (!cfg->allowDiskFormatProbing) {
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 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown image format of '%s' and "
                                 "format probing is disabled"),
                               defdisk->src);
                goto cleanup;
            }

            /* adds cmd line arg: backing_file=/path/to/backing/file */
            virCommandAddArgFormat(cmd, "backing_file=%s", defdisk->src);
        }

        /* adds cmd line args: /path/to/target/file */
        virCommandAddArg(cmd, snapdisk->file);

        /* If the target does not exist, we're going to create it possibly */
        if (!virFileExists(snapdisk->file))
            ignore_value(virBitmapSetBit(created, i));

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;

        virCommandFree(cmd);
        cmd = NULL;
    }

    /* update disk definitions */
    for (i = 0; i < snap->def->ndisks; i++) {
        snapdisk = &(snap->def->disks[i]);
        defdisk = vm->def->disks[snapdisk->index];

        if (snapdisk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            VIR_FREE(defdisk->src);
            if (!(defdisk->src = strdup(snapdisk->file))) {
                /* we cannot rollback here in a sane way */
                virReportOOMError();
                goto cleanup;
            }
            defdisk->format = snapdisk->format;
        }
    }

    ret = 0;

cleanup:
    virCommandFree(cmd);

    /* unlink images if creation has failed */
10820
    if (ret < 0 && created) {
10821 10822 10823 10824 10825 10826 10827 10828 10829
        ssize_t bit = -1;
        while ((bit = virBitmapNextSetBit(created, bit)) >= 0) {
            snapdisk = &(snap->def->disks[bit]);
            if (unlink(snapdisk->file) < 0)
                VIR_WARN("Failed to remove snapshot image '%s'",
                         snapdisk->file);
        }
    }
    virBitmapFree(created);
10830
    virObjectUnref(cfg);
10831 10832 10833 10834

    return ret;
}

10835

10836 10837
/* The domain is expected to be locked and active. */
static int
10838
qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
10839
                                       virQEMUDriverPtr driver,
10840 10841 10842
                                       virDomainObjPtr *vmptr,
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
10843 10844 10845
{
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
10846
    virDomainEventPtr event = NULL;
10847 10848
    bool resume = false;
    int ret = -1;
10849

10850
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
10851 10852
        return -1;

10853
    if (!virDomainObjIsActive(vm)) {
10854 10855
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10856 10857 10858
        goto endjob;
    }

J
Jiri Denemark 已提交
10859
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
10860 10861 10862 10863
        /* 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.
         */
10864 10865
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
10866 10867 10868 10869
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
10870 10871
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
10872 10873 10874 10875
            goto cleanup;
        }
    }

10876
    qemuDomainObjEnterMonitor(driver, vm);
10877
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
10878
    qemuDomainObjExitMonitor(driver, vm);
10879 10880 10881 10882 10883 10884
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
10885
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
10886 10887 10888 10889 10890 10891 10892
        virDomainAuditStop(vm, "from-snapshot");
        /* We already filtered the _HALT flag for persistent domains
         * only, so this end job never drops the last reference.  */
        ignore_value(qemuDomainObjEndJob(driver, vm));
        resume = false;
        vm = NULL;
    }
10893

10894 10895
cleanup:
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
10896
        qemuProcessStartCPUs(driver, vm, conn,
10897
                             VIR_DOMAIN_RUNNING_UNPAUSED,
10898 10899 10900 10901 10902 10903 10904 10905
                             QEMU_ASYNC_JOB_NONE) < 0) {
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after snapshot failed"));
        }
10906 10907
    }

10908
endjob:
10909
    if (vm && qemuDomainObjEndJob(driver, vm) == 0) {
10910 10911
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
10912
        *vmptr = NULL;
10913 10914
        ret = -1;
    }
10915

10916 10917 10918
    if (event)
        qemuDomainEventQueue(driver, event);

10919 10920 10921
    return ret;
}

10922
static int
E
Eric Blake 已提交
10923 10924
qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
                          unsigned int *flags)
10925 10926 10927 10928 10929
{
    int ret = -1;
    int i;
    bool active = virDomainObjIsActive(vm);
    struct stat st;
10930
    bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
10931
    bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
10932
    bool found_internal = false;
10933 10934
    int external = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
10935

E
Eric Blake 已提交
10936
    if (def->state == VIR_DOMAIN_DISK_SNAPSHOT &&
10937
        reuse && !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
10938 10939
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("reuse is not supported with this QEMU binary"));
10940 10941 10942
        goto cleanup;
    }

10943 10944
    for (i = 0; i < def->ndisks; i++) {
        virDomainSnapshotDiskDefPtr disk = &def->disks[i];
E
Eric Blake 已提交
10945
        virDomainDiskDefPtr dom_disk = vm->def->disks[i];
10946 10947

        switch (disk->snapshot) {
E
Eric Blake 已提交
10948
        case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
E
Eric Blake 已提交
10949 10950 10951 10952 10953
            if (def->state != VIR_DOMAIN_DISK_SNAPSHOT &&
                dom_disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
                (dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG ||
                 dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD)) {
                break;
10954
            }
10955 10956
            if (vm->def->disks[i]->format > 0 &&
                vm->def->disks[i]->format != VIR_STORAGE_FILE_QCOW2) {
10957 10958 10959 10960
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("internal snapshot for disk %s unsupported "
                                 "for storage type %s"),
                               disk->name,
10961 10962
                               virStorageFileFormatTypeToString(
                                   vm->def->disks[i]->format));
10963 10964
                goto cleanup;
            }
E
Eric Blake 已提交
10965 10966 10967 10968 10969 10970 10971
            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;
            }
10972
            found_internal = true;
10973 10974
            break;

E
Eric Blake 已提交
10975
        case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
10976 10977 10978 10979
            if (!disk->format) {
                disk->format = VIR_STORAGE_FILE_QCOW2;
            } else if (disk->format != VIR_STORAGE_FILE_QCOW2 &&
                       disk->format != VIR_STORAGE_FILE_QED) {
10980 10981 10982
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot format for disk %s "
                                 "is unsupported: %s"),
10983 10984
                               disk->name,
                               virStorageFileFormatTypeToString(disk->format));
10985 10986 10987 10988 10989 10990 10991 10992
                goto cleanup;
            }
            if (stat(disk->file, &st) < 0) {
                if (errno != ENOENT) {
                    virReportSystemError(errno,
                                         _("unable to stat for disk %s: %s"),
                                         disk->name, disk->file);
                    goto cleanup;
10993 10994 10995 10996 10997
                } else if (reuse) {
                    virReportSystemError(errno,
                                         _("missing existing file for disk %s: %s"),
                                         disk->name, disk->file);
                    goto cleanup;
10998
                }
10999
            } else if (!S_ISBLK(st.st_mode) && st.st_size && !reuse) {
11000 11001 11002 11003
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot file for disk %s already "
                                 "exists and is not a block device: %s"),
                               disk->name, disk->file);
11004 11005
                goto cleanup;
            }
11006
            external++;
11007 11008
            break;

E
Eric Blake 已提交
11009
        case VIR_DOMAIN_SNAPSHOT_LOCATION_NONE:
11010 11011
            break;

E
Eric Blake 已提交
11012
        case VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT:
11013
        default:
11014 11015
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unexpected code path"));
11016 11017 11018 11019
            goto cleanup;
        }
    }

11020 11021 11022
    /* internal snapshot requires a disk image to store the memory image to */
    if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL &&
        !found_internal) {
11023
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
11024
                       _("internal checkpoints require at least "
11025
                         "one disk to be selected for snapshot"));
11026 11027
        goto cleanup;
    }
11028

11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050
    /* disk snapshot requires at least one disk */
    if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && !external) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk-only snapshots require at least "
                         "one disk to be selected for snapshot"));
        goto cleanup;
    }

    /* For now, we don't allow mixing internal and external disks.
     * XXX technically, we could mix internal and external disks for
     * offline snapshots */
    if (found_internal && external) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("mixing internal and external snapshots is not "
                         "supported yet"));
        goto cleanup;
    }

    /* Alter flags to let later users know what we learned.  */
    if (external && !active)
        *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;

E
Eric Blake 已提交
11051
    if (def->state != VIR_DOMAIN_DISK_SNAPSHOT && active) {
11052
        if (external == 1 ||
11053
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
11054 11055
            *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC;
        } else if (atomic && external > 1) {
11056 11057 11058
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("atomic live snapshot of multiple disks "
                             "is unsupported"));
11059 11060 11061
            goto cleanup;
        }
    }
11062 11063 11064 11065 11066 11067 11068 11069 11070

    ret = 0;

cleanup:
    return ret;
}

/* The domain is expected to hold monitor lock.  */
static int
11071
qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
11072
                                         virDomainObjPtr vm,
11073
                                         virCgroupPtr cgroup,
11074
                                         virDomainSnapshotDiskDefPtr snap,
11075
                                         virDomainDiskDefPtr disk,
11076
                                         virDomainDiskDefPtr persistDisk,
11077 11078
                                         virJSONValuePtr actions,
                                         bool reuse)
11079 11080 11081 11082
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *device = NULL;
    char *source = NULL;
11083 11084
    int format = snap->format;
    const char *formatStr = NULL;
11085
    char *persistSource = NULL;
11086
    int ret = -1;
11087 11088
    int fd = -1;
    bool need_unlink = false;
11089

E
Eric Blake 已提交
11090
    if (snap->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
11091 11092
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected code path"));
11093 11094 11095 11096 11097
        return -1;
    }

    if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
        !(source = strdup(snap->file)) ||
11098
        (persistDisk &&
11099
         !(persistSource = strdup(source)))) {
11100 11101 11102 11103
        virReportOOMError();
        goto cleanup;
    }

11104 11105
    /* create the stub file and set selinux labels; manipulate disk in
     * place, in a way that can be reverted on failure. */
11106 11107 11108 11109 11110 11111 11112
    if (!reuse) {
        fd = qemuOpenFile(driver, source, O_WRONLY | O_TRUNC | O_CREAT,
                          &need_unlink, NULL);
        if (fd < 0)
            goto cleanup;
        VIR_FORCE_CLOSE(fd);
    }
11113

11114 11115 11116 11117 11118 11119 11120 11121
    /* XXX Here, we know we are about to alter disk->backingChain if
     * successful, so we nuke the existing chain so that future
     * commands will recompute it.  Better would be storing the chain
     * ourselves rather than reprobing, but this requires modifying
     * domain_conf and our XML to fully track the chain across
     * libvirtd restarts.  */
    virStorageFileFreeMetadata(disk->backingChain);
    disk->backingChain = NULL;
11122

11123 11124 11125 11126
    if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, source,
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, source,
                                          VIR_DISK_CHAIN_NO_ACCESS);
11127 11128 11129 11130
        goto cleanup;
    }

    /* create the actual snapshot */
11131 11132
    if (snap->format)
        formatStr = virStorageFileFormatTypeToString(snap->format);
11133
    ret = qemuMonitorDiskSnapshot(priv->mon, actions, device, source,
11134
                                  formatStr, reuse);
11135 11136 11137 11138 11139
    virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
    if (ret < 0)
        goto cleanup;

    /* Update vm in place to match changes.  */
11140
    need_unlink = false;
11141 11142 11143
    VIR_FREE(disk->src);
    disk->src = source;
    source = NULL;
11144
    disk->format = format;
11145 11146 11147 11148
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
11149
        persistDisk->format = format;
11150
    }
11151 11152

cleanup:
11153 11154
    if (need_unlink && unlink(source))
        VIR_WARN("unable to unlink just-created %s", source);
11155 11156
    VIR_FREE(device);
    VIR_FREE(source);
11157
    VIR_FREE(persistSource);
11158 11159 11160
    return ret;
}

11161 11162 11163 11164
/* The domain is expected to hold monitor lock.  This is the
 * counterpart to qemuDomainSnapshotCreateSingleDiskActive, called
 * only on a failed transaction. */
static void
11165
qemuDomainSnapshotUndoSingleDiskActive(virQEMUDriverPtr driver,
11166
                                       virDomainObjPtr vm,
11167
                                       virCgroupPtr cgroup,
11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178
                                       virDomainDiskDefPtr origdisk,
                                       virDomainDiskDefPtr disk,
                                       virDomainDiskDefPtr persistDisk,
                                       bool need_unlink)
{
    char *source = NULL;
    char *persistSource = NULL;
    struct stat st;

    if (!(source = strdup(origdisk->src)) ||
        (persistDisk &&
11179
         !(persistSource = strdup(source)))) {
11180 11181 11182 11183
        virReportOOMError();
        goto cleanup;
    }

11184 11185
    qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, origdisk->src,
                                      VIR_DISK_CHAIN_NO_ACCESS);
11186
    if (need_unlink && stat(disk->src, &st) == 0 &&
11187
        S_ISREG(st.st_mode) && unlink(disk->src) < 0)
11188 11189 11190 11191 11192 11193
        VIR_WARN("Unable to remove just-created %s", disk->src);

    /* Update vm in place to match changes.  */
    VIR_FREE(disk->src);
    disk->src = source;
    source = NULL;
11194
    disk->format = origdisk->format;
11195 11196 11197 11198
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
11199
        persistDisk->format = origdisk->format;
11200 11201 11202 11203 11204 11205 11206
    }

cleanup:
    VIR_FREE(source);
    VIR_FREE(persistSource);
}

11207 11208
/* The domain is expected to be locked and active. */
static int
11209
qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
11210
                                   virDomainObjPtr vm,
11211
                                   virDomainSnapshotObjPtr snap,
11212 11213
                                   unsigned int flags,
                                   enum qemuDomainAsyncJob asyncJob)
11214
{
11215 11216
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virJSONValuePtr actions = NULL;
11217 11218
    int ret = -1;
    int i;
11219
    bool persist = false;
11220
    bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
11221
    virCgroupPtr cgroup = NULL;
11222
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
11223

11224
    if (!virDomainObjIsActive(vm)) {
11225 11226
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11227
        goto cleanup;
11228 11229
    }

11230 11231
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
11232 11233 11234
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
11235
        goto cleanup;
11236 11237 11238
    }
    /* 'cgroup' is still NULL if cgroups are disabled.  */

11239
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
11240
        if (!(actions = virJSONValueNewArray())) {
11241 11242 11243
            virReportOOMError();
            goto cleanup;
        }
11244
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DISK_SNAPSHOT)) {
11245 11246 11247 11248
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live disk snapshot not supported with this "
                         "QEMU binary"));
        goto cleanup;
11249
    }
11250 11251

    /* No way to roll back if first disk succeeds but later disks
11252
     * fail, unless we have transaction support.
E
Eric Blake 已提交
11253
     * Based on earlier qemuDomainSnapshotPrepare, all
11254 11255
     * disks in this list are now either SNAPSHOT_NO, or
     * SNAPSHOT_EXTERNAL with a valid file name and qcow2 format.  */
11256 11257 11258
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;

11259
    for (i = 0; i < snap->def->ndisks; i++) {
11260 11261
        virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
11262
        if (snap->def->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
11263
            continue;
11264 11265 11266 11267 11268 11269 11270 11271 11272
        if (vm->newDef) {
            int indx = virDomainDiskIndexByName(vm->newDef,
                                                vm->def->disks[i]->dst,
                                                false);
            if (indx >= 0) {
                persistDisk = vm->newDef->disks[indx];
                persist = true;
            }
        }
11273

11274
        ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm, cgroup,
11275
                                                       &snap->def->disks[i],
11276
                                                       vm->def->disks[i],
11277 11278
                                                       persistDisk, actions,
                                                       reuse);
11279 11280 11281
        if (ret < 0)
            break;
    }
11282 11283 11284
    if (actions) {
        if (ret == 0)
            ret = qemuMonitorTransaction(priv->mon, actions);
E
Eric Blake 已提交
11285
        virJSONValueFree(actions);
11286 11287 11288 11289 11290 11291
        if (ret < 0) {
            /* Transaction failed; undo the changes to vm.  */
            bool need_unlink = !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);
            while (--i >= 0) {
                virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
11292 11293
                if (snap->def->disks[i].snapshot ==
                    VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
11294 11295 11296 11297 11298 11299 11300 11301 11302
                    continue;
                if (vm->newDef) {
                    int indx = virDomainDiskIndexByName(vm->newDef,
                                                        vm->def->disks[i]->dst,
                                                        false);
                    if (indx >= 0)
                        persistDisk = vm->newDef->disks[indx];
                }

11303
                qemuDomainSnapshotUndoSingleDiskActive(driver, vm, cgroup,
11304 11305 11306 11307 11308 11309 11310
                                                       snap->def->dom->disks[i],
                                                       vm->def->disks[i],
                                                       persistDisk,
                                                       need_unlink);
            }
        }
    }
11311
    qemuDomainObjExitMonitor(driver, vm);
11312 11313 11314 11315

cleanup:
    virCgroupFree(&cgroup);

11316
    if (ret == 0 || !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
11317
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0 ||
11318
            (persist && virDomainSaveConfig(cfg->configDir, vm->newDef) < 0))
11319 11320
            ret = -1;
    }
11321
    virObjectUnref(cfg);
11322 11323 11324 11325 11326 11327 11328

    return ret;
}


static int
qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
11329
                                       virQEMUDriverPtr driver,
11330 11331 11332 11333 11334 11335 11336 11337 11338 11339
                                       virDomainObjPtr *vmptr,
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
{
    bool resume = false;
    int ret = -1;
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *xml = NULL;
    bool memory = snap->def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
11340
    bool memory_unlink = false;
11341
    bool atomic = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC);
11342
    bool transaction = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION);
11343
    int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
11344
    bool pmsuspended = false;
11345

11346
    if (qemuDomainObjBeginAsyncJob(driver, vm,
11347
                                             QEMU_ASYNC_JOB_SNAPSHOT) < 0)
11348 11349
        goto cleanup;

11350 11351 11352 11353 11354
    /* If quiesce was requested, then issue a freeze command, and a
     * counterpart thaw command, no matter what.  The command will
     * fail if the guest is paused or the guest agent is not
     * running.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) {
11355
        if (qemuDomainSnapshotFSFreeze(vm) < 0) {
11356 11357 11358 11359 11360 11361 11362 11363
            /* helper reported the error */
            thaw = -1;
            goto endjob;
        } else {
            thaw = 1;
        }
    }

11364 11365 11366 11367 11368
    /* 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) {
11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397
        resume = true;

        /* For external checkpoints (those with memory), the guest
         * must pause (either by libvirt up front, or by qemu after
         * _LIVE converges).  For disk-only snapshots with multiple
         * disks, libvirt must pause externally to get all snapshots
         * to be at the same point in time, unless qemu supports
         * transactions.  For a single disk, snapshot is atomic
         * without requiring a pause.  Thanks to
         * qemuDomainSnapshotPrepare, if we got to this point, the
         * atomic flag now says whether we need to pause, and a
         * capability bit says whether to use transaction.
         */
        if ((memory && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_LIVE)) ||
            (!memory && atomic && !transaction)) {
            if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SNAPSHOT,
                                    QEMU_ASYNC_JOB_SNAPSHOT) < 0)
                goto endjob;

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

    /* do the memory snapshot if necessary */
    if (memory) {
11398 11399 11400 11401
        /* check if migration is possible */
        if (!qemuMigrationIsAllowed(driver, vm, vm->def, false))
            goto endjob;

11402 11403 11404 11405 11406 11407 11408 11409 11410
        /* allow the migration job to be cancelled or the domain to be paused */
        qemuDomainObjSetAsyncJobMask(vm, DEFAULT_JOB_MASK |
                                     JOB_MASK(QEMU_JOB_SUSPEND) |
                                     JOB_MASK(QEMU_JOB_MIGRATION_OP));

        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, false)))
            goto endjob;

        if ((ret = qemuDomainSaveMemory(driver, vm, snap->def->file,
11411
                                        xml, QEMU_SAVE_FORMAT_RAW,
11412 11413 11414 11415
                                        resume, 0,
                                        QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
            goto endjob;

11416 11417 11418
        /* the memory image was created, remove it on errors */
        memory_unlink = true;

11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434
        /* forbid any further manipulation */
        qemuDomainObjSetAsyncJobMask(vm, DEFAULT_JOB_MASK);
    }

    /* now the domain is now paused if:
     * - if a memory snapshot was requested
     * - an atomic snapshot was requested AND
     *   qemu does not support transactions
     *
     * Next we snapshot the disks.
     */
    if ((ret = qemuDomainSnapshotCreateDiskActive(driver, vm, snap, flags,
                                                  QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
        goto endjob;

    /* the snapshot is complete now */
11435 11436 11437 11438 11439
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        virDomainEventPtr event;

        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
11440
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
11441 11442 11443
        virDomainAuditStop(vm, "from-snapshot");
        /* We already filtered the _HALT flag for persistent domains
         * only, so this end job never drops the last reference.  */
11444
        ignore_value(qemuDomainObjEndAsyncJob(driver, vm));
11445
        resume = false;
E
Eric Blake 已提交
11446
        thaw = 0;
11447 11448 11449
        vm = NULL;
        if (event)
            qemuDomainEventQueue(driver, event);
11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461
    } else if (memory && pmsuspended) {
        /* qemu 1.3 is unable to save a domain in pm-suspended (S3)
         * state; so we must emit an event stating that it was
         * converted to paused.  */
        virDomainEventPtr event;

        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                             VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
        if (event)
            qemuDomainEventQueue(driver, event);
11462 11463
    }

11464
    ret = 0;
11465 11466

endjob:
11467 11468 11469
    if (resume && vm && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
11470
                             QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
11471 11472 11473 11474 11475 11476 11477 11478 11479 11480
        virDomainEventPtr event = NULL;
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (event)
            qemuDomainEventQueue(driver, event);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after snapshot failed"));
        }
11481

11482 11483
        ret = -1;
        goto cleanup;
11484
    }
E
Eric Blake 已提交
11485
    if (vm && thaw != 0 &&
11486
        qemuDomainSnapshotFSThaw(vm, thaw > 0) < 0) {
E
Eric Blake 已提交
11487 11488 11489 11490
        /* helper reported the error, if it was needed */
        if (thaw > 0)
            ret = -1;
    }
11491
    if (vm && !qemuDomainObjEndAsyncJob(driver, vm)) {
11492
        /* Only possible if a transient vm quit while our locks were down,
11493 11494
         * in which case we don't want to save snapshot metadata.
         */
11495 11496
        *vmptr = NULL;
        ret = -1;
11497 11498
    }

11499 11500
cleanup:
    VIR_FREE(xml);
11501 11502
    if (memory_unlink && ret < 0)
        unlink(snap->def->file);
11503

11504 11505 11506
    return ret;
}

11507

11508 11509 11510 11511
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
                            const char *xmlDesc,
                            unsigned int flags)
C
Chris Lalancette 已提交
11512
{
11513
    virQEMUDriverPtr driver = domain->conn->privateData;
C
Chris Lalancette 已提交
11514
    virDomainObjPtr vm = NULL;
11515
    char *xml = NULL;
C
Chris Lalancette 已提交
11516 11517 11518
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
11519
    virDomainSnapshotDefPtr def = NULL;
11520
    bool update_current = true;
11521
    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
11522
    virDomainSnapshotObjPtr other = NULL;
11523 11524
    int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
    int align_match = true;
11525
    virQEMUDriverConfigPtr cfg = NULL;
11526
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
11527

11528 11529
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
11530
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
11531
                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
11532
                  VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
11533
                  VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
11534
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
11535 11536
                  VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
                  VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
11537 11538 11539

    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
        !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
11540 11541
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("quiesce requires disk-only"));
11542 11543
        return NULL;
    }
11544 11545 11546 11547 11548 11549 11550

    if (((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
         !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
        (flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA))
        update_current = false;
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
11551

C
Chris Lalancette 已提交
11552
    virUUIDFormat(domain->uuid, uuidstr);
11553
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
C
Chris Lalancette 已提交
11554
    if (!vm) {
11555 11556
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
11557 11558 11559
        goto cleanup;
    }

11560 11561
    cfg = virQEMUDriverGetConfig(driver);

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

11565
    if (qemuProcessAutoDestroyActive(driver, vm)) {
11566 11567
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is marked for auto destroy"));
11568 11569
        goto cleanup;
    }
E
Eric Blake 已提交
11570 11571 11572 11573 11574 11575
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }

11576
    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
11577 11578
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot halt after transient domain snapshot"));
11579 11580
        goto cleanup;
    }
11581 11582 11583
    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) ||
        !virDomainObjIsActive(vm))
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE;
11584

11585
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, caps, driver->xmlopt,
11586 11587
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
11588 11589
        goto cleanup;

11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607
    /* 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;
        }
11608 11609
    }

11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628
    /* reject the VIR_DOMAIN_SNAPSHOT_CREATE_LIVE flag where not supported */
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_LIVE &&
        (!virDomainObjIsActive(vm) ||
         def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL ||
         flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live snapshot creation is supported only "
                         "with external checkpoints"));
        goto cleanup;
    }
    if ((def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL ||
         def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL) &&
        flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("disk-only snapshot creation is not compatible with "
                         "memory snapshot"));
        goto cleanup;
    }

11629 11630 11631 11632
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* Prevent circular chains */
        if (def->parent) {
            if (STREQ(def->name, def->parent)) {
11633 11634 11635
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot set snapshot %s as its own parent"),
                               def->name);
11636 11637
                goto cleanup;
            }
11638
            other = virDomainSnapshotFindByName(vm->snapshots, def->parent);
11639
            if (!other) {
11640 11641 11642
                virReportError(VIR_ERR_INVALID_ARG,
                               _("parent %s for snapshot %s not found"),
                               def->parent, def->name);
11643 11644 11645 11646
                goto cleanup;
            }
            while (other->def->parent) {
                if (STREQ(other->def->parent, def->name)) {
11647 11648 11649
                    virReportError(VIR_ERR_INVALID_ARG,
                                   _("parent %s would create cycle to %s"),
                                   other->def->name, def->name);
11650 11651
                    goto cleanup;
                }
11652
                other = virDomainSnapshotFindByName(vm->snapshots,
11653 11654 11655 11656 11657 11658 11659 11660 11661 11662
                                                    other->def->parent);
                if (!other) {
                    VIR_WARN("snapshots are inconsistent for %s",
                             vm->def->name);
                    break;
                }
            }
        }

        /* Check that any replacement is compatible */
11663 11664 11665 11666 11667 11668 11669 11670 11671
        if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) &&
            def->state != VIR_DOMAIN_DISK_SNAPSHOT) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("disk-only flag for snapshot %s requires "
                             "disk-snapshot state"),
                           def->name);
            goto cleanup;

        }
11672

11673 11674
        if (def->dom &&
            memcmp(def->dom->uuid, domain->uuid, VIR_UUID_BUFLEN)) {
11675 11676 11677
            virReportError(VIR_ERR_INVALID_ARG,
                           _("definition for snapshot %s must use uuid %s"),
                           def->name, uuidstr);
11678 11679
            goto cleanup;
        }
11680

11681
        other = virDomainSnapshotFindByName(vm->snapshots, def->name);
11682 11683 11684 11685 11686
        if (other) {
            if ((other->def->state == VIR_DOMAIN_RUNNING ||
                 other->def->state == VIR_DOMAIN_PAUSED) !=
                (def->state == VIR_DOMAIN_RUNNING ||
                 def->state == VIR_DOMAIN_PAUSED)) {
11687 11688 11689 11690
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot change between online and offline "
                                 "snapshot state in snapshot %s"),
                               def->name);
11691 11692
                goto cleanup;
            }
11693

11694 11695
            if ((other->def->state == VIR_DOMAIN_DISK_SNAPSHOT) !=
                (def->state == VIR_DOMAIN_DISK_SNAPSHOT)) {
11696 11697 11698 11699
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot change between disk snapshot and "
                                 "system checkpoint in snapshot %s"),
                               def->name);
11700 11701
                goto cleanup;
            }
11702

11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713
            if (other->def->dom) {
                if (def->dom) {
                    if (!virDomainDefCheckABIStability(other->def->dom,
                                                       def->dom))
                        goto cleanup;
                } else {
                    /* Transfer the domain def */
                    def->dom = other->def->dom;
                    other->def->dom = NULL;
                }
            }
11714

11715 11716
            if (def->dom) {
                if (def->state == VIR_DOMAIN_DISK_SNAPSHOT ||
11717
                    virDomainSnapshotDefIsExternal(def)) {
11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732
                    align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
                    align_match = false;
                }

                if (virDomainSnapshotAlignDisks(def, align_location,
                                                align_match) < 0) {
                    /* revert stealing of the snapshot domain definition */
                    if (def->dom && !other->def->dom) {
                        other->def->dom = def->dom;
                        def->dom = NULL;
                    }
                    goto cleanup;
                }
            }

11733 11734 11735 11736
            if (other == vm->current_snapshot) {
                update_current = true;
                vm->current_snapshot = NULL;
            }
11737

11738 11739
            /* Drop and rebuild the parent relationship, but keep all
             * child relations by reusing snap.  */
11740
            virDomainSnapshotDropParent(other);
11741
            virDomainSnapshotDefFree(other->def);
11742 11743
            other->def = def;
            def = NULL;
11744
            snap = other;
11745 11746 11747 11748 11749 11750 11751 11752 11753 11754
        } else {
            if (def->dom) {
                if (def->state == VIR_DOMAIN_DISK_SNAPSHOT ||
                    def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
                    align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
                    align_match = false;
                }
                if (virDomainSnapshotAlignDisks(def, align_location,
                                                align_match) < 0)
                    goto cleanup;
11755
            }
11756
        }
11757 11758 11759
    } else {
        /* Easiest way to clone inactive portion of vm->def is via
         * conversion in and back out of xml.  */
11760
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
11761
            !(def->dom = virDomainDefParseString(xml, caps, driver->xmlopt,
11762 11763 11764 11765
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE)))
            goto cleanup;

11766
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
11767 11768
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
11769 11770 11771 11772
            if (virDomainObjIsActive(vm))
                def->state = VIR_DOMAIN_DISK_SNAPSHOT;
            else
                def->state = VIR_DOMAIN_SHUTOFF;
11773
            def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
11774 11775 11776 11777
        } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            def->state = virDomainObjGetState(vm, NULL);
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
11778 11779
        } else {
            def->state = virDomainObjGetState(vm, NULL);
11780 11781 11782
            def->memory = (def->state == VIR_DOMAIN_SHUTOFF ?
                           VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
                           VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL);
11783
        }
E
Eric Blake 已提交
11784 11785 11786 11787
        if (virDomainSnapshotAlignDisks(def, align_location,
                                        align_match) < 0 ||
            qemuDomainSnapshotPrepare(vm, def, &flags) < 0)
            goto cleanup;
11788 11789
    }

11790 11791 11792 11793 11794 11795
    if (!snap) {
        if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
            goto cleanup;

        def = NULL;
    }
C
Chris Lalancette 已提交
11796

11797 11798
    if (update_current)
        snap->def->current = true;
11799
    if (vm->current_snapshot) {
11800 11801 11802 11803 11804 11805
        if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
            snap->def->parent = strdup(vm->current_snapshot->def->name);
            if (snap->def->parent == NULL) {
                virReportOOMError();
                goto cleanup;
            }
11806
        }
11807
        if (update_current) {
11808 11809
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
11810
                                                cfg->snapshotDir) < 0)
11811 11812 11813
                goto cleanup;
            vm->current_snapshot = NULL;
        }
11814
    }
11815

C
Chris Lalancette 已提交
11816
    /* actually do the snapshot */
11817 11818
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* XXX Should we validate that the redefined snapshot even
11819 11820
         * makes sense, such as checking that qemu-img recognizes the
         * snapshot name in at least one of the domain's disks?  */
11821 11822 11823 11824 11825 11826 11827 11828 11829 11830 11831 11832 11833
    } else if (virDomainObjIsActive(vm)) {
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY ||
            snap->def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            /* external checkpoint or disk snapshot */
            if (qemuDomainSnapshotCreateActiveExternal(domain->conn, driver,
                                                       &vm, snap, flags) < 0)
                goto cleanup;
        } else {
            /* internal checkpoint */
            if (qemuDomainSnapshotCreateActiveInternal(domain->conn, driver,
                                                       &vm, snap, flags) < 0)
                goto cleanup;
        }
E
Eric Blake 已提交
11834
    } else {
11835 11836 11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847
        /* inactive; qemuDomainSnapshotPrepare guaranteed that we
         * aren't mixing internal and external, and altered flags to
         * contain DISK_ONLY if there is an external disk.  */
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
            bool reuse = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);

            if (qemuDomainSnapshotCreateInactiveExternal(driver, vm, snap,
                                                         reuse) < 0)
                goto cleanup;
        } else {
            if (qemuDomainSnapshotCreateInactiveInternal(driver, vm, snap) < 0)
                goto cleanup;
        }
C
Chris Lalancette 已提交
11848 11849
    }

11850
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
11851 11852 11853 11854 11855 11856
     * do; we've successfully taken the snapshot, and we are now running
     * on it, so we have to go forward the best we can
     */
    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
11857
    if (vm) {
11858
        if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
11859
            if (qemuDomainSnapshotWriteMetadata(vm, snap,
11860
                                                cfg->snapshotDir) < 0) {
11861 11862 11863 11864 11865 11866 11867 11868
                /* if writing of metadata fails, error out rather than trying
                 * to silently carry on  without completing the snapshot */
                virDomainSnapshotFree(snapshot);
                snapshot = NULL;
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unable to save metadata for snapshot %s"),
                               snap->def->name);
                virDomainSnapshotObjListRemove(vm->snapshots, snap);
11869 11870 11871
            } else {
                if (update_current)
                    vm->current_snapshot = snap;
11872
                other = virDomainSnapshotFindByName(vm->snapshots,
11873 11874 11875 11876 11877
                                                    snap->def->parent);
                snap->parent = other;
                other->nchildren++;
                snap->sibling = other->first_child;
                other->first_child = snap;
11878
            }
11879
        } else if (snap) {
11880
            virDomainSnapshotObjListRemove(vm->snapshots, snap);
11881
        }
11882
        virObjectUnlock(vm);
11883 11884
    }
    virDomainSnapshotDefFree(def);
11885
    VIR_FREE(xml);
11886
    virObjectUnref(caps);
11887
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
11888 11889 11890 11891 11892
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
11893
                                       unsigned int flags)
C
Chris Lalancette 已提交
11894 11895 11896 11897
{
    virDomainObjPtr vm = NULL;
    int n = -1;

11898
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
11899
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11900

11901
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11902 11903
        goto cleanup;

11904
    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
11905
                                         flags);
C
Chris Lalancette 已提交
11906 11907 11908

cleanup:
    if (vm)
11909
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11910 11911 11912 11913
    return n;
}

static int qemuDomainSnapshotNum(virDomainPtr domain,
11914
                                 unsigned int flags)
C
Chris Lalancette 已提交
11915 11916 11917 11918
{
    virDomainObjPtr vm = NULL;
    int n = -1;

11919
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
11920
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11921

11922
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11923 11924
        goto cleanup;

11925
    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
C
Chris Lalancette 已提交
11926 11927 11928

cleanup:
    if (vm)
11929
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11930 11931 11932
    return n;
}

11933 11934 11935 11936 11937 11938 11939 11940 11941 11942
static int
qemuDomainListAllSnapshots(virDomainPtr domain, virDomainSnapshotPtr **snaps,
                           unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);

11943
    if (!(vm = qemuDomObjFromDomain(domain)))
11944 11945
        goto cleanup;

11946
    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
11947 11948 11949

cleanup:
    if (vm)
11950
        virObjectUnlock(vm);
11951 11952 11953
    return n;
}

11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964
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 |
11965
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11966

11967
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11968 11969
        goto cleanup;

11970
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11971 11972
        goto cleanup;

11973
    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
11974
                                         flags);
11975 11976 11977

cleanup:
    if (vm)
11978
        virObjectUnlock(vm);
11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990
    return n;
}

static int
qemuDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
11991
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11992

11993
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11994 11995
        goto cleanup;

11996
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11997 11998
        goto cleanup;

11999
    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
12000 12001 12002

cleanup:
    if (vm)
12003
        virObjectUnlock(vm);
12004 12005 12006
    return n;
}

12007 12008 12009 12010 12011 12012 12013 12014 12015 12016 12017 12018
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);

12019
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
12020 12021
        goto cleanup;

12022
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
12023 12024
        goto cleanup;

12025
    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
12026 12027 12028 12029
                               flags);

cleanup:
    if (vm)
12030
        virObjectUnlock(vm);
12031 12032 12033
    return n;
}

C
Chris Lalancette 已提交
12034 12035
static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
12036
                                                           unsigned int flags)
C
Chris Lalancette 已提交
12037 12038 12039 12040 12041
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

12042 12043
    virCheckFlags(0, NULL);

12044
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
12045 12046
        goto cleanup;

12047
    if (!(snap = qemuSnapObjFromName(vm, name)))
C
Chris Lalancette 已提交
12048 12049 12050 12051 12052 12053
        goto cleanup;

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
    if (vm)
12054
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12055 12056 12057 12058
    return snapshot;
}

static int qemuDomainHasCurrentSnapshot(virDomainPtr domain,
12059
                                        unsigned int flags)
C
Chris Lalancette 已提交
12060 12061 12062 12063
{
    virDomainObjPtr vm;
    int ret = -1;

12064 12065
    virCheckFlags(0, -1);

12066
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
12067 12068 12069 12070 12071 12072
        goto cleanup;

    ret = (vm->current_snapshot != NULL);

cleanup:
    if (vm)
12073
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12074 12075 12076
    return ret;
}

12077 12078 12079 12080 12081 12082 12083 12084 12085 12086
static virDomainSnapshotPtr
qemuDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

12087
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
12088 12089
        goto cleanup;

12090
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
12091 12092 12093
        goto cleanup;

    if (!snap->def->parent) {
12094 12095 12096
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snap->def->name);
12097 12098 12099 12100 12101 12102 12103
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);

cleanup:
    if (vm)
12104
        virObjectUnlock(vm);
12105 12106 12107
    return parent;
}

C
Chris Lalancette 已提交
12108
static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
12109
                                                      unsigned int flags)
C
Chris Lalancette 已提交
12110 12111 12112 12113
{
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

12114 12115
    virCheckFlags(0, NULL);

12116
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
12117 12118 12119
        goto cleanup;

    if (!vm->current_snapshot) {
12120 12121
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                       _("the domain does not have a current snapshot"));
C
Chris Lalancette 已提交
12122 12123 12124 12125 12126 12127 12128
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);

cleanup:
    if (vm)
12129
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12130 12131 12132
    return snapshot;
}

12133 12134
static char *qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                                          unsigned int flags)
C
Chris Lalancette 已提交
12135 12136 12137 12138 12139 12140
{
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

12141
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
12142

12143
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
C
Chris Lalancette 已提交
12144 12145
        goto cleanup;

12146
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
12147
        goto cleanup;
12148 12149

    virUUIDFormat(snapshot->domain->uuid, uuidstr);
C
Chris Lalancette 已提交
12150

12151
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
12152 12153 12154

cleanup:
    if (vm)
12155
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12156 12157 12158
    return xml;
}

12159 12160 12161 12162 12163 12164 12165 12166 12167 12168
static int
qemuDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

12169
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
12170 12171
        goto cleanup;

12172
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
12173 12174 12175 12176 12177 12178 12179
        goto cleanup;

    ret = (vm->current_snapshot &&
           STREQ(snapshot->name, vm->current_snapshot->def->name));

cleanup:
    if (vm)
12180
        virObjectUnlock(vm);
12181 12182 12183 12184 12185 12186 12187 12188 12189 12190 12191 12192 12193 12194
    return ret;
}


static int
qemuDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

12195
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
12196 12197
        goto cleanup;

12198
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
12199 12200 12201 12202 12203 12204 12205 12206 12207
        goto cleanup;

    /* XXX Someday, we should recognize internal snapshots in qcow2
     * images that are not tied to a libvirt snapshot; if we ever do
     * that, then we would have a reason to return 0 here.  */
    ret = 1;

cleanup:
    if (vm)
12208
        virObjectUnlock(vm);
12209 12210 12211
    return ret;
}

12212 12213
/* The domain is expected to be locked and inactive. */
static int
12214
qemuDomainSnapshotRevertInactive(virQEMUDriverPtr driver,
E
Eric Blake 已提交
12215
                                 virDomainObjPtr vm,
12216 12217 12218
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
12219
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
12220 12221 12222
    return ret > 0 ? -1 : ret;
}

C
Chris Lalancette 已提交
12223
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
12224
                                      unsigned int flags)
C
Chris Lalancette 已提交
12225
{
12226
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
12227 12228 12229 12230 12231
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainEventPtr event = NULL;
12232
    virDomainEventPtr event2 = NULL;
12233
    int detail;
C
Chris Lalancette 已提交
12234 12235
    qemuDomainObjPrivatePtr priv;
    int rc;
12236
    virDomainDefPtr config = NULL;
12237
    virQEMUDriverConfigPtr cfg = NULL;
12238
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
12239

12240
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
12241 12242
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
12243

12244 12245 12246 12247 12248 12249 12250 12251 12252 12253
    /* 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
12254 12255
     * Also, several transitions occur even if we fail partway through,
     * and use of FORCE can cause multiple transitions.
12256 12257
     */

C
Chris Lalancette 已提交
12258
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
12259
    vm = virDomainObjListFindByUUID(driver->domains, snapshot->domain->uuid);
C
Chris Lalancette 已提交
12260
    if (!vm) {
12261 12262
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
12263 12264
        goto cleanup;
    }
12265 12266 12267

    cfg = virQEMUDriverGetConfig(driver);

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

E
Eric Blake 已提交
12271 12272 12273 12274 12275
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }
C
Chris Lalancette 已提交
12276

12277
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
12278 12279
        goto cleanup;

12280 12281 12282 12283 12284
    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) {
12285 12286 12287
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("transient domain needs to request run or pause "
                         "to revert to inactive snapshot"));
12288 12289
        goto cleanup;
    }
12290
    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
12291 12292 12293
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("revert to external disk snapshot not supported "
                         "yet"));
12294 12295
        goto cleanup;
    }
12296 12297
    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
        if (!snap->def->dom) {
12298 12299 12300
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                           _("snapshot '%s' lacks domain '%s' rollback info"),
                           snap->def->name, vm->def->name);
12301 12302 12303 12304 12305 12306 12307
            goto cleanup;
        }
        if (virDomainObjIsActive(vm) &&
            !(snap->def->state == VIR_DOMAIN_RUNNING
              || snap->def->state == VIR_DOMAIN_PAUSED) &&
            (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
                      VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
12308 12309
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                           _("must respawn qemu to start inactive snapshot"));
12310 12311 12312 12313
            goto cleanup;
        }
    }

12314

12315 12316 12317
    if (vm->current_snapshot) {
        vm->current_snapshot->def->current = false;
        if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
12318
                                            cfg->snapshotDir) < 0)
12319 12320 12321 12322 12323 12324
            goto cleanup;
        vm->current_snapshot = NULL;
        /* XXX Should we restore vm->current_snapshot after this point
         * in the failure cases where we know there was no change?  */
    }

12325
    /* Prepare to copy the snapshot inactive xml as the config of this
12326
     * domain.
12327 12328 12329
     *
     * XXX Should domain snapshots track live xml rather
     * than inactive xml?  */
12330
    snap->def->current = true;
12331
    if (snap->def->dom) {
12332
        config = virDomainDefCopy(snap->def->dom, caps, driver->xmlopt, true);
12333 12334 12335
        if (!config)
            goto cleanup;
    }
C
Chris Lalancette 已提交
12336

12337
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
12338 12339 12340 12341
        goto cleanup;

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {
12342 12343 12344 12345 12346 12347 12348 12349 12350
        /* Transitions 2, 3, 5, 6, 8, 9 */
        bool was_running = false;
        bool was_stopped = false;

        /* When using the loadvm monitor command, qemu does not know
         * whether to pause or run the reverted domain, and just stays
         * in the same state as before the monitor command, whether
         * that is paused or running.  We always pause before loadvm,
         * to have finer control.  */
C
Chris Lalancette 已提交
12351
        if (virDomainObjIsActive(vm)) {
12352
            /* Transitions 5, 6, 8, 9 */
12353 12354
            /* Check for ABI compatibility.  */
            if (config && !virDomainDefCheckABIStability(vm->def, config)) {
12355 12356 12357 12358 12359
                virErrorPtr err = virGetLastError();

                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
                    /* Re-spawn error using correct category. */
                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
12360 12361
                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                                       err->str2);
12362 12363 12364
                    goto endjob;
                }
                virResetError(err);
12365 12366
                qemuProcessStop(driver, vm,
                                VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12367 12368 12369 12370 12371 12372 12373 12374
                virDomainAuditStop(vm, "from-snapshot");
                detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 detail);
                if (event)
                    qemuDomainEventQueue(driver, event);
                goto load;
12375 12376
            }

C
Chris Lalancette 已提交
12377
            priv = vm->privateData;
12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391 12392
            if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
                /* Transitions 5, 6 */
                was_running = true;
                if (qemuProcessStopCPUs(driver, vm,
                                        VIR_DOMAIN_PAUSED_FROM_SNAPSHOT,
                                        QEMU_ASYNC_JOB_NONE) < 0)
                    goto endjob;
                /* Create an event now in case the restore fails, so
                 * that user will be alerted that they are now paused.
                 * If restore later succeeds, we might replace this. */
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 detail);
                if (!virDomainObjIsActive(vm)) {
12393 12394
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("guest unexpectedly quit"));
12395 12396 12397
                    goto endjob;
                }
            }
12398
            qemuDomainObjEnterMonitor(driver, vm);
C
Chris Lalancette 已提交
12399
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
12400
            qemuDomainObjExitMonitor(driver, vm);
12401 12402 12403
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
12404
                goto endjob;
12405
            }
12406
            if (config)
12407
                virDomainObjAssignDef(vm, config, false, NULL);
E
Eric Blake 已提交
12408
        } else {
12409
            /* Transitions 2, 3 */
12410
        load:
12411
            was_stopped = true;
12412
            if (config)
12413
                virDomainObjAssignDef(vm, config, false, NULL);
12414

12415 12416 12417 12418
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, snap,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  VIR_QEMU_PROCESS_START_PAUSED);
12419
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
12420 12421 12422 12423
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
12424
            if (rc < 0)
12425
                goto endjob;
C
Chris Lalancette 已提交
12426 12427
        }

12428
        /* Touch up domain state.  */
12429 12430 12431
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
12432 12433 12434 12435 12436 12437 12438 12439 12440 12441 12442 12443 12444
            /* Transitions 3, 6, 9 */
            virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                                 VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
            if (was_stopped) {
                /* Transition 3, use event as-is and add event2 */
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
                event2 = virDomainEventNewFromObj(vm,
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            } /* else transition 6 and 9 use event as-is */
        } else {
            /* Transitions 2, 5, 8 */
            if (!virDomainObjIsActive(vm)) {
12445 12446
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
12447 12448 12449 12450 12451
                goto endjob;
            }
            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
                                      QEMU_ASYNC_JOB_NONE);
H
Hu Tao 已提交
12452
            if (rc < 0)
12453
                goto endjob;
12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 12466 12467 12468
            virDomainEventFree(event);
            event = NULL;
            if (was_stopped) {
                /* Transition 2 */
                detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_STARTED,
                                                 detail);
            } else if (was_running) {
                /* Transition 8 */
                detail = VIR_DOMAIN_EVENT_RESUMED;
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_RESUMED,
                                                 detail);
            }
C
Chris Lalancette 已提交
12469
        }
E
Eric Blake 已提交
12470
    } else {
12471
        /* Transitions 1, 4, 7 */
12472 12473 12474
        /* 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 已提交
12475 12476 12477
         */

        if (virDomainObjIsActive(vm)) {
12478
            /* Transitions 4, 7 */
12479
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12480
            virDomainAuditStop(vm, "from-snapshot");
12481
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
C
Chris Lalancette 已提交
12482 12483
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
12484
                                             detail);
12485 12486
        }

E
Eric Blake 已提交
12487
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
12488
            if (!vm->persistent) {
12489
                if (qemuDomainObjEndJob(driver, vm) > 0)
12490
                    qemuDomainRemoveInactive(driver, vm);
12491
                vm = NULL;
12492
                goto cleanup;
12493
            }
12494
            goto endjob;
C
Chris Lalancette 已提交
12495
        }
12496
        if (config)
12497
            virDomainObjAssignDef(vm, config, false, NULL);
12498

12499 12500 12501 12502
        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;
12503 12504 12505
            unsigned int start_flags = 0;

            start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
12506 12507 12508

            if (event)
                qemuDomainEventQueue(driver, event);
12509 12510 12511 12512
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, NULL,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  start_flags);
12513 12514 12515 12516
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
                    if (qemuDomainObjEndJob(driver, vm) > 0)
12517
                        qemuDomainRemoveInactive(driver, vm);
12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533
                    vm = NULL;
                    goto cleanup;
                }
                goto endjob;
            }
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
            if (paused) {
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
                event2 = virDomainEventNewFromObj(vm,
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            }
        }
C
Chris Lalancette 已提交
12534 12535 12536 12537
    }

    ret = 0;

12538
endjob:
12539
    if (vm && qemuDomainObjEndJob(driver, vm) == 0)
C
Chris Lalancette 已提交
12540 12541
        vm = NULL;

12542
cleanup:
12543 12544
    if (vm && ret == 0) {
        if (qemuDomainSnapshotWriteMetadata(vm, snap,
12545
                                            cfg->snapshotDir) < 0)
12546 12547 12548 12549 12550 12551
            ret = -1;
        else
            vm->current_snapshot = snap;
    } else if (snap) {
        snap->def->current = false;
    }
12552
    if (event) {
C
Chris Lalancette 已提交
12553
        qemuDomainEventQueue(driver, event);
12554 12555 12556
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
12557
    if (vm)
12558
        virObjectUnlock(vm);
12559
    virObjectUnref(caps);
12560
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
12561 12562 12563 12564

    return ret;
}

12565 12566 12567 12568

typedef struct _virQEMUSnapReparent virQEMUSnapReparent;
typedef virQEMUSnapReparent *virQEMUSnapReparentPtr;
struct _virQEMUSnapReparent {
12569
    virQEMUDriverConfigPtr cfg;
12570
    virDomainSnapshotObjPtr parent;
12571 12572
    virDomainObjPtr vm;
    int err;
12573
    virDomainSnapshotObjPtr last;
12574 12575 12576 12577
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
12578
                                   const void *name ATTRIBUTE_UNUSED,
12579 12580 12581
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
12582
    virQEMUSnapReparentPtr rep = data;
12583 12584 12585 12586 12587

    if (rep->err < 0) {
        return;
    }

12588
    VIR_FREE(snap->def->parent);
12589
    snap->parent = rep->parent;
12590

12591
    if (rep->parent->def) {
12592
        snap->def->parent = strdup(rep->parent->def->name);
12593

12594 12595 12596 12597
        if (snap->def->parent == NULL) {
            virReportOOMError();
            rep->err = -1;
            return;
12598 12599
        }
    }
12600

12601 12602 12603
    if (!snap->sibling)
        rep->last = snap;

12604
    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
12605
                                               rep->cfg->snapshotDir);
12606 12607
}

12608

C
Chris Lalancette 已提交
12609 12610 12611
static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                                    unsigned int flags)
{
12612
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
12613 12614 12615 12616
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
12617 12618
    virQEMUSnapRemove rem;
    virQEMUSnapReparent rep;
12619
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
12620
    int external = 0;
12621
    virQEMUDriverConfigPtr cfg = NULL;
C
Chris Lalancette 已提交
12622

12623
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
12624 12625
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
12626

C
Chris Lalancette 已提交
12627
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
12628
    vm = virDomainObjListFindByUUID(driver->domains, snapshot->domain->uuid);
C
Chris Lalancette 已提交
12629
    if (!vm) {
12630 12631
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
12632 12633 12634
        goto cleanup;
    }

12635
    cfg = virQEMUDriverGetConfig(driver);
12636
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
12637 12638
        goto cleanup;

12639
    if (!metadata_only) {
12640
        if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
12641
            virDomainSnapshotIsExternal(snap))
12642 12643
            external++;
        if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
E
Eric Blake 已提交
12644
            virDomainSnapshotForEachDescendant(snap,
12645 12646 12647
                                               qemuDomainSnapshotCountExternal,
                                               &external);
        if (external) {
12648 12649 12650
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("deletion of %d external disk snapshots not "
                             "supported yet"), external);
12651 12652 12653 12654
            goto cleanup;
        }
    }

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

12658 12659
    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
C
Chris Lalancette 已提交
12660 12661
        rem.driver = driver;
        rem.vm = vm;
12662
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
12663
        rem.err = 0;
12664
        rem.current = false;
E
Eric Blake 已提交
12665
        virDomainSnapshotForEachDescendant(snap,
E
Eric Blake 已提交
12666
                                           qemuDomainSnapshotDiscardAll,
12667
                                           &rem);
C
Chris Lalancette 已提交
12668
        if (rem.err < 0)
12669
            goto endjob;
12670 12671 12672 12673
        if (rem.current) {
            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
                snap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, snap,
12674
                                                    cfg->snapshotDir) < 0) {
12675 12676 12677
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("failed to set snapshot '%s' as current"),
                                   snap->def->name);
12678 12679 12680 12681
                    snap->def->current = false;
                    goto endjob;
                }
            }
12682
            vm->current_snapshot = snap;
12683
        }
12684
    } else if (snap->nchildren) {
12685
        rep.cfg = cfg;
12686
        rep.parent = snap->parent;
12687 12688
        rep.vm = vm;
        rep.err = 0;
12689
        rep.last = NULL;
E
Eric Blake 已提交
12690
        virDomainSnapshotForEachChild(snap,
12691 12692
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
12693 12694
        if (rep.err < 0)
            goto endjob;
12695
        /* Can't modify siblings during ForEachChild, so do it now.  */
12696 12697 12698
        snap->parent->nchildren += snap->nchildren;
        rep.last->sibling = snap->parent->first_child;
        snap->parent->first_child = snap->first_child;
C
Chris Lalancette 已提交
12699 12700
    }

12701 12702 12703
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
        snap->nchildren = 0;
        snap->first_child = NULL;
12704
        ret = 0;
12705
    } else {
12706
        virDomainSnapshotDropParent(snap);
12707
        ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
12708
    }
C
Chris Lalancette 已提交
12709

12710
endjob:
12711
    if (qemuDomainObjEndJob(driver, vm) == 0)
12712 12713
        vm = NULL;

C
Chris Lalancette 已提交
12714 12715
cleanup:
    if (vm)
12716
        virObjectUnlock(vm);
12717
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
12718 12719
    return ret;
}
12720

12721 12722 12723
static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
                                    char **result, unsigned int flags)
{
12724
    virQEMUDriverPtr driver = domain->conn->privateData;
12725 12726 12727
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
12728
    bool hmp;
12729

12730
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
12731

12732
    if (!(vm = qemuDomObjFromDomain(domain)))
12733 12734 12735
        goto cleanup;

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

12741
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
12742 12743 12744
        goto cleanup;

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

12750 12751
    priv = vm->privateData;

12752
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
12753

12754 12755
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

12756
    qemuDomainObjEnterMonitor(driver, vm);
12757
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
12758
    qemuDomainObjExitMonitor(driver, vm);
12759 12760

endjob:
12761
    if (qemuDomainObjEndJob(driver, vm) == 0) {
12762 12763 12764 12765 12766
        vm = NULL;
    }

cleanup:
    if (vm)
12767
        virObjectUnlock(vm);
12768 12769 12770
    return ret;
}

12771

12772
static virDomainPtr qemuDomainAttach(virConnectPtr conn,
12773
                                     unsigned int pid_value,
12774 12775
                                     unsigned int flags)
{
12776
    virQEMUDriverPtr driver = conn->privateData;
12777 12778 12779 12780 12781
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
12782
    pid_t pid = pid_value;
12783
    char *pidfile = NULL;
12784
    virQEMUCapsPtr qemuCaps = NULL;
12785
    virCapsPtr caps = NULL;
12786 12787 12788

    virCheckFlags(0, NULL);

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

12792
    if (!(def = qemuParseCommandLinePid(caps, driver->xmlopt, pid,
12793 12794 12795 12796
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

    if (!monConfig) {
12797 12798
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("No monitor connection for pid %u"), pid_value);
12799 12800 12801
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
12802 12803 12804 12805 12806
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot connect to monitor connection of type '%s' "
                         "for pid %u"),
                       virDomainChrTypeToString(monConfig->type),
                       pid_value);
12807 12808 12809 12810
        goto cleanup;
    }

    if (!(def->name) &&
12811
        virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0) {
12812 12813 12814 12815
        virReportOOMError();
        goto cleanup;
    }

12816
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
12817 12818
        goto cleanup;

12819
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
12820 12821
        goto cleanup;

12822
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
12823 12824
        goto cleanup;

12825
    if (!(vm = virDomainObjListAdd(driver->domains, def,
12826
                                   driver->xmlopt,
12827 12828 12829
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
12830 12831 12832 12833
        goto cleanup;

    def = NULL;

12834
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
12835 12836 12837 12838 12839 12840 12841 12842 12843 12844 12845 12846 12847 12848
        goto cleanup;

    if (qemuProcessAttach(conn, driver, vm, pid,
                          pidfile, monConfig, monJSON) < 0) {
        monConfig = NULL;
        goto endjob;
    }

    monConfig = NULL;

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

endjob:
12849
    if (qemuDomainObjEndJob(driver, vm) == 0) {
12850 12851 12852 12853 12854 12855
        vm = NULL;
        goto cleanup;
    }

cleanup:
    virDomainDefFree(def);
12856
    virObjectUnref(qemuCaps);
12857 12858
    virDomainChrSourceDefFree(monConfig);
    if (vm)
12859
        virObjectUnlock(vm);
12860
    VIR_FREE(pidfile);
12861
    virObjectUnref(caps);
12862 12863 12864 12865
    return dom;
}


12866 12867
static int
qemuDomainOpenConsole(virDomainPtr dom,
12868
                      const char *dev_name,
12869 12870 12871 12872 12873 12874 12875
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    int i;
    virDomainChrDefPtr chr = NULL;
12876
    qemuDomainObjPrivatePtr priv;
12877

12878 12879
    virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE |
                  VIR_DOMAIN_CONSOLE_FORCE, -1);
12880

12881
    if (!(vm = qemuDomObjFromDomain(dom)))
12882 12883 12884
        goto cleanup;

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

12890 12891
    priv = vm->privateData;

12892
    if (dev_name) {
12893 12894 12895 12896 12897
        for (i = 0 ; !chr && i < vm->def->nconsoles ; i++) {
            if (vm->def->consoles[i]->info.alias &&
                STREQ(dev_name, vm->def->consoles[i]->info.alias))
                chr = vm->def->consoles[i];
        }
12898
        for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
12899
            if (STREQ(dev_name, vm->def->serials[i]->info.alias))
12900 12901 12902
                chr = vm->def->serials[i];
        }
        for (i = 0 ; !chr && i < vm->def->nparallels ; i++) {
12903
            if (STREQ(dev_name, vm->def->parallels[i]->info.alias))
12904 12905 12906
                chr = vm->def->parallels[i];
        }
    } else {
12907 12908
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
12909 12910 12911 12912 12913
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
12914 12915 12916
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find character device %s"),
                       NULLSTR(dev_name));
12917 12918 12919
        goto cleanup;
    }

12920
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
12921 12922 12923
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("character device %s is not using a PTY"),
                       NULLSTR(dev_name));
12924 12925 12926
        goto cleanup;
    }

12927
    /* handle mutually exclusive access to console devices */
12928
    ret = virChrdevOpen(priv->devs,
12929
                        &chr->source,
12930 12931
                        st,
                        (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0);
12932 12933

    if (ret == 1) {
12934 12935
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active console session exists for this domain"));
12936 12937
        ret = -1;
    }
12938 12939 12940

cleanup:
    if (vm)
12941
        virObjectUnlock(vm);
12942 12943 12944
    return ret;
}

12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957 12958 12959 12960 12961 12962 12963 12964 12965 12966 12967 12968 12969 12970 12971 12972 12973 12974 12975 12976 12977 12978 12979 12980 12981 12982 12983 12984 12985 12986 12987 12988 12989 12990 12991 12992 12993 12994 12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008 13009 13010 13011 13012
static int
qemuDomainOpenChannel(virDomainPtr dom,
                      const char *name,
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    int i;
    virDomainChrDefPtr chr = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(VIR_DOMAIN_CHANNEL_FORCE, -1);

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

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

    priv = vm->privateData;

    if (name) {
        for (i = 0 ; !chr && i < vm->def->nchannels ; i++) {
            if (STREQ(name, vm->def->channels[i]->info.alias))
                chr = vm->def->channels[i];

            if (vm->def->channels[i]->targetType == \
                VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
                STREQ(name, vm->def->channels[i]->target.name))
                chr = vm->def->channels[i];
        }
    } else {
        if (vm->def->nchannels)
            chr = vm->def->channels[0];
    }

    if (!chr) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find channel %s"),
                       NULLSTR(name));
        goto cleanup;
    }

    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_UNIX) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("channel %s is not using a UNIX socket"),
                       NULLSTR(name));
        goto cleanup;
    }

    /* handle mutually exclusive access to channel devices */
    ret = virChrdevOpen(priv->devs,
                        &chr->source,
                        st,
                        (flags & VIR_DOMAIN_CHANNEL_FORCE) != 0);

    if (ret == 1) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active channel stream exists for this domain"));
        ret = -1;
    }

cleanup:
    if (vm)
13013
        virObjectUnlock(vm);
13014 13015 13016
    return ret;
}

E
Eric Blake 已提交
13017
static char *
E
Eric Blake 已提交
13018
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path, int *idx)
E
Eric Blake 已提交
13019
{
13020 13021
    int i;
    char *ret = NULL;
13022
    virDomainDiskDefPtr disk;
13023

13024 13025 13026
    i = virDomainDiskIndexByName(vm->def, path, true);
    if (i < 0)
        goto cleanup;
13027

13028
    disk = vm->def->disks[i];
E
Eric Blake 已提交
13029 13030
    if (idx)
        *idx = i;
13031

13032 13033 13034 13035 13036 13037 13038 13039
    if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
        disk->type != VIR_DOMAIN_DISK_TYPE_FILE)
        goto cleanup;

    if (disk->src) {
        if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0) {
            virReportOOMError();
            return NULL;
13040 13041 13042
        }
    }

13043
cleanup:
13044
    if (!ret) {
13045 13046
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("No device found for specified path"));
13047 13048 13049 13050
    }
    return ret;
}

13051 13052 13053 13054
/* 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 已提交
13055
qemuDomainBlockPivot(virConnectPtr conn,
13056
                     virQEMUDriverPtr driver, virDomainObjPtr vm,
13057 13058 13059 13060 13061 13062
                     const char *device, virDomainDiskDefPtr disk)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainBlockJobInfo info;
    const char *format = virStorageFileFormatTypeToString(disk->mirrorFormat);
E
Eric Blake 已提交
13063
    bool resume = false;
13064 13065 13066 13067
    virCgroupPtr cgroup = NULL;
    char *oldsrc = NULL;
    int oldformat;
    virStorageFileMetadataPtr oldchain = NULL;
13068
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
13069 13070 13071

    /* Probe the status, if needed.  */
    if (!disk->mirroring) {
13072
        qemuDomainObjEnterMonitor(driver, vm);
13073 13074
        ret = qemuMonitorBlockJob(priv->mon, device, NULL, 0, &info,
                                  BLOCK_JOB_INFO, true);
13075
        qemuDomainObjExitMonitor(driver, vm);
13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094
        if (ret < 0)
            goto cleanup;
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain is not running"));
            goto cleanup;
        }
        if (ret == 1 && info.cur == info.end &&
            info.type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY)
            disk->mirroring = true;
    }

    if (!disk->mirroring) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' not ready for pivot yet"),
                       disk->dst);
        goto cleanup;
    }

E
Eric Blake 已提交
13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 13109 13110 13111 13112 13113 13114 13115 13116 13117
    /* 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;
        }
    }

13118 13119 13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 13136 13137 13138 13139 13140 13141 13142 13143 13144
    /* We previously labeled only the top-level image; but if the
     * image includes a relative backing file, the pivot may result in
     * qemu needing to open the entire backing chain, so we need to
     * label the entire chain.  This action is safe even if the
     * backing chain has already been labeled; but only necessary when
     * we know for sure that there is a backing chain.  */
    if (disk->mirrorFormat && disk->mirrorFormat != VIR_STORAGE_FILE_RAW &&
        qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
        goto cleanup;
    }
    oldsrc = disk->src;
    oldformat = disk->format;
    oldchain = disk->backingChain;
    disk->src = disk->mirror;
    disk->format = disk->mirrorFormat;
    disk->backingChain = NULL;
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0) {
        disk->src = oldsrc;
        disk->format = oldformat;
        disk->backingChain = oldchain;
        goto cleanup;
    }
    if (disk->mirrorFormat && disk->mirrorFormat != VIR_STORAGE_FILE_RAW &&
13145
        (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
13146 13147 13148 13149 13150 13151 13152 13153 13154 13155
                                 vm, disk) < 0 ||
         (cgroup && qemuSetupDiskCgroup(vm, cgroup, disk) < 0) ||
         virSecurityManagerSetImageLabel(driver->securityManager, vm->def,
                                         disk) < 0)) {
        disk->src = oldsrc;
        disk->format = oldformat;
        disk->backingChain = oldchain;
        goto cleanup;
    }

13156
    /* Attempt the pivot.  */
13157
    qemuDomainObjEnterMonitor(driver, vm);
13158
    ret = qemuMonitorDrivePivot(priv->mon, device, disk->mirror, format);
13159
    qemuDomainObjExitMonitor(driver, vm);
13160 13161 13162 13163 13164 13165 13166 13167 13168

    if (ret == 0) {
        /* XXX We want to revoke security labels and disk lease, as
         * well as audit that revocation, before dropping the original
         * source.  But it gets tricky if both source and mirror share
         * common backing files (we want to only revoke the non-shared
         * portion of the chain, and is made more difficult by the
         * fact that we aren't tracking the full chain ourselves; so
         * for now, we leak the access to the original.  */
13169 13170
        VIR_FREE(oldsrc);
        virStorageFileFreeMetadata(oldchain);
13171 13172 13173 13174 13175 13176 13177 13178 13179 13180
        disk->mirror = NULL;
    } else {
        /* On failure, qemu abandons the mirror, and reverts back to
         * the source disk (RHEL 6.3 has a bug where the revert could
         * cause catastrophic failure in qemu, but we don't need to
         * worry about it here as it is not an upstream qemu problem.  */
        /* XXX should we be parsing the exact qemu error, or calling
         * 'query-block', to see what state we really got left in
         * before killing the mirroring job?  And just as on the
         * success case, there's security labeling to worry about.  */
13181 13182 13183 13184
        disk->src = oldsrc;
        disk->format = oldformat;
        virStorageFileFreeMetadata(disk->backingChain);
        disk->backingChain = oldchain;
13185 13186
        VIR_FREE(disk->mirror);
    }
13187 13188
    disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
    disk->mirroring = false;
13189 13190

cleanup:
13191 13192
    if (cgroup)
        virCgroupFree(&cgroup);
E
Eric Blake 已提交
13193 13194 13195
    if (resume && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
13196 13197 13198 13199 13200 13201 13202 13203 13204 13205 13206
                             QEMU_ASYNC_JOB_NONE) < 0) {
        virDomainEventPtr event = NULL;
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (event)
            qemuDomainEventQueue(driver, event);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after drive-reopen failed"));
        }
E
Eric Blake 已提交
13207
    }
13208
    virObjectUnref(cfg);
13209 13210 13211
    return ret;
}

13212
static int
13213
qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base,
13214
                       unsigned long bandwidth, virDomainBlockJobInfoPtr info,
13215
                       int mode, unsigned int flags)
13216
{
13217
    virQEMUDriverPtr driver = dom->conn->privateData;
13218 13219 13220
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
E
Eric Blake 已提交
13221
    char *device = NULL;
13222
    int ret = -1;
13223
    bool async = false;
13224 13225 13226
    virDomainEventPtr event = NULL;
    int idx;
    virDomainDiskDefPtr disk;
13227 13228

    virUUIDFormat(dom->uuid, uuidstr);
13229
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
13230
    if (!vm) {
13231 13232
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13233 13234
        goto cleanup;
    }
13235
    if (!virDomainObjIsActive(vm)) {
13236 13237
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
13238 13239 13240
        goto cleanup;
    }

13241
    priv = vm->privateData;
13242
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC)) {
13243
        async = true;
13244
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC)) {
13245 13246
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block jobs not supported with this QEMU binary"));
13247 13248
        goto cleanup;
    } else if (base) {
13249 13250 13251
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("partial block pull not supported with this "
                         "QEMU binary"));
13252
        goto cleanup;
13253
    } else if (mode == BLOCK_JOB_PULL && bandwidth) {
13254 13255 13256
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("setting bandwidth at start of block pull not "
                         "supported with this QEMU binary"));
13257
        goto cleanup;
13258
    }
13259

13260 13261
    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
13262
        goto cleanup;
13263
    disk = vm->def->disks[idx];
13264

E
Eric Blake 已提交
13265 13266 13267 13268 13269 13270
    if (mode == BLOCK_JOB_PULL && disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' already in active block copy job"),
                       disk->dst);
        goto cleanup;
    }
13271 13272 13273 13274 13275 13276 13277 13278
    if (mode == BLOCK_JOB_ABORT &&
        (flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT) &&
        !(async && disk->mirror)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("pivot of disk '%s' requires an active copy job"),
                       disk->dst);
        goto cleanup;
    }
E
Eric Blake 已提交
13279

13280
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
13281
        goto cleanup;
13282 13283

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

13289 13290
    if (disk->mirror && mode == BLOCK_JOB_ABORT &&
        (flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)) {
E
Eric Blake 已提交
13291
        ret = qemuDomainBlockPivot(dom->conn, driver, vm, device, disk);
13292 13293 13294
        goto endjob;
    }

13295
    qemuDomainObjEnterMonitor(driver, vm);
13296
    /* XXX - libvirt should really be tracking the backing file chain
13297 13298
     * itself, and validating that base is on the chain, rather than
     * relying on qemu to do this.  */
13299 13300
    ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode,
                              async);
13301
    qemuDomainObjExitMonitor(driver, vm);
13302 13303 13304
    if (ret < 0)
        goto endjob;

13305 13306 13307 13308 13309 13310
    /* Snoop block copy operations, so future cancel operations can
     * avoid checking if pivot is safe.  */
    if (mode == BLOCK_JOB_INFO && ret == 1 && disk->mirror &&
        info->cur == info->end && info->type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY)
        disk->mirroring = true;

13311 13312 13313 13314 13315 13316 13317 13318 13319
    /* A successful block job cancelation stops any mirroring.  */
    if (mode == BLOCK_JOB_ABORT && disk->mirror) {
        /* XXX We should also revoke security labels and disk lease on
         * the mirror, and audit that fact, before dropping things.  */
        VIR_FREE(disk->mirror);
        disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
        disk->mirroring = false;
    }

13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330 13331 13332 13333 13334 13335 13336 13337 13338
    /* With synchronous block cancel, we must synthesize an event, and
     * we silently ignore the ABORT_ASYNC flag.  With asynchronous
     * block cancel, the event will come from qemu, but without the
     * ABORT_ASYNC flag, we must block to guarantee synchronous
     * operation.  We do the waiting while still holding the VM job,
     * to prevent newly scheduled block jobs from confusing us.  */
    if (mode == BLOCK_JOB_ABORT) {
        if (!async) {
            int type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
            int status = VIR_DOMAIN_BLOCK_JOB_CANCELED;
            event = virDomainEventBlockJobNewFromObj(vm, disk->src, type,
                                                     status);
        } else if (!(flags & VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC)) {
            while (1) {
                /* Poll every 50ms */
                static struct timespec ts = { .tv_sec = 0,
                                              .tv_nsec = 50 * 1000 * 1000ull };
                virDomainBlockJobInfo dummy;

13339
                qemuDomainObjEnterMonitor(driver, vm);
13340 13341
                ret = qemuMonitorBlockJob(priv->mon, device, NULL, 0, &dummy,
                                          BLOCK_JOB_INFO, async);
13342
                qemuDomainObjExitMonitor(driver, vm);
13343 13344 13345 13346

                if (ret <= 0)
                    break;

13347
                virObjectUnlock(vm);
13348 13349 13350

                nanosleep(&ts, NULL);

13351
                virObjectLock(vm);
13352 13353

                if (!virDomainObjIsActive(vm)) {
13354 13355
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("domain is not running"));
13356 13357 13358 13359 13360 13361
                    ret = -1;
                    break;
                }
            }
        }
    }
13362 13363

endjob:
13364 13365 13366 13367 13368 13369 13370 13371
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    VIR_FREE(device);
    if (vm)
13372
        virObjectUnlock(vm);
13373 13374
    if (event)
        qemuDomainEventQueue(driver, event);
13375 13376 13377 13378 13379 13380
    return ret;
}

static int
qemuDomainBlockJobAbort(virDomainPtr dom, const char *path, unsigned int flags)
{
13381 13382
    virCheckFlags(VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC |
                  VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT, -1);
13383 13384
    return qemuDomainBlockJobImpl(dom, path, NULL, 0, NULL, BLOCK_JOB_ABORT,
                                  flags);
13385 13386 13387 13388 13389 13390 13391
}

static int
qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
                           virDomainBlockJobInfoPtr info, unsigned int flags)
{
    virCheckFlags(0, -1);
13392 13393
    return qemuDomainBlockJobImpl(dom, path, NULL, 0, info, BLOCK_JOB_INFO,
                                  flags);
13394 13395 13396 13397 13398 13399 13400
}

static int
qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
                           unsigned long bandwidth, unsigned int flags)
{
    virCheckFlags(0, -1);
13401
    return qemuDomainBlockJobImpl(dom, path, NULL, bandwidth, NULL,
13402
                                  BLOCK_JOB_SPEED, flags);
13403 13404
}

13405 13406 13407 13408 13409
static int
qemuDomainBlockCopy(virDomainPtr dom, const char *path,
                    const char *dest, const char *format,
                    unsigned long bandwidth, unsigned int flags)
{
13410
    virQEMUDriverPtr driver = dom->conn->privateData;
13411 13412 13413 13414 13415 13416
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *device = NULL;
    virDomainDiskDefPtr disk;
    int ret = -1;
    int idx;
13417
    struct stat st;
13418 13419 13420
    bool need_unlink = false;
    char *mirror = NULL;
    virCgroupPtr cgroup = NULL;
13421
    virQEMUDriverConfigPtr cfg = NULL;
13422 13423

    /* Preliminaries: find the disk we are editing, sanity checks */
13424 13425
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT, -1);
13426 13427 13428 13429

    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
    priv = vm->privateData;
13430
    cfg = virQEMUDriverGetConfig(driver);
13431 13432 13433 13434 13435
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
        goto cleanup;
    }
13436 13437 13438 13439 13440 13441 13442
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
        goto cleanup;
    }
13443 13444 13445 13446 13447 13448 13449 13450 13451 13452 13453 13454 13455

    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device) {
        goto cleanup;
    }
    disk = vm->def->disks[idx];
    if (disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' already in active block copy job"),
                       disk->dst);
        goto cleanup;
    }

13456 13457
    if (!(virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_MIRROR) &&
          virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC))) {
13458 13459 13460 13461 13462 13463 13464 13465 13466 13467 13468 13469 13470 13471 13472 13473 13474 13475 13476 13477 13478 13479 13480 13481 13482 13483 13484 13485 13486 13487 13488 13489 13490 13491 13492 13493
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block copy is not supported with this QEMU binary"));
        goto cleanup;
    }
    if (vm->persistent) {
        /* XXX if qemu ever lets us start a new domain with mirroring
         * already active, we can relax this; but for now, the risk of
         * 'managedsave' due to libvirt-guests means we can't risk
         * this on persistent domains.  */
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not transient"));
        goto cleanup;
    }

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

    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
        goto endjob;
    }
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto endjob;

    if ((flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) &&
        STREQ_NULLABLE(format, "raw") &&
        disk->backingChain->backingStore) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk '%s' has backing file, so raw shallow copy "
                         "is not possible"),
                       disk->dst);
        goto endjob;
    }

    /* Prepare the destination file.  */
13494 13495 13496 13497 13498 13499 13500 13501 13502 13503 13504 13505 13506 13507 13508 13509 13510 13511 13512 13513
    if (stat(dest, &st) < 0) {
        if (errno != ENOENT) {
            virReportSystemError(errno, _("unable to stat for disk %s: %s"),
                                 disk->dst, dest);
            goto endjob;
        } else if (flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) {
            virReportSystemError(errno,
                                 _("missing destination file for disk %s: %s"),
                                 disk->dst, dest);
            goto endjob;
        }
    } else if (!S_ISBLK(st.st_mode) && st.st_size &&
               !(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("external destination file for disk %s already "
                         "exists and is not a block device: %s"),
                       disk->dst, dest);
        goto endjob;
    }

13514 13515 13516 13517 13518 13519 13520
    if (!(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
        int fd = qemuOpenFile(driver, dest, O_WRONLY | O_TRUNC | O_CREAT,
                              &need_unlink, NULL);
        if (fd < 0)
            goto endjob;
        VIR_FORCE_CLOSE(fd);
        if (!format)
13521
            disk->mirrorFormat = disk->format;
13522
    } else if (format) {
13523 13524 13525 13526 13527 13528
        disk->mirrorFormat = virStorageFileFormatTypeFromString(format);
        if (disk->mirrorFormat <= 0) {
            virReportError(VIR_ERR_INVALID_ARG, _("unrecognized format '%s'"),
                           format);
            goto endjob;
        }
13529 13530 13531 13532 13533
    } else {
        /* If the user passed the REUSE_EXT flag, then either they
         * also passed the RAW flag (and format is non-NULL), or it is
         * safe for us to probe the format from the file that we will
         * be using.  */
13534 13535
        disk->mirrorFormat = virStorageFileProbeFormat(dest, cfg->user,
                                                       cfg->group);
13536 13537 13538
    }
    if (!format && disk->mirrorFormat > 0)
        format = virStorageFileFormatTypeToString(disk->mirrorFormat);
13539
    if (!(mirror = strdup(dest))) {
13540 13541 13542 13543
        virReportOOMError();
        goto endjob;
    }

13544 13545 13546 13547 13548 13549 13550
    if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
                                          VIR_DISK_CHAIN_NO_ACCESS);
        goto endjob;
    }

13551 13552 13553 13554
    /* Actually start the mirroring */
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorDriveMirror(priv->mon, device, dest, format, bandwidth,
                                 flags);
13555
    virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0);
13556
    qemuDomainObjExitMonitor(driver, vm);
13557 13558 13559 13560 13561 13562 13563 13564 13565 13566
    if (ret < 0) {
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
                                          VIR_DISK_CHAIN_NO_ACCESS);
        goto endjob;
    }

    /* Update vm in place to match changes.  */
    need_unlink = false;
    disk->mirror = mirror;
    mirror = NULL;
13567 13568

endjob:
13569 13570 13571
    if (need_unlink && unlink(dest))
        VIR_WARN("unable to unlink just-created %s", dest);
    if (ret < 0)
13572
        disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
13573
    VIR_FREE(mirror);
13574 13575 13576 13577 13578 13579
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
13580 13581
    if (cgroup)
        virCgroupFree(&cgroup);
13582 13583
    VIR_FREE(device);
    if (vm)
13584
        virObjectUnlock(vm);
13585
    virObjectUnref(cfg);
13586 13587 13588
    return ret;
}

13589
static int
13590 13591
qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
                      unsigned long bandwidth, unsigned int flags)
13592
{
13593
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
13594
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
13595 13596 13597 13598 13599 13600 13601 13602 13603 13604 13605 13606
                  VIR_DOMAIN_BLOCK_REBASE_COPY |
                  VIR_DOMAIN_BLOCK_REBASE_COPY_RAW, -1);

    if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY) {
        const char *format = NULL;
        if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
            format = "raw";
        flags &= ~(VIR_DOMAIN_BLOCK_REBASE_COPY |
                   VIR_DOMAIN_BLOCK_REBASE_COPY_RAW);
        return qemuDomainBlockCopy(dom, path, base, format, bandwidth, flags);
    }

13607 13608
    return qemuDomainBlockJobImpl(dom, path, base, bandwidth, NULL,
                                  BLOCK_JOB_PULL, flags);
13609
}
13610

13611 13612 13613 13614
static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
                    unsigned int flags)
{
13615 13616 13617
    virCheckFlags(0, -1);
    return qemuDomainBlockJobImpl(dom, path, NULL, bandwidth, NULL,
                                  BLOCK_JOB_PULL, flags);
13618 13619
}

13620 13621 13622 13623 13624 13625

static int
qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base,
                      const char *top, unsigned long bandwidth,
                      unsigned int flags)
{
13626
    virQEMUDriverPtr driver = dom->conn->privateData;
13627 13628 13629 13630 13631
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm = NULL;
    char *device = NULL;
    int ret = -1;
    int idx;
E
Eric Blake 已提交
13632
    virDomainDiskDefPtr disk = NULL;
13633 13634 13635 13636
    const char *top_canon = NULL;
    virStorageFileMetadataPtr top_meta = NULL;
    const char *top_parent = NULL;
    const char *base_canon = NULL;
13637
    virCgroupPtr cgroup = NULL;
E
Eric Blake 已提交
13638
    bool clean_access = false;
13639

13640
    virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW, -1);
13641 13642 13643 13644 13645 13646 13647 13648 13649 13650 13651 13652 13653

    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
    priv = vm->privateData;

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

    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto endjob;
    }
13654
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCK_COMMIT)) {
13655 13656 13657 13658 13659 13660 13661 13662 13663 13664 13665 13666 13667 13668 13669 13670
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("online commit not supported with this QEMU binary"));
        goto endjob;
    }

    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
        goto endjob;
    disk = vm->def->disks[idx];

    if (!disk->src) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk %s has no source file to be committed"),
                       disk->dst);
        goto endjob;
    }
13671 13672
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto endjob;
13673

13674 13675 13676 13677 13678 13679 13680 13681 13682 13683 13684 13685 13686 13687 13688 13689 13690 13691 13692 13693 13694 13695 13696 13697 13698 13699 13700 13701 13702 13703 13704 13705 13706 13707 13708 13709 13710 13711 13712
    if (!top) {
        top_canon = disk->src;
        top_meta = disk->backingChain;
    } else if (!(top_canon = virStorageFileChainLookup(disk->backingChain,
                                                       disk->src,
                                                       top, &top_meta,
                                                       &top_parent))) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("could not find top '%s' in chain for '%s'"),
                       top, path);
        goto endjob;
    }
    if (!top_meta || !top_meta->backingStore) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("top '%s' in chain for '%s' has no backing file"),
                       top, path);
        goto endjob;
    }
    if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW)) {
        base_canon = top_meta->backingStore;
    } else if (!(base_canon = virStorageFileChainLookup(top_meta, top_canon,
                                                        base, NULL, NULL))) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("could not find base '%s' below '%s' in chain "
                         "for '%s'"),
                       base ? base : "(default)", top_canon, path);
        goto endjob;
    }
    /* Note that this code exploits the fact that
     * virStorageFileChainLookup guarantees a simple pointer
     * comparison will work, rather than needing full-blown STREQ.  */
    if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) &&
        base_canon != top_meta->backingStore) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("base '%s' is not immediately below '%s' in chain "
                         "for '%s'"),
                       base, top_canon, path);
        goto endjob;
    }
13713

13714 13715 13716 13717 13718 13719 13720 13721 13722 13723 13724 13725 13726 13727
    /* For the commit to succeed, we must allow qemu to open both the
     * 'base' image and the parent of 'top' as read/write; 'top' might
     * not have a parent, or might already be read-write.  XXX It
     * would also be nice to revert 'base' to read-only, as well as
     * revoke access to files removed from the chain, when the commit
     * operation succeeds, but doing that requires tracking the
     * operation in XML across libvirtd restarts.  */
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
        goto endjob;
    }
E
Eric Blake 已提交
13728
    clean_access = true;
13729 13730 13731 13732 13733 13734 13735 13736 13737
    if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, base_canon,
                                          VIR_DISK_CHAIN_READ_WRITE) < 0 ||
        (top_parent && top_parent != disk->src &&
         qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk,
                                           top_parent,
                                           VIR_DISK_CHAIN_READ_WRITE) < 0))
        goto endjob;

    /* Start the commit operation.  */
13738
    qemuDomainObjEnterMonitor(driver, vm);
13739 13740
    ret = qemuMonitorBlockCommit(priv->mon, device, top_canon, base_canon,
                                 bandwidth);
13741 13742 13743
    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
13744
    if (ret < 0 && clean_access) {
13745 13746 13747 13748 13749 13750 13751 13752 13753 13754
        /* Revert access to read-only, if possible.  */
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, base_canon,
                                          VIR_DISK_CHAIN_READ_ONLY);
        if (top_parent && top_parent != disk->src)
            qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk,
                                              top_parent,
                                              VIR_DISK_CHAIN_READ_ONLY);
    }
    if (cgroup)
        virCgroupFree(&cgroup);
13755 13756 13757 13758 13759 13760 13761 13762
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    VIR_FREE(device);
    if (vm)
13763
        virObjectUnlock(vm);
13764 13765 13766
    return ret;
}

13767 13768 13769 13770 13771 13772
static int
qemuDomainOpenGraphics(virDomainPtr dom,
                       unsigned int idx,
                       int fd,
                       unsigned int flags)
{
13773
    virQEMUDriverPtr driver = dom->conn->privateData;
13774 13775 13776 13777 13778 13779 13780 13781 13782
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
    const char *protocol;

    virCheckFlags(VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH, -1);

    virUUIDFormat(dom->uuid, uuidstr);
13783
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
13784
    if (!vm) {
13785 13786
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13787 13788 13789 13790
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
13791 13792
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
13793 13794 13795 13796 13797 13798
        goto cleanup;
    }

    priv = vm->privateData;

    if (idx >= vm->def->ngraphics) {
13799 13800
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No graphics backend with index %d"), idx);
13801 13802 13803 13804 13805 13806 13807 13808 13809 13810
        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:
13811 13812 13813
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can only open VNC or SPICE graphics backends, not %s"),
                       virDomainGraphicsTypeToString(vm->def->graphics[idx]->type));
13814 13815 13816
        goto cleanup;
    }

13817
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
13818
        goto cleanup;
13819
    qemuDomainObjEnterMonitor(driver, vm);
13820 13821
    ret = qemuMonitorOpenGraphics(priv->mon, protocol, fd, "graphicsfd",
                                  (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH) != 0);
13822
    qemuDomainObjExitMonitor(driver, vm);
13823 13824 13825 13826 13827 13828 13829
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    if (vm)
13830
        virObjectUnlock(vm);
13831 13832 13833
    return ret;
}

13834 13835 13836 13837 13838 13839 13840
static int
qemuDomainSetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int nparams,
                         unsigned int flags)
{
13841
    virQEMUDriverPtr driver = dom->conn->privateData;
13842 13843 13844 13845
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo info;
E
Eric Blake 已提交
13846
    virDomainBlockIoTuneInfo *oldinfo;
13847 13848 13849 13850 13851
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    const char *device = NULL;
    int ret = -1;
    int i;
    int idx = -1;
E
Eric Blake 已提交
13852 13853
    bool set_bytes = false;
    bool set_iops = false;
13854
    virQEMUDriverConfigPtr cfg = NULL;
13855
    virCapsPtr caps = NULL;
13856 13857 13858

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
13859 13860 13861 13862 13863 13864 13865 13866 13867 13868 13869 13870 13871 13872 13873
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       NULL) < 0)
        return -1;
13874 13875 13876 13877

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

    virUUIDFormat(dom->uuid, uuidstr);
13878
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
13879
    if (!vm) {
13880 13881
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13882 13883
        goto cleanup;
    }
13884
    priv = vm->privateData;
13885 13886
    cfg = virQEMUDriverGetConfig(driver);

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

13890
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_IOTUNE)) {
13891 13892 13893
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block I/O throttling not supported with this "
                         "QEMU binary"));
13894 13895
        goto cleanup;
    }
13896

E
Eric Blake 已提交
13897
    device = qemuDiskPathToAlias(vm, disk, &idx);
13898 13899 13900 13901
    if (!device) {
        goto cleanup;
    }

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

13905
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
13906
                                        &persistentDef) < 0)
13907 13908 13909 13910 13911 13912 13913
        goto endjob;

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

        if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC)) {
            info.total_bytes_sec = param->value.ul;
E
Eric Blake 已提交
13914
            set_bytes = true;
13915 13916 13917
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC)) {
            info.read_bytes_sec = param->value.ul;
E
Eric Blake 已提交
13918
            set_bytes = true;
13919 13920 13921
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC)) {
            info.write_bytes_sec = param->value.ul;
E
Eric Blake 已提交
13922
            set_bytes = true;
13923 13924 13925
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC)) {
            info.total_iops_sec = param->value.ul;
E
Eric Blake 已提交
13926
            set_iops = true;
13927 13928 13929
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC)) {
            info.read_iops_sec = param->value.ul;
E
Eric Blake 已提交
13930
            set_iops = true;
13931 13932 13933
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC)) {
            info.write_iops_sec = param->value.ul;
E
Eric Blake 已提交
13934
            set_iops = true;
13935 13936 13937 13938 13939
        }
    }

    if ((info.total_bytes_sec && info.read_bytes_sec) ||
        (info.total_bytes_sec && info.write_bytes_sec)) {
13940 13941
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of bytes_sec cannot be set at the same time"));
13942 13943 13944 13945 13946
        goto endjob;
    }

    if ((info.total_iops_sec && info.read_iops_sec) ||
        (info.total_iops_sec && info.write_iops_sec)) {
13947 13948
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of iops_sec cannot be set at the same time"));
13949 13950 13951 13952
        goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
E
Eric Blake 已提交
13953 13954 13955 13956 13957 13958 13959 13960 13961 13962 13963 13964 13965 13966
        /* 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;
        }
13967
        qemuDomainObjEnterMonitor(driver, vm);
13968
        ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
13969
        qemuDomainObjExitMonitor(driver, vm);
L
Lei Li 已提交
13970 13971
        if (ret < 0)
            goto endjob;
13972
        vm->def->disks[idx]->blkdeviotune = info;
13973 13974 13975
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
13976 13977 13978 13979
        sa_assert(persistentDef);
        idx = virDomainDiskIndexByName(persistentDef, disk, true);
        if (idx < 0)
            goto endjob;
E
Eric Blake 已提交
13980 13981 13982 13983 13984 13985 13986 13987 13988 13989 13990
        oldinfo = &persistentDef->disks[idx]->blkdeviotune;
        if (!set_bytes) {
            info.total_bytes_sec = oldinfo->total_bytes_sec;
            info.read_bytes_sec = oldinfo->read_bytes_sec;
            info.write_bytes_sec = oldinfo->write_bytes_sec;
        }
        if (!set_iops) {
            info.total_iops_sec = oldinfo->total_iops_sec;
            info.read_iops_sec = oldinfo->read_iops_sec;
            info.write_iops_sec = oldinfo->write_iops_sec;
        }
13991
        persistentDef->disks[idx]->blkdeviotune = info;
13992
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
13993
        if (ret < 0) {
13994
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
13995 13996 13997 13998 13999 14000 14001 14002 14003 14004 14005 14006
                           _("Write to config file failed"));
            goto endjob;
        }
    }

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

cleanup:
    VIR_FREE(device);
    if (vm)
14007
        virObjectUnlock(vm);
14008
    virObjectUnref(caps);
14009
    virObjectUnref(cfg);
14010 14011 14012 14013 14014 14015 14016 14017 14018 14019
    return ret;
}

static int
qemuDomainGetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int *nparams,
                         unsigned int flags)
{
14020
    virQEMUDriverPtr driver = dom->conn->privateData;
14021 14022 14023 14024 14025 14026 14027 14028
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo reply;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    const char *device = NULL;
    int ret = -1;
    int i;
14029
    virCapsPtr caps = NULL;
14030 14031 14032 14033 14034 14035 14036 14037 14038

    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;

    virUUIDFormat(dom->uuid, uuidstr);
14039
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
14040
    if (!vm) {
14041 14042
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
14043 14044 14045
        goto cleanup;
    }

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

14049 14050 14051 14052 14053 14054 14055
    if ((*nparams) == 0) {
        /* Current number of parameters supported by QEMU Block I/O Throttling */
        *nparams = QEMU_NB_BLOCK_IO_TUNE_PARAM;
        ret = 0;
        goto cleanup;
    }

E
Eric Blake 已提交
14056
    device = qemuDiskPathToAlias(vm, disk, NULL);
14057 14058 14059 14060 14061

    if (!device) {
        goto cleanup;
    }

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

14065
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
14066
                                        &persistentDef) < 0)
14067 14068 14069 14070
        goto endjob;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        priv = vm->privateData;
14071
        qemuDomainObjEnterMonitor(driver, vm);
14072
        ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply);
14073
        qemuDomainObjExitMonitor(driver, vm);
14074 14075 14076 14077 14078 14079 14080 14081 14082 14083 14084 14085 14086 14087
        if (ret < 0)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        int idx = virDomainDiskIndexByName(vm->def, disk, true);
        if (idx < 0)
            goto endjob;
        reply = persistentDef->disks[idx]->blkdeviotune;
    }

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

14088
        switch (i) {
14089
        case 0:
14090 14091 14092 14093
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_bytes_sec) < 0)
14094 14095 14096
                goto endjob;
            break;
        case 1:
14097 14098 14099 14100
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_bytes_sec) < 0)
14101 14102 14103
                goto endjob;
            break;
        case 2:
14104 14105 14106 14107
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_bytes_sec) < 0)
14108 14109 14110
                goto endjob;
            break;
        case 3:
14111 14112 14113 14114
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_iops_sec) < 0)
14115 14116 14117
                goto endjob;
            break;
        case 4:
14118 14119 14120 14121
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_iops_sec) < 0)
14122 14123 14124
                goto endjob;
            break;
        case 5:
14125 14126 14127 14128
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_iops_sec) < 0)
14129 14130 14131 14132 14133 14134 14135 14136 14137 14138 14139 14140 14141 14142 14143 14144 14145 14146
                goto endjob;
            break;
        default:
            break;
        }
    }

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

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

cleanup:
    VIR_FREE(device);
    if (vm)
14147
        virObjectUnlock(vm);
14148
    virObjectUnref(caps);
14149 14150
    return ret;
}
14151

14152 14153 14154 14155 14156 14157
static int
qemuDomainGetDiskErrors(virDomainPtr dom,
                        virDomainDiskErrorPtr errors,
                        unsigned int nerrors,
                        unsigned int flags)
{
14158
    virQEMUDriverPtr driver = dom->conn->privateData;
14159 14160 14161 14162 14163 14164 14165 14166 14167
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virHashTablePtr table = NULL;
    int ret = -1;
    int i;
    int n = 0;

    virCheckFlags(0, -1);

14168
    if (!(vm = qemuDomObjFromDomain(dom)))
14169 14170 14171 14172 14173 14174 14175 14176
        goto cleanup;

    priv = vm->privateData;

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

    if (!virDomainObjIsActive(vm)) {
14177 14178
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14179 14180 14181 14182 14183 14184 14185 14186 14187 14188 14189 14190 14191 14192 14193 14194 14195 14196 14197 14198 14199 14200 14201 14202 14203 14204 14205 14206 14207 14208 14209 14210 14211 14212 14213 14214 14215 14216 14217 14218
        goto endjob;
    }

    if (!errors) {
        ret = vm->def->ndisks;
        goto endjob;
    }

    qemuDomainObjEnterMonitor(driver, vm);
    table = qemuMonitorGetBlockInfo(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);
    if (!table)
        goto endjob;

    for (i = n = 0; i < vm->def->ndisks; i++) {
        struct qemuDomainDiskInfo *info;
        virDomainDiskDefPtr disk = vm->def->disks[i];

        if ((info = virHashLookup(table, disk->info.alias)) &&
            info->io_status != VIR_DOMAIN_DISK_ERROR_NONE) {
            if (n == nerrors)
                break;

            if (!(errors[n].disk = strdup(disk->dst))) {
                virReportOOMError();
                goto endjob;
            }
            errors[n].error = info->io_status;
            n++;
        }
    }

    ret = n;

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

cleanup:
    if (vm)
14219
        virObjectUnlock(vm);
14220 14221 14222 14223 14224 14225 14226 14227
    virHashFree(table);
    if (ret < 0) {
        for (i = 0; i < n; i++)
            VIR_FREE(errors[i].disk);
    }
    return ret;
}

14228 14229 14230 14231 14232 14233 14234 14235
static int
qemuDomainSetMetadata(virDomainPtr dom,
                      int type,
                      const char *metadata,
                      const char *key ATTRIBUTE_UNUSED,
                      const char *uri ATTRIBUTE_UNUSED,
                      unsigned int flags)
{
14236
    virQEMUDriverPtr driver = dom->conn->privateData;
14237 14238 14239
    virDomainObjPtr vm;
    virDomainDefPtr persistentDef;
    int ret = -1;
14240
    virQEMUDriverConfigPtr cfg = NULL;
14241
    virCapsPtr caps = NULL;
14242 14243 14244 14245

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

14246
    if (!(vm = qemuDomObjFromDomain(dom)))
14247 14248
        goto cleanup;

14249 14250
    cfg = virQEMUDriverGetConfig(driver);

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

14254
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
14255 14256 14257 14258 14259 14260 14261 14262 14263 14264 14265 14266 14267 14268 14269 14270 14271 14272
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        switch ((virDomainMetadataType) type) {
        case VIR_DOMAIN_METADATA_DESCRIPTION:
            VIR_FREE(vm->def->description);
            if (metadata &&
                !(vm->def->description = strdup(metadata)))
                goto no_memory;
            break;
        case VIR_DOMAIN_METADATA_TITLE:
            VIR_FREE(vm->def->title);
            if (metadata &&
                !(vm->def->title = strdup(metadata)))
                goto no_memory;
            break;
        case VIR_DOMAIN_METADATA_ELEMENT:
14273
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
14274
                           _("QEmu driver does not support modifying "
14275
                             "<metadata> element"));
14276 14277 14278
            goto cleanup;
            break;
        default:
14279 14280
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("unknown metadata type"));
14281 14282 14283 14284 14285 14286 14287 14288 14289 14290 14291 14292 14293 14294 14295 14296 14297 14298 14299 14300
            goto cleanup;
            break;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        switch ((virDomainMetadataType) type) {
        case VIR_DOMAIN_METADATA_DESCRIPTION:
            VIR_FREE(persistentDef->description);
            if (metadata &&
                !(persistentDef->description = strdup(metadata)))
                goto no_memory;
            break;
        case VIR_DOMAIN_METADATA_TITLE:
            VIR_FREE(persistentDef->title);
            if (metadata &&
                !(persistentDef->title = strdup(metadata)))
                goto no_memory;
            break;
        case VIR_DOMAIN_METADATA_ELEMENT:
14301
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
14302
                           _("QEMU driver does not support "
14303
                             "<metadata> element"));
14304 14305
            goto cleanup;
         default:
14306 14307
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("unknown metadata type"));
14308 14309 14310 14311
            goto cleanup;
            break;
        }

14312
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
14313 14314 14315 14316 14317 14318 14319
            goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
14320
        virObjectUnlock(vm);
14321
    virObjectUnref(caps);
14322
    virObjectUnref(cfg);
14323 14324 14325 14326 14327 14328 14329 14330 14331 14332 14333 14334
    return ret;
no_memory:
    virReportOOMError();
    goto cleanup;
}

static char *
qemuDomainGetMetadata(virDomainPtr dom,
                      int type,
                      const char *uri ATTRIBUTE_UNUSED,
                      unsigned int flags)
{
14335
    virQEMUDriverPtr driver = dom->conn->privateData;
14336 14337 14338 14339
    virDomainObjPtr vm;
    virDomainDefPtr def;
    char *ret = NULL;
    char *field = NULL;
14340
    virCapsPtr caps = NULL;
14341 14342 14343 14344

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, NULL);

14345
    if (!(vm = qemuDomObjFromDomain(dom)))
14346 14347
        goto cleanup;

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

14351
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags, &def) < 0)
14352 14353 14354 14355 14356 14357 14358 14359 14360 14361 14362 14363 14364 14365
        goto cleanup;

    /* use correct domain definition according to flags */
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
        def = vm->def;

    switch ((virDomainMetadataType) type) {
    case VIR_DOMAIN_METADATA_DESCRIPTION:
        field = def->description;
        break;
    case VIR_DOMAIN_METADATA_TITLE:
        field = def->title;
        break;
    case VIR_DOMAIN_METADATA_ELEMENT:
14366
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
14367
                       _("QEMU driver does not support "
14368
                         "<metadata> element"));
14369 14370 14371
        goto cleanup;
        break;
    default:
14372 14373
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("unknown metadata type"));
14374 14375 14376 14377 14378
        goto cleanup;
        break;
    }

    if (!field) {
14379 14380
        virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                       _("Requested metadata element is not present"));
14381 14382 14383 14384 14385 14386 14387 14388 14389 14390
        goto cleanup;
    }

    if (!(ret = strdup(field))) {
        virReportOOMError();
        goto cleanup;
    }

cleanup:
    if (vm)
14391
        virObjectUnlock(vm);
14392
    virObjectUnref(caps);
14393 14394 14395
    return ret;
}

14396 14397 14398 14399 14400 14401 14402 14403 14404 14405
/* qemuDomainGetCPUStats() with start_cpu == -1 */
static int
qemuDomainGetTotalcpuStats(virCgroupPtr group,
                           virTypedParameterPtr params,
                           int nparams)
{
    unsigned long long cpu_time;
    int ret;

    if (nparams == 0) /* return supported number of params */
E
Eric Blake 已提交
14406
        return QEMU_NB_TOTAL_CPU_STAT_PARAM;
14407 14408 14409 14410 14411 14412 14413
    /* entry 0 is cputime */
    ret = virCgroupGetCpuacctUsage(group, &cpu_time);
    if (ret < 0) {
        virReportSystemError(-ret, "%s", _("unable to get cpu account"));
        return -1;
    }

E
Eric Blake 已提交
14414 14415 14416 14417 14418 14419 14420 14421 14422 14423 14424 14425 14426 14427 14428 14429 14430 14431 14432 14433 14434 14435 14436 14437 14438 14439 14440 14441 14442
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_CPU_STATS_CPUTIME,
                                VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
        return -1;

    if (nparams > 1) {
        unsigned long long user;
        unsigned long long sys;

        ret = virCgroupGetCpuacctStat(group, &user, &sys);
        if (ret < 0) {
            virReportSystemError(-ret, "%s", _("unable to get cpu account"));
            return -1;
        }

        if (virTypedParameterAssign(&params[1],
                                    VIR_DOMAIN_CPU_STATS_USERTIME,
                                    VIR_TYPED_PARAM_ULLONG, user) < 0)
            return -1;
        if (nparams > 2 &&
            virTypedParameterAssign(&params[2],
                                    VIR_DOMAIN_CPU_STATS_SYSTEMTIME,
                                    VIR_TYPED_PARAM_ULLONG, sys) < 0)
            return -1;

        if (nparams > QEMU_NB_TOTAL_CPU_STAT_PARAM)
            nparams = QEMU_NB_TOTAL_CPU_STAT_PARAM;
    }

    return nparams;
14443 14444
}

14445 14446 14447 14448 14449 14450 14451 14452 14453 14454 14455 14456 14457 14458 14459 14460 14461 14462 14463 14464 14465 14466 14467 14468 14469 14470 14471 14472 14473 14474 14475
/* This function gets the sums of cpu time consumed by all vcpus.
 * For example, if there are 4 physical cpus, and 2 vcpus in a domain,
 * then for each vcpu, the cpuacct.usage_percpu looks like this:
 *   t0 t1 t2 t3
 * and we have 2 groups of such data:
 *   v\p   0   1   2   3
 *   0   t00 t01 t02 t03
 *   1   t10 t11 t12 t13
 * for each pcpu, the sum is cpu time consumed by all vcpus.
 *   s0 = t00 + t10
 *   s1 = t01 + t11
 *   s2 = t02 + t12
 *   s3 = t03 + t13
 */
static int
getSumVcpuPercpuStats(virCgroupPtr group,
                      unsigned int nvcpu,
                      unsigned long long *sum_cpu_time,
                      unsigned int num)
{
    int ret = -1;
    int i;
    char *buf = NULL;
    virCgroupPtr group_vcpu = NULL;

    for (i = 0; i < nvcpu; i++) {
        char *pos;
        unsigned long long tmp;
        int j;

        if (virCgroupForVcpu(group, i, &group_vcpu, 0) < 0) {
14476 14477
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("error accessing cgroup cpuacct for vcpu"));
14478 14479 14480
            goto cleanup;
        }

14481
        if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0)
14482 14483 14484 14485 14486
            goto cleanup;

        pos = buf;
        for (j = 0; j < num; j++) {
            if (virStrToLong_ull(pos, &pos, 10, &tmp) < 0) {
14487 14488
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cpuacct parse error"));
14489 14490 14491 14492 14493 14494 14495 14496 14497 14498 14499 14500 14501 14502 14503 14504
                goto cleanup;
            }
            sum_cpu_time[j] += tmp;
        }

        virCgroupFree(&group_vcpu);
        VIR_FREE(buf);
    }

    ret = 0;
cleanup:
    virCgroupFree(&group_vcpu);
    VIR_FREE(buf);
    return ret;
}

14505
static int
14506
qemuDomainGetPercpuStats(virDomainObjPtr vm,
14507 14508 14509 14510 14511 14512 14513
                         virCgroupPtr group,
                         virTypedParameterPtr params,
                         unsigned int nparams,
                         int start_cpu,
                         unsigned int ncpus)
{
    int rv = -1;
14514
    int i, id, max_id;
14515 14516
    char *pos;
    char *buf = NULL;
14517 14518 14519 14520
    unsigned long long *sum_cpu_time = NULL;
    unsigned long long *sum_cpu_pos;
    unsigned int n = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
14521 14522
    virTypedParameterPtr ent;
    int param_idx;
14523
    unsigned long long cpu_time;
14524 14525 14526

    /* return the number of supported params */
    if (nparams == 0 && ncpus != 0)
14527
        return QEMU_NB_PER_CPU_STAT_PARAM;
14528

14529 14530 14531
    /* To parse account file, we need to know how many cpus are present.  */
    max_id = nodeGetCPUCount();
    if (max_id < 0)
14532 14533 14534
        return rv;

    if (ncpus == 0) { /* returns max cpu ID */
14535
        rv = max_id;
14536 14537 14538 14539
        goto cleanup;
    }

    if (start_cpu > max_id) {
14540 14541 14542
        virReportError(VIR_ERR_INVALID_ARG,
                       _("start_cpu %d larger than maximum of %d"),
                       start_cpu, max_id);
14543 14544 14545 14546 14547 14548 14549
        goto cleanup;
    }

    /* we get percpu cputime accounting info. */
    if (virCgroupGetCpuacctPercpuUsage(group, &buf))
        goto cleanup;
    pos = buf;
14550
    memset(params, 0, nparams * ncpus);
14551

14552 14553 14554
    /* return percpu cputime in index 0 */
    param_idx = 0;

14555
    /* number of cpus to compute */
14556 14557 14558
    if (start_cpu >= max_id - ncpus)
        id = max_id - 1;
    else
14559
        id = start_cpu + ncpus - 1;
14560

14561
    for (i = 0; i <= id; i++) {
14562
        if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) {
14563
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
14564
                           _("cpuacct parse error"));
14565
            goto cleanup;
14566 14567
        } else {
            n++;
14568 14569 14570
        }
        if (i < start_cpu)
            continue;
14571
        ent = &params[(i - start_cpu) * nparams + param_idx];
E
Eric Blake 已提交
14572 14573 14574
        if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
            goto cleanup;
14575
    }
14576 14577 14578 14579 14580 14581 14582 14583 14584 14585 14586 14587 14588 14589 14590

    /* return percpu vcputime in index 1 */
    if (++param_idx >= nparams) {
        rv = nparams;
        goto cleanup;
    }

    if (VIR_ALLOC_N(sum_cpu_time, n) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    if (getSumVcpuPercpuStats(group, priv->nvcpupids, sum_cpu_time, n) < 0)
        goto cleanup;

    sum_cpu_pos = sum_cpu_time;
14591
    for (i = 0; i <= id; i++) {
14592
        cpu_time = *(sum_cpu_pos++);
14593 14594 14595 14596 14597 14598 14599 14600 14601 14602
        if (i < start_cpu)
            continue;
        if (virTypedParameterAssign(&params[(i - start_cpu) * nparams +
                                            param_idx],
                                    VIR_DOMAIN_CPU_STATS_VCPUTIME,
                                    VIR_TYPED_PARAM_ULLONG,
                                    cpu_time) < 0)
            goto cleanup;
    }

14603 14604
    rv = param_idx + 1;
cleanup:
14605
    VIR_FREE(sum_cpu_time);
14606 14607 14608 14609 14610 14611 14612 14613 14614 14615 14616 14617 14618
    VIR_FREE(buf);
    return rv;
}


static int
qemuDomainGetCPUStats(virDomainPtr domain,
                virTypedParameterPtr params,
                unsigned int nparams,
                int start_cpu,
                unsigned int ncpus,
                unsigned int flags)
{
14619
    virQEMUDriverPtr driver = domain->conn->privateData;
14620 14621 14622 14623 14624 14625 14626
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    bool isActive;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

14627
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
14628
    if (vm == NULL) {
14629 14630
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), domain->uuid);
14631 14632 14633 14634 14635
        goto cleanup;
    }

    isActive = virDomainObjIsActive(vm);
    if (!isActive) {
14636 14637
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
14638 14639 14640 14641
        goto cleanup;
    }

    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUACCT)) {
14642 14643
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPUACCT controller is not mounted"));
14644 14645 14646 14647
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
14648 14649
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
14650 14651 14652 14653 14654 14655
        goto cleanup;
    }

    if (start_cpu == -1)
        ret = qemuDomainGetTotalcpuStats(group, params, nparams);
    else
14656
        ret = qemuDomainGetPercpuStats(vm, group, params, nparams,
14657 14658 14659 14660
                                       start_cpu, ncpus);
cleanup:
    virCgroupFree(&group);
    if (vm)
14661
        virObjectUnlock(vm);
14662 14663 14664
    return ret;
}

14665 14666 14667 14668 14669 14670
static int
qemuDomainPMSuspendForDuration(virDomainPtr dom,
                               unsigned int target,
                               unsigned long long duration,
                               unsigned int flags)
{
14671
    virQEMUDriverPtr driver = dom->conn->privateData;
14672 14673 14674 14675 14676 14677 14678
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    if (duration) {
14679 14680
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Duration not supported. Use 0 for now"));
14681 14682 14683 14684 14685 14686
        return -1;
    }

    if (!(target == VIR_NODE_SUSPEND_TARGET_MEM ||
          target == VIR_NODE_SUSPEND_TARGET_DISK ||
          target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
14687 14688 14689
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unknown suspend target: %u"),
                       target);
14690 14691 14692
        return -1;
    }

14693
    if (!(vm = qemuDomObjFromDomain(dom)))
14694 14695 14696 14697
        goto cleanup;

    priv = vm->privateData;

14698
    if (!virDomainObjIsActive(vm)) {
14699 14700
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14701 14702 14703
        goto cleanup;
    }

14704
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP) &&
14705 14706
        (target == VIR_NODE_SUSPEND_TARGET_MEM ||
         target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
14707 14708 14709
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Unable to suspend domain due to "
                         "missing system_wakeup monitor command"));
O
Osier Yang 已提交
14710
        goto cleanup;
14711 14712
    }

14713 14714 14715 14716 14717 14718 14719 14720 14721 14722 14723 14724 14725 14726 14727 14728 14729
    if (vm->def->pm.s3 || vm->def->pm.s4) {
        if (vm->def->pm.s3 == VIR_DOMAIN_PM_STATE_DISABLED &&
            (target == VIR_NODE_SUSPEND_TARGET_MEM ||
             target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("S3 state is disabled for this domain"));
            goto cleanup;
        }

        if (vm->def->pm.s4 == VIR_DOMAIN_PM_STATE_DISABLED &&
            target == VIR_NODE_SUSPEND_TARGET_DISK) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("S4 state is disabled for this domain"));
            goto cleanup;
        }
    }

14730
    if (priv->agentError) {
14731 14732 14733
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
14734 14735 14736 14737
        goto cleanup;
    }

    if (!priv->agent) {
14738 14739
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
14740 14741 14742 14743 14744 14745 14746
        goto cleanup;
    }

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

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

14752
    qemuDomainObjEnterAgent(vm);
14753
    ret = qemuAgentSuspend(priv->agent, target);
14754
    qemuDomainObjExitAgent(vm);
14755 14756 14757 14758 14759 14760 14761

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

cleanup:
    if (vm)
14762
        virObjectUnlock(vm);
14763 14764 14765
    return ret;
}

14766 14767 14768 14769
static int
qemuDomainPMWakeup(virDomainPtr dom,
                   unsigned int flags)
{
14770
    virQEMUDriverPtr driver = dom->conn->privateData;
14771 14772 14773 14774 14775 14776
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

14777
    if (!(vm = qemuDomObjFromDomain(dom)))
14778 14779 14780 14781 14782 14783
        goto cleanup;

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

    if (!virDomainObjIsActive(vm)) {
14784 14785
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14786 14787 14788 14789 14790
        goto endjob;
    }

    priv = vm->privateData;

14791
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP)) {
14792 14793 14794
       virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                      _("Unable to wake up domain due to "
                        "missing system_wakeup monitor command"));
14795 14796 14797 14798 14799 14800 14801 14802 14803 14804 14805 14806 14807
       goto endjob;
    }

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

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

cleanup:
    if (vm)
14808
        virObjectUnlock(vm);
14809 14810 14811
    return ret;
}

14812 14813 14814 14815 14816
static int
qemuListAllDomains(virConnectPtr conn,
                   virDomainPtr **domains,
                   unsigned int flags)
{
14817
    virQEMUDriverPtr driver = conn->privateData;
14818 14819
    int ret = -1;

O
Osier Yang 已提交
14820
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
14821

14822
    ret = virDomainObjListExport(driver->domains, conn, domains, flags);
14823 14824 14825 14826

    return ret;
}

M
MATSUDA Daiki 已提交
14827
static char *
14828
qemuDomainAgentCommand(virDomainPtr domain,
M
MATSUDA Daiki 已提交
14829 14830 14831 14832
                       const char *cmd,
                       int timeout,
                       unsigned int flags)
{
14833
    virQEMUDriverPtr driver = domain->conn->privateData;
M
MATSUDA Daiki 已提交
14834 14835 14836 14837 14838 14839 14840
    virDomainObjPtr vm;
    int ret = -1;
    char *result = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, NULL);

14841
    if (!(vm = qemuDomObjFromDomain(domain)))
M
MATSUDA Daiki 已提交
14842 14843 14844 14845 14846 14847 14848 14849 14850 14851 14852
        goto cleanup;

    priv = vm->privateData;

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

    if (priv->agentError) {
14853 14854 14855
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
M
MATSUDA Daiki 已提交
14856 14857 14858 14859 14860 14861 14862 14863 14864 14865 14866 14867 14868 14869 14870 14871 14872 14873
        goto cleanup;
    }

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

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

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

14874
    qemuDomainObjEnterAgent(vm);
M
MATSUDA Daiki 已提交
14875
    ret = qemuAgentArbitraryCommand(priv->agent, cmd, &result, timeout);
14876
    qemuDomainObjExitAgent(vm);
M
MATSUDA Daiki 已提交
14877 14878 14879 14880 14881 14882 14883 14884 14885 14886 14887 14888 14889
    if (ret < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to execute agent command"));
        goto endjob;
    }

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

cleanup:
    if (vm)
14890
        virObjectUnlock(vm);
M
MATSUDA Daiki 已提交
14891 14892 14893
    return result;
}

M
Michal Privoznik 已提交
14894 14895 14896 14897 14898 14899
static int
qemuDomainFSTrim(virDomainPtr dom,
                 const char *mountPoint,
                 unsigned long long minimum,
                 unsigned int flags)
{
14900
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Michal Privoznik 已提交
14901 14902 14903 14904 14905 14906 14907 14908 14909 14910 14911 14912 14913 14914 14915 14916 14917 14918 14919 14920 14921 14922 14923 14924 14925 14926 14927 14928 14929 14930 14931 14932 14933 14934 14935 14936 14937 14938 14939 14940 14941 14942 14943 14944 14945 14946
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

    if (mountPoint) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Specifying mount point "
                         "is not supported for now"));
        return -1;
    }

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

    priv = vm->privateData;

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

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

    if (priv->agentError) {
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
        goto cleanup;
    }

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

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

14947
    qemuDomainObjEnterAgent(vm);
M
Michal Privoznik 已提交
14948
    ret = qemuAgentFSTrim(priv->agent, minimum);
14949
    qemuDomainObjExitAgent(vm);
M
Michal Privoznik 已提交
14950 14951 14952 14953 14954 14955 14956

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

cleanup:
    if (vm)
14957
        virObjectUnlock(vm);
M
Michal Privoznik 已提交
14958 14959 14960
    return ret;
}

14961
static virDriver qemuDriver = {
14962
    .no = VIR_DRV_QEMU,
14963
    .name = QEMU_DRIVER_NAME,
14964 14965 14966 14967 14968
    .open = qemuOpen, /* 0.2.0 */
    .close = qemuClose, /* 0.2.0 */
    .supports_feature = qemuSupportsFeature, /* 0.5.0 */
    .type = qemuGetType, /* 0.2.0 */
    .version = qemuGetVersion, /* 0.2.0 */
14969 14970
    .getHostname = virGetHostname, /* 0.3.3 */
    .getSysinfo = qemuGetSysinfo, /* 0.8.8 */
14971
    .getMaxVcpus = qemuGetMaxVCPUs, /* 0.2.1 */
14972
    .nodeGetInfo = nodeGetInfo, /* 0.2.0 */
14973 14974 14975
    .getCapabilities = qemuGetCapabilities, /* 0.2.1 */
    .listDomains = qemuListDomains, /* 0.2.0 */
    .numOfDomains = qemuNumDomains, /* 0.2.0 */
14976
    .listAllDomains = qemuListAllDomains, /* 0.9.13 */
14977 14978 14979 14980 14981 14982
    .domainCreateXML = qemuDomainCreate, /* 0.2.0 */
    .domainLookupByID = qemuDomainLookupByID, /* 0.2.0 */
    .domainLookupByUUID = qemuDomainLookupByUUID, /* 0.2.0 */
    .domainLookupByName = qemuDomainLookupByName, /* 0.2.0 */
    .domainSuspend = qemuDomainSuspend, /* 0.2.0 */
    .domainResume = qemuDomainResume, /* 0.2.0 */
14983
    .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
14984
    .domainShutdownFlags = qemuDomainShutdownFlags, /* 0.9.10 */
14985
    .domainReboot = qemuDomainReboot, /* 0.9.3 */
14986
    .domainReset = qemuDomainReset, /* 0.9.7 */
14987 14988
    .domainDestroy = qemuDomainDestroy, /* 0.2.0 */
    .domainDestroyFlags = qemuDomainDestroyFlags, /* 0.9.4 */
14989
    .domainGetOSType = qemuDomainGetOSType, /* 0.2.2 */
14990
    .domainGetMaxMemory = qemuDomainGetMaxMemory, /* 0.4.2 */
14991 14992 14993
    .domainSetMaxMemory = qemuDomainSetMaxMemory, /* 0.4.2 */
    .domainSetMemory = qemuDomainSetMemory, /* 0.4.2 */
    .domainSetMemoryFlags = qemuDomainSetMemoryFlags, /* 0.9.0 */
14994 14995 14996 14997
    .domainSetMemoryParameters = qemuDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */
    .domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */
    .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */
14998
    .domainGetInfo = qemuDomainGetInfo, /* 0.2.0 */
14999
    .domainGetState = qemuDomainGetState, /* 0.9.2 */
15000
    .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */
15001 15002
    .domainSave = qemuDomainSave, /* 0.2.0 */
    .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */
15003
    .domainRestore = qemuDomainRestore, /* 0.2.0 */
15004
    .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */
15005 15006
    .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */
    .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */
15007
    .domainCoreDump = qemuDomainCoreDump, /* 0.7.0 */
15008
    .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */
15009 15010
    .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */
    .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */
15011 15012 15013 15014 15015 15016 15017 15018 15019
    .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 已提交
15020
    .domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
15021
    .nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */
15022 15023 15024
    .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */
    .domainXMLFromNative = qemuDomainXMLFromNative, /* 0.6.4 */
    .domainXMLToNative = qemuDomainXMLToNative, /* 0.6.4 */
15025 15026
    .listDefinedDomains = qemuListDefinedDomains, /* 0.2.0 */
    .numOfDefinedDomains = qemuNumDefinedDomains, /* 0.2.0 */
15027 15028
    .domainCreate = qemuDomainStart, /* 0.2.0 */
    .domainCreateWithFlags = qemuDomainStartWithFlags, /* 0.8.2 */
15029 15030
    .domainDefineXML = qemuDomainDefine, /* 0.2.0 */
    .domainUndefine = qemuDomainUndefine, /* 0.2.0 */
15031
    .domainUndefineFlags = qemuDomainUndefineFlags, /* 0.9.4 */
15032 15033 15034 15035 15036
    .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 */
15037 15038
    .domainGetAutostart = qemuDomainGetAutostart, /* 0.2.1 */
    .domainSetAutostart = qemuDomainSetAutostart, /* 0.2.1 */
15039 15040
    .domainGetSchedulerType = qemuGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = qemuGetSchedulerParameters, /* 0.7.0 */
15041
    .domainGetSchedulerParametersFlags = qemuGetSchedulerParametersFlags, /* 0.9.2 */
15042
    .domainSetSchedulerParameters = qemuSetSchedulerParameters, /* 0.7.0 */
15043
    .domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */
15044
    .domainMigratePerform = qemuDomainMigratePerform, /* 0.5.0 */
15045
    .domainBlockResize = qemuDomainBlockResize, /* 0.9.8 */
15046 15047
    .domainBlockStats = qemuDomainBlockStats, /* 0.4.1 */
    .domainBlockStatsFlags = qemuDomainBlockStatsFlags, /* 0.9.5 */
15048 15049 15050 15051
    .domainInterfaceStats = qemuDomainInterfaceStats, /* 0.4.1 */
    .domainMemoryStats = qemuDomainMemoryStats, /* 0.7.5 */
    .domainBlockPeek = qemuDomainBlockPeek, /* 0.4.4 */
    .domainMemoryPeek = qemuDomainMemoryPeek, /* 0.4.4 */
15052
    .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
15053
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
15054
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
15055 15056 15057 15058
    .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.4.4 */
    .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.4.4 */
    .domainEventRegister = qemuDomainEventRegister, /* 0.5.0 */
    .domainEventDeregister = qemuDomainEventDeregister, /* 0.5.0 */
15059 15060 15061 15062 15063 15064
    .domainMigratePrepare2 = qemuDomainMigratePrepare2, /* 0.5.0 */
    .domainMigrateFinish2 = qemuDomainMigrateFinish2, /* 0.5.0 */
    .nodeDeviceDettach = qemuNodeDeviceDettach, /* 0.6.1 */
    .nodeDeviceReAttach = qemuNodeDeviceReAttach, /* 0.6.1 */
    .nodeDeviceReset = qemuNodeDeviceReset, /* 0.6.1 */
    .domainMigratePrepareTunnel = qemuDomainMigratePrepareTunnel, /* 0.7.2 */
15065 15066 15067 15068 15069 15070 15071 15072
    .isEncrypted = qemuIsEncrypted, /* 0.7.3 */
    .isSecure = qemuIsSecure, /* 0.7.3 */
    .domainIsActive = qemuDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = qemuDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = qemuDomainIsUpdated, /* 0.8.6 */
    .cpuCompare = qemuCPUCompare, /* 0.7.5 */
    .cpuBaseline = qemuCPUBaseline, /* 0.7.7 */
    .domainGetJobInfo = qemuDomainGetJobInfo, /* 0.7.7 */
15073
    .domainGetJobStats = qemuDomainGetJobStats, /* 1.0.3 */
15074 15075
    .domainAbortJob = qemuDomainAbortJob, /* 0.7.7 */
    .domainMigrateSetMaxDowntime = qemuDomainMigrateSetMaxDowntime, /* 0.8.0 */
15076 15077
    .domainMigrateGetCompressionCache = qemuDomainMigrateGetCompressionCache, /* 1.0.3 */
    .domainMigrateSetCompressionCache = qemuDomainMigrateSetCompressionCache, /* 1.0.3 */
15078
    .domainMigrateSetMaxSpeed = qemuDomainMigrateSetMaxSpeed, /* 0.9.0 */
15079
    .domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
15080 15081 15082 15083 15084 15085 15086 15087 15088
    .domainEventRegisterAny = qemuDomainEventRegisterAny, /* 0.8.0 */
    .domainEventDeregisterAny = qemuDomainEventDeregisterAny, /* 0.8.0 */
    .domainManagedSave = qemuDomainManagedSave, /* 0.8.0 */
    .domainHasManagedSaveImage = qemuDomainHasManagedSaveImage, /* 0.8.0 */
    .domainManagedSaveRemove = qemuDomainManagedSaveRemove, /* 0.8.0 */
    .domainSnapshotCreateXML = qemuDomainSnapshotCreateXML, /* 0.8.0 */
    .domainSnapshotGetXMLDesc = qemuDomainSnapshotGetXMLDesc, /* 0.8.0 */
    .domainSnapshotNum = qemuDomainSnapshotNum, /* 0.8.0 */
    .domainSnapshotListNames = qemuDomainSnapshotListNames, /* 0.8.0 */
15089
    .domainListAllSnapshots = qemuDomainListAllSnapshots, /* 0.9.13 */
15090 15091
    .domainSnapshotNumChildren = qemuDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = qemuDomainSnapshotListChildrenNames, /* 0.9.7 */
15092
    .domainSnapshotListAllChildren = qemuDomainSnapshotListAllChildren, /* 0.9.13 */
15093 15094
    .domainSnapshotLookupByName = qemuDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = qemuDomainHasCurrentSnapshot, /* 0.8.0 */
15095
    .domainSnapshotGetParent = qemuDomainSnapshotGetParent, /* 0.9.7 */
15096
    .domainSnapshotCurrent = qemuDomainSnapshotCurrent, /* 0.8.0 */
15097 15098
    .domainSnapshotIsCurrent = qemuDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = qemuDomainSnapshotHasMetadata, /* 0.9.13 */
15099 15100 15101
    .domainRevertToSnapshot = qemuDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = qemuDomainSnapshotDelete, /* 0.8.0 */
    .qemuDomainMonitorCommand = qemuDomainMonitorCommand, /* 0.8.3 */
15102
    .qemuDomainAttach = qemuDomainAttach, /* 0.9.4 */
15103
    .qemuDomainArbitraryAgentCommand = qemuDomainAgentCommand, /* 0.10.0 */
15104
    .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */
15105
    .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */
15106
    .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */
15107 15108 15109 15110 15111 15112
    .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 */
15113
    .domainSendKey = qemuDomainSendKey, /* 0.9.4 */
15114 15115 15116 15117
    .domainBlockJobAbort = qemuDomainBlockJobAbort, /* 0.9.4 */
    .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
    .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
    .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
15118
    .domainBlockRebase = qemuDomainBlockRebase, /* 0.9.10 */
15119
    .domainBlockCommit = qemuDomainBlockCommit, /* 1.0.0 */
15120
    .isAlive = qemuIsAlive, /* 0.9.8 */
15121
    .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
15122 15123
    .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
    .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
15124 15125
    .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */
    .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
15126 15127
    .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
    .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
15128
    .domainGetDiskErrors = qemuDomainGetDiskErrors, /* 0.9.10 */
15129 15130
    .domainSetMetadata = qemuDomainSetMetadata, /* 0.9.10 */
    .domainGetMetadata = qemuDomainGetMetadata, /* 0.9.10 */
15131
    .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
15132
    .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
15133
    .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
15134 15135
    .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */
15136
    .nodeGetCPUMap = nodeGetCPUMap, /* 1.0.0 */
M
Michal Privoznik 已提交
15137
    .domainFSTrim = qemuDomainFSTrim, /* 1.0.1 */
15138
    .domainOpenChannel = qemuDomainOpenChannel, /* 1.0.2 */
15139 15140 15141
};


15142
static virStateDriver qemuStateDriver = {
15143
    .name = "QEMU",
15144 15145 15146
    .initialize = qemuStartup,
    .cleanup = qemuShutdown,
    .reload = qemuReload,
15147
    .stop = qemuStop,
15148
};
15149

15150
int qemuRegister(void) {
15151 15152 15153 15154
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
    return 0;
}