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->xmlconf,
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 727 728
    if (!(qemu_driver->xmlconf = virQEMUDriverCreateXMLConf()))
        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 769
    if (virDomainObjListLoadAllConfigs(qemu_driver->domains,
                                       qemu_driver->caps,
770
                                       qemu_driver->xmlconf,
771 772 773 774
                                       cfg->stateDir,
                                       NULL,
                                       1, QEMU_EXPECTED_VIRT_TYPES,
                                       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 794
    if (virDomainObjListLoadAllConfigs(qemu_driver->domains,
                                       qemu_driver->caps,
795
                                       qemu_driver->xmlconf,
796 797 798 799
                                       cfg->configDir,
                                       cfg->autostartDir,
                                       0, QEMU_EXPECTED_VIRT_TYPES,
                                       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
    virDomainObjListLoadAllConfigs(qemu_driver->domains,
868
                                   caps,
869
                                   qemu_driver->xmlconf,
870 871 872 873
                                   cfg->configDir,
                                   cfg->autostartDir,
                                   0, QEMU_EXPECTED_VIRT_TYPES,
                                   qemuNotifyLoadDomain, qemu_driver);
874
cleanup:
875
    virObjectUnref(cfg);
876
    virObjectUnref(caps);
877 878
    return 0;
}
S
Stefan Berger 已提交
879

880 881 882 883 884 885 886 887 888 889 890

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

898 899
    if (!(conn = virConnectOpen(cfg->uri)))
        goto cleanup;
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 934

    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);
935 936 937
    if (conn)
        virConnectClose(conn);
    virObjectUnref(cfg);
938 939 940 941

    return ret;
}

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

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

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

964 965
    virObjectUnref(qemu_driver->xmlconf);

966
    virSysinfoDefFree(qemu_driver->hostsysinfo);
967

968
    virObjectUnref(qemu_driver->closeCallbacks);
969

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

972
    virObjectUnref(qemu_driver->securityManager);
973

974
    ebtablesContextFree(qemu_driver->ebtables);
975

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

979
    virCgroupFree(&qemu_driver->cgroup);
980

981 982
    virLockManagerPluginUnref(qemu_driver->lockManager);

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

987
    return 0;
988 989
}

990

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

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

        cfg = virQEMUDriverGetConfig(qemu_driver);
1006

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

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

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

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

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

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

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

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

    conn->privateData = NULL;

    return 0;
}

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

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

1097

1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
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;
}

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

1115

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

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

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

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

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


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

    virCheckFlags(0, NULL);

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

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

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

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

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

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

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

1188

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

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

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

cleanup:
1202

1203
    return xml;
1204 1205 1206
}


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

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

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

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

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

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

1273 1274

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

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

    return 0;
}


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1354 1355 1356 1357 1358 1359

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

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

1363 1364 1365 1366
    ret = virDomainObjIsActive(obj);

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

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

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

1379 1380 1381 1382
    ret = obj->persistent;

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

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

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

1395 1396 1397 1398
    ret = obj->updated;

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

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

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

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

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

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

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

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

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

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

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

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

1443 1444

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

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

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

    return 0;
}


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

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

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

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

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

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

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

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

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

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

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

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

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

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
    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);
    }
1541
    virDomainAuditStart(vm, "booted", true);
D
Daniel P. Berrange 已提交
1542

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

1546
    if (vm &&
1547
        qemuDomainObjEndJob(driver, vm) == 0)
1548
        vm = NULL;
1549

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


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

1576
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1577

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

1591
    cfg = virQEMUDriverGetConfig(driver);
1592 1593
    priv = vm->privateData;

1594
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_SUSPEND) < 0)
1595 1596 1597
        goto cleanup;

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

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

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

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

1634
endjob:
1635
    if (qemuDomainObjEndJob(driver, vm) == 0)
1636
        vm = NULL;
1637

1638
cleanup:
1639
    if (vm)
1640
        virObjectUnlock(vm);
1641

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


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

1658
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
1659

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

1668 1669
    cfg = virQEMUDriverGetConfig(driver);

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

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

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

1703
endjob:
1704
    if (qemuDomainObjEndJob(driver, vm) == 0)
1705
        vm = NULL;
1706

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

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

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
1726

1727
    if (!(vm = qemuDomObjFromDomain(dom)))
1728
        goto cleanup;
1729

1730
    priv = vm->privateData;
1731 1732
    agentRequested = flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT;
    acpiRequested  = flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN;
1733

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

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

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

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

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

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

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

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

1786
endjob:
1787
    if (qemuDomainObjEndJob(driver, vm) == 0)
1788
        vm = NULL;
1789

1790
cleanup:
1791
    if (vm)
1792
        virObjectUnlock(vm);
1793
    return ret;
1794 1795
}

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

1801

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

1811 1812
    virCheckFlags(VIR_DOMAIN_REBOOT_ACPI_POWER_BTN |
                  VIR_DOMAIN_REBOOT_GUEST_AGENT , -1);
1813

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

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

1825 1826
    priv = vm->privateData;

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

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

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

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

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

1880 1881
        if (ret == 0)
            qemuDomainSetFakeReboot(driver, vm, true);
1882 1883
    }

1884 1885 1886 1887
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

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


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

    virCheckFlags(0, -1);

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

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

    if (!virDomainObjIsActive(vm)) {
1912 1913
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929
        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)
1930
        virObjectUnlock(vm);
1931 1932 1933 1934
    return ret;
}


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

1944
    if (virDomainSnapshotIsExternal(snap))
1945 1946 1947
        (*count)++;
}

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

1958
    virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1);
1959

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

1969 1970
    priv = vm->privateData;

1971
    qemuDomainSetFakeReboot(driver, vm, false);
1972

1973 1974 1975 1976 1977 1978

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

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

1996
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_DESTROY) < 0)
1997 1998
        goto cleanup;

1999 2000
    priv->beingDestroyed = false;

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

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

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

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

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

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

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

2043
    if (!(vm = qemuDomObjFromDomain(dom)))
2044
        goto cleanup;
2045

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

cleanup:
2050
    if (vm)
2051
        virObjectUnlock(vm);
2052 2053 2054
    return type;
}

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

2062
    if (!(vm = qemuDomObjFromDomain(dom)))
2063
        goto cleanup;
2064

2065
    ret = vm->def->mem.max_balloon;
2066 2067

cleanup:
2068
    if (vm)
2069
        virObjectUnlock(vm);
2070
    return ret;
2071 2072
}

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

2083 2084
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
2085
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
2086

2087
    if (!(vm = qemuDomObjFromDomain(dom)))
2088
        goto cleanup;
2089

2090 2091
    cfg = virQEMUDriverGetConfig(driver);

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

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

2101 2102 2103
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */

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

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

2121 2122 2123 2124
    } else {
        /* resize the current memory */

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

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

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

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

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

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

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

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

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

    virCheckFlags(0, -1);

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

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

    priv = vm->privateData;

2206
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2207
        goto cleanup;
2208 2209

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

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

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

cleanup:
    if (vm)
2227
        virObjectUnlock(vm);
2228 2229 2230
    return ret;
}

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

    virCheckFlags(0, -1);

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

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

2264
    if (!(vm = qemuDomObjFromDomain(domain)))
2265 2266 2267 2268
        goto cleanup;

    priv = vm->privateData;

2269
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2270 2271 2272
        goto cleanup;

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

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

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
2284 2285 2286 2287
        vm = NULL;

cleanup:
    if (vm)
2288
        virObjectUnlock(vm);
2289 2290 2291
    return ret;
}

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

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

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

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

2316
    info->maxMem = vm->def->mem.max_balloon;
2317

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

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

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

2360
    info->nrVirtCpu = vm->def->vcpus;
2361 2362 2363
    ret = 0;

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

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

    virCheckFlags(0, -1);

2380
    if (!(vm = qemuDomObjFromDomain(dom)))
2381 2382
        goto cleanup;

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

cleanup:
    if (vm)
2388
        virObjectUnlock(vm);
2389 2390 2391
    return ret;
}

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

    virCheckFlags(0, -1);

2403
    if (!(vm = qemuDomObjFromDomain(dom)))
2404 2405 2406
        goto cleanup;

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

    priv = vm->privateData;

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

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

    ret = 0;

cleanup:
    if (vm)
2438
        virObjectUnlock(vm);
2439 2440 2441
    return ret;
}

D
Daniel P. Berrange 已提交
2442

2443 2444 2445 2446 2447 2448
/* 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
2449

2450
verify(sizeof(QEMU_SAVE_MAGIC) == sizeof(QEMU_SAVE_PARTIAL));
E
Eric Blake 已提交
2451

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

2466
    QEMU_SAVE_FORMAT_LAST
2467
} virQEMUSaveFormat;
2468

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

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

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


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

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

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

2522
/* Given a virQEMUSaveFormat compression level, return the name
2523 2524 2525 2526
 * of the program to run, or NULL if no program is needed.  */
static const char *
qemuCompressProgramName(int compress)
{
2527 2528
    return (compress == QEMU_SAVE_FORMAT_RAW ? NULL :
            qemuSaveCompressionTypeToString(compress));
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 2556 2557
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 已提交
2558 2559 2560
/* Internal function to properly create or open existing files, with
 * ownership affected by qemu driver setup.  */
static int
2561
qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
E
Eric Blake 已提交
2562 2563 2564 2565 2566 2567
             bool *needUnlink, bool *bypassSecurityDriver)
{
    struct stat sb;
    bool is_reg = true;
    bool need_unlink = false;
    bool bypass_security = false;
L
Laine Stump 已提交
2568
    unsigned int vfoflags = 0;
E
Eric Blake 已提交
2569
    int fd = -1;
2570
    int path_shared = virStorageFileIsSharedFS(path);
E
Eric Blake 已提交
2571 2572
    uid_t uid = getuid();
    gid_t gid = getgid();
2573
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
E
Eric Blake 已提交
2574 2575 2576 2577 2578 2579

    /* 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;
2580 2581 2582

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

E
Eric Blake 已提交
2586 2587 2588 2589 2590
        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 */
2591
            if (is_reg && !cfg->dynamicOwnership) {
E
Eric Blake 已提交
2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605
                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 已提交
2606 2607
        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
E
Eric Blake 已提交
2608 2609 2610
            /* 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
2611
               qemu user (cfg->user) is non-root, just set a flag to
E
Eric Blake 已提交
2612 2613 2614
               bypass security driver shenanigans, and retry the operation
               after doing setuid to qemu user */
            if ((fd != -EACCES && fd != -EPERM) ||
2615
                cfg->user == getuid()) {
E
Eric Blake 已提交
2616 2617 2618 2619 2620 2621 2622
                virReportSystemError(-fd,
                                     _("Failed to create file '%s'"),
                                     path);
                goto cleanup;
            }

            /* On Linux we can also verify the FS-type of the directory. */
2623
            switch (path_shared) {
E
Eric Blake 已提交
2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645
                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;
            }

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

            if ((fd = virFileOpenAs(path, oflags,
                                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
2650
                                    cfg->user, cfg->group,
L
Laine Stump 已提交
2651
                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
E
Eric Blake 已提交
2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669
                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;
2670
    virObjectUnref(cfg);
E
Eric Blake 已提交
2671 2672 2673
    return fd;
}

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

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

2705
    header.compressed = compressed;
2706

2707
    len = strlen(domXML) + 1;
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720
    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));
2721
    if (VIR_ALLOC_N(xml, len + pad) < 0) {
2722
        virReportOOMError();
2723
        goto cleanup;
2724
    }
2725 2726
    strcpy(xml, domXML);

2727 2728
    offset += pad;
    header.xml_len = len;
2729

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

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

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

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

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

2770
    if (virFileWrapperFdClose(wrapperFd) < 0)
2771 2772 2773 2774
        goto cleanup;

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

2776
    memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic));
2777

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

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

2788 2789
    ret = 0;

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

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

    return ret;
}

2801
/* The vm must be active + locked. Vm will be unlocked and
2802 2803 2804 2805 2806
 * 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
2807
qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
2808 2809 2810 2811 2812 2813 2814 2815 2816
                       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;
2817 2818 2819 2820
    virCapsPtr caps;

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

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

2825
    if (qemuDomainObjBeginAsyncJob(driver, vm,
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 2856 2857
                                             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;

2858
        if (!(def = virDomainDefParseString(caps, driver->xmlconf, xmlin,
2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881
                                            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;

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

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

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

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

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

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

2949 2950 2951
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
2952

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

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

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

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

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

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

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

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

3016
    virObjectUnref(cfg);
3017
    return ret;
3018 3019 3020 3021 3022
}

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

3029 3030 3031
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3032

3033
    if (!(vm = qemuDomObjFromDomain(dom)))
3034
        return -1;
3035

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

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

3050
    VIR_INFO("Saving state to %s", name);
3051

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

3057
    vm = NULL;
3058 3059 3060

cleanup:
    if (vm)
3061
        virObjectUnlock(vm);
3062 3063 3064
    VIR_FREE(name);

    return ret;
3065 3066
}

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

3075
    virObjectLock(vm);
3076 3077 3078 3079 3080 3081

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

    vm->hasManagedSave = virFileExists(name);

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

3089

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

3096
    virCheckFlags(0, -1);
3097

3098 3099
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
3100

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

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

3114
    virCheckFlags(0, -1);
3115

3116
    if (!(vm = qemuDomObjFromDomain(dom)))
3117
        return -1;
3118

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

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

3129
    vm->hasManagedSave = false;
3130
    ret = 0;
3131 3132 3133

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

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

3144
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
3145
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3146
                       _("dump-guest-memory is not supported"));
3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158
        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;

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

    return ret;
}

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

    /* Create an empty file with appropriate ownership.  */
3179
    if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
3180
        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
3181 3182
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
3183 3184
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
3185 3186 3187
            goto cleanup;
        }
    }
E
Eric Blake 已提交
3188 3189 3190 3191 3192 3193
    /* 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 已提交
3194 3195
        goto cleanup;

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

3199 3200 3201 3202 3203 3204 3205 3206 3207
    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)
3208 3209
        goto cleanup;

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

3219
    ret = 0;
H
Hu Tao 已提交
3220 3221

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

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

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

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

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

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

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

3288 3289
    if (qemuDomainObjBeginAsyncJob(driver, vm,
                                   QEMU_ASYNC_JOB_DUMP) < 0)
3290 3291
        goto cleanup;

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

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

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

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

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

    paused = 1;
3322 3323

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

P
Paolo Bonzini 已提交
3332 3333 3334
    /* 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 已提交
3335 3336 3337 3338
    else if (((resume && paused) || (flags & VIR_DUMP_RESET)) &&
             virDomainObjIsActive(vm)) {
        if ((ret == 0) && (flags & VIR_DUMP_RESET)) {
            priv =  vm->privateData;
3339
            qemuDomainObjEnterMonitor(driver, vm);
M
Michal Privoznik 已提交
3340
            ret = qemuMonitorSystemReset(priv->mon);
3341
            qemuDomainObjExitMonitor(driver, vm);
M
Michal Privoznik 已提交
3342 3343 3344 3345 3346
        }

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

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

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

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

E
Eric Blake 已提交
3386 3387
    virCheckFlags(0, NULL);

3388
    if (!(vm = qemuDomObjFromDomain(dom)))
3389 3390 3391
        goto cleanup;

    priv = vm->privateData;
3392
    cfg = virQEMUDriverGetConfig(driver);
3393

3394
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3395 3396 3397
        goto cleanup;

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

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

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

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

3423
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
3424

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

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

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

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

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

3451
    if (qemuDomainObjEndJob(driver, vm) == 0)
3452 3453 3454 3455
        vm = NULL;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3548
    qemuDomainObjEnterMonitor(driver, vm);
3549

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

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

E
Eric Blake 已提交
3573
            vcpus--;
3574 3575 3576
        }
    }

3577 3578
    /* hotplug succeeded */

3579 3580
    ret = 0;

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

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

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

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

3612 3613 3614 3615
    if (nvcpus > oldvcpus) {
        for (i = oldvcpus; i < nvcpus; i++) {
            if (cgroup_available) {
                int rv = -1;
3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634
                /* 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;
                }
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 3669 3670
            /* 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 {
3671 3672
                    if (virProcessSetAffinity(cpupids[i],
                                              vcpupin->cpumask) < 0) {
3673 3674 3675 3676 3677 3678 3679
                        virReportError(VIR_ERR_SYSTEM_ERROR,
                                       _("failed to set cpu affinity for vcpu %d"),
                                       i);
                        ret = -1;
                        goto cleanup;
                    }
                }
3680
            }
3681 3682

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

            if (cgroup_available) {
                int rv = -1;

3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704
                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);
            }

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

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

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

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


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

3749 3750
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
3751 3752 3753
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

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

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

3763
    if (!(vm = qemuDomObjFromDomain(dom)))
3764
        goto cleanup;
3765

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

3769 3770 3771
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

3772
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
3773 3774
                                        &persistentDef) < 0)
        goto endjob;
3775 3776 3777

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

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

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

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

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

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

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

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

3825
    ret = 0;
3826

3827
endjob:
3828
    if (qemuDomainObjEndJob(driver, vm) == 0)
3829
        vm = NULL;
3830

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

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

3845 3846

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

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

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

3870 3871
    cfg = virQEMUDriverGetConfig(driver);

3872
    if (!(vm = qemuDomObjFromDomain(dom)))
3873 3874
        goto cleanup;

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

3878
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
3879
                                        &persistentDef) < 0)
3880
        goto cleanup;
3881

3882 3883 3884
    priv = vm->privateData;

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

3891 3892 3893 3894
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

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

3901
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3902

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

3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923
        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;
        }

3924
        if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, vcpu) < 0) {
3925 3926
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to update vcpupin"));
H
Hu Tao 已提交
3927
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938
            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);
3939 3940 3941
                goto cleanup;
            }
        } else {
3942
            if (virProcessSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) {
3943 3944 3945 3946
                virReportError(VIR_ERR_SYSTEM_ERROR,
                               _("failed to set cpu affinity for vcpu %d"),
                               vcpu);
                goto cleanup;
H
Hu Tao 已提交
3947
            }
3948 3949
        }

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

            vm->def->cputune.vcpupin = newVcpuPin;
            vm->def->cputune.nvcpupin = newVcpuPinNum;
            newVcpuPin = NULL;
3964 3965
        }

3966
        if (newVcpuPin)
H
Hu Tao 已提交
3967
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
3968

3969
        if (virDomainSaveStatus(driver->xmlconf, cfg->stateDir, vm) < 0)
3970
            goto cleanup;
3971
    }
3972

3973 3974
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

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

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

4006
    ret = 0;
4007

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

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

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

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4052
    if (!(vm = qemuDomObjFromDomain(dom)))
4053 4054
        goto cleanup;

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

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

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

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

4069
    if ((hostcpus = nodeGetCPUCount()) < 0)
4070
        goto cleanup;
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 4098 4099
    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 已提交
4100 4101 4102
            if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
                goto cleanup;
            if (!pinned)
4103 4104 4105 4106 4107 4108 4109
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

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

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4139 4140
    cfg = virQEMUDriverGetConfig(driver);

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

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

4147 4148 4149 4150 4151 4152 4153
    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;
    }

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

    priv = vm->privateData;

4160 4161 4162 4163
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

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

    pid = vm->pid;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {

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

4180
            if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, -1) < 0) {
H
Hu Tao 已提交
4181 4182
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update vcpupin"));
H
Hu Tao 已提交
4183
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195
                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) {
4196 4197
                        if (qemuSetupCgroupEmulatorPin(cgroup_emulator,
                                                       newVcpuPin[0]->cpumask) < 0) {
H
Hu Tao 已提交
4198 4199 4200 4201 4202 4203 4204 4205
                            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                           _("failed to set cpuset.cpus in cgroup"
                                             " for emulator threads"));
                            goto cleanup;
                        }
                    }
                }
            } else {
4206
                if (virProcessSetAffinity(pid, pcpumap) < 0) {
H
Hu Tao 已提交
4207 4208 4209 4210 4211 4212 4213
                    virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
                                   _("failed to set cpu affinity for "
                                     "emulator threads"));
                    goto cleanup;
                }
            }

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

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

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

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

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

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

    ret = 0;

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

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

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

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

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

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

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

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

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

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

    ret = 1;

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

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

4359
    if (!(vm = qemuDomObjFromDomain(dom)))
4360 4361
        goto cleanup;

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

4369 4370
    priv = vm->privateData;

4371
    if ((hostcpus = nodeGetCPUCount()) < 0)
4372
        goto cleanup;
4373 4374

    maxcpu = maplen * 8;
4375 4376
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
4377 4378

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

4382 4383 4384 4385 4386 4387
    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;
4388

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

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

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

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

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


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

4447 4448
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4449 4450
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

4451
    if (!(vm = qemuDomObjFromDomain(dom)))
4452
        goto cleanup;
4453

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

4457 4458
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf,
                                        vm, &flags, &def) < 0)
4459
        goto cleanup;
4460

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

4465
    ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
4466

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

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

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

4487
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
4488

4489 4490
    memset(seclabel, 0, sizeof(*seclabel));

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

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

    ret = 0;

cleanup:
    if (vm)
4533
        virObjectUnlock(vm);
4534 4535 4536
    return ret;
}

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

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

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

    /*
4563
     * Check the comment in qemuDomainGetSecurityLabel function.
M
Marcelo Cerri 已提交
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 4602 4603
     */
    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)
4604
        virObjectUnlock(vm);
M
Marcelo Cerri 已提交
4605 4606
    return ret;
}
4607 4608


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

4617 4618
    memset(secmodel, 0, sizeof(*secmodel));

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

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

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

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

cleanup:
4648
    virObjectUnref(caps);
4649
    return ret;
4650 4651
}

E
Eric Blake 已提交
4652
/* Return -1 on most failures after raising error, -2 if edit was specified
4653 4654 4655
 * 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.  */
4656
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
4657
qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
4658 4659
                        const char *path,
                        virDomainDefPtr *ret_def,
4660
                        virQEMUSaveHeaderPtr ret_header,
J
Jiri Denemark 已提交
4661 4662
                        bool bypass_cache,
                        virFileWrapperFdPtr *wrapperFd,
4663 4664
                        const char *xmlin, int state, bool edit,
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
4665
{
W
Wen Congyang 已提交
4666
    int fd = -1;
4667
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
4668 4669
    char *xml = NULL;
    virDomainDefPtr def = NULL;
4670
    int oflags = edit ? O_RDWR : O_RDONLY;
4671
    virCapsPtr caps = NULL;
4672

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

4683 4684 4685
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto error;

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

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

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

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

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

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

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

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

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

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

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

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

J
Jiri Denemark 已提交
4789
    VIR_FREE(xml);
4790

J
Jiri Denemark 已提交
4791 4792
    *ret_def = def;
    *ret_header = header;
4793

4794 4795
    virObjectUnref(caps);

J
Jiri Denemark 已提交
4796
    return fd;
4797

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

    return -1;
}

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

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

4828 4829
        intermediatefd = *fd;
        *fd = -1;
4830

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

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

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

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

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

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

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

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

4882

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

4907
    ret = 0;
4908

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

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

4934 4935 4936
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
4937

J
Jiri Denemark 已提交
4938

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

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

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

4959
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
4960 4961
        goto cleanup;

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

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

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

4983 4984 4985 4986 4987 4988 4989
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

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

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

    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5004
                                 NULL, -1, false, false);
5005 5006 5007 5008

    if (fd < 0)
        goto cleanup;

5009
    ret = qemuDomainDefFormatXML(driver, def, flags);
5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020

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

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

5030 5031
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5032

5033 5034 5035 5036 5037
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

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

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

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

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

5066
    if (lseek(fd, 0, SEEK_SET) != 0) {
5067 5068 5069
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
5070 5071
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085
        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 已提交
5086 5087
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
5088 5089
static int
qemuDomainObjRestore(virConnectPtr conn,
5090
                     virQEMUDriverPtr driver,
5091
                     virDomainObjPtr vm,
5092
                     const char *path,
5093
                     bool start_paused,
5094
                     bool bypass_cache)
J
Jiri Denemark 已提交
5095 5096 5097 5098
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    int ret = -1;
5099
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5100
    virFileWrapperFdPtr wrapperFd = NULL;
J
Jiri Denemark 已提交
5101

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

    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);
5117 5118 5119 5120 5121
        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 已提交
5122 5123 5124
        goto cleanup;
    }

5125
    virDomainObjAssignDef(vm, def, true, NULL);
J
Jiri Denemark 已提交
5126 5127
    def = NULL;

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

cleanup:
    virDomainDefFree(def);
5135
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5136
    virFileWrapperFdFree(wrapperFd);
J
Jiri Denemark 已提交
5137 5138 5139
    return ret;
}

D
Daniel P. Berrange 已提交
5140

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

5151
    /* Flags checked by virDomainDefFormat */
5152

5153
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
5154

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

5163 5164
    priv = vm->privateData;

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

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

5182
            qemuDomainObjEnterMonitor(driver, vm);
5183
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
5184
            qemuDomainObjExitMonitor(driver, vm);
5185 5186

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

5199 5200 5201 5202
    if ((flags & VIR_DOMAIN_XML_MIGRATABLE))
        flags |= QEMU_DOMAIN_FORMAT_LIVE_FLAGS;

    ret = qemuDomainFormatXML(driver, vm, flags);
5203 5204

cleanup:
5205
    if (vm)
5206
        virObjectUnlock(vm);
5207
    return ret;
D
Daniel P. Berrange 已提交
5208 5209 5210
}


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

E
Eric Blake 已提交
5221 5222
    virCheckFlags(0, NULL);

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

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

5232
    def = qemuParseCommandLineString(caps, driver->xmlconf, config,
5233
                                     NULL, NULL, NULL);
5234 5235 5236
    if (!def)
        goto cleanup;

5237 5238 5239 5240 5241 5242
    if (!def->name &&
        !(def->name = strdup("unnamed"))) {
        virReportOOMError();
        goto cleanup;
    }

5243
    xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE);
5244 5245 5246

cleanup:
    virDomainDefFree(def);
5247
    virObjectUnref(caps);
5248 5249 5250
    return xml;
}

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

E
Eric Blake 已提交
5267 5268
    virCheckFlags(0, NULL);

5269
    cfg = virQEMUDriverGetConfig(driver);
5270

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

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

5280
    def = virDomainDefParseString(caps, driver->xmlconf, xmlData,
M
Matthias Bolte 已提交
5281
                                  QEMU_EXPECTED_VIRT_TYPES, 0);
5282 5283 5284
    if (!def)
        goto cleanup;

5285
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
5286 5287
        goto cleanup;

5288 5289
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
5290 5291 5292 5293 5294
     * 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];
5295
        int bootIndex = net->info.bootIndex;
5296 5297
        char *model = net->model;

5298 5299 5300 5301
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

5302
            VIR_FREE(net->data.network.name);
5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314
            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);

5315
                memset(net, 0, sizeof(*net));
5316 5317

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

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5329
                net->script = NULL;
5330 5331 5332 5333 5334
                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);
5335

5336
            memset(net, 0, sizeof(*net));
5337 5338

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

5347
            memset(net, 0, sizeof(*net));
5348 5349

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5350
            net->script = script;
5351 5352 5353
            net->data.ethernet.dev = brname;
            net->data.ethernet.ipaddr = ipaddr;
        }
5354

5355
        VIR_FREE(net->virtPortProfile);
5356
        net->info.bootIndex = bootIndex;
5357
        net->model = model;
5358 5359
    }

5360
    monitor_json = virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON);
T
tangchen 已提交
5361

5362
    if (qemuProcessPrepareMonitorChr(cfg, &monConfig, def->name) < 0)
5363
        goto cleanup;
5364

5365
    if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
5366 5367
        goto cleanup;

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

E
Eric Blake 已提交
5373
    ret = virCommandToString(cmd);
5374 5375 5376

cleanup:

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


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

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

5395
static int qemuNumDefinedDomains(virConnectPtr conn) {
5396
    virQEMUDriverPtr driver = conn->privateData;
5397
    int n;
5398

5399
    n = virDomainObjListNumOfDomains(driver->domains, 0);
5400

5401
    return n;
D
Daniel P. Berrange 已提交
5402 5403 5404
}


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

    start_flags |= start_paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
5420
    start_flags |= autodestroy ? VIR_QEMU_PROCESS_START_AUTODESTROY : 0;
J
Jiri Denemark 已提交
5421 5422 5423

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

    if (!managed_save)
        goto cleanup;

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

5444 5445 5446 5447 5448 5449 5450
            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 已提交
5451 5452 5453 5454
            if (ret > 0)
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
            else
                goto cleanup;
5455
        }
J
Jiri Denemark 已提交
5456 5457
    }

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

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

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

5490
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
5491
                  VIR_DOMAIN_START_AUTODESTROY |
5492 5493
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
5494

5495
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
5496

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

5505
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
5506 5507 5508
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
5509 5510
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is already running"));
5511 5512 5513
        goto endjob;
    }

5514
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
5515 5516 5517
        goto endjob;

    ret = 0;
5518

5519
endjob:
5520
    if (qemuDomainObjEndJob(driver, vm) == 0)
5521
        vm = NULL;
5522

5523
cleanup:
5524
    if (vm)
5525
        virObjectUnlock(vm);
5526
    return ret;
D
Daniel P. Berrange 已提交
5527 5528
}

5529
static int
5530
qemuDomainStart(virDomainPtr dom)
5531
{
5532
    return qemuDomainStartWithFlags(dom, 0);
5533 5534
}

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

5546
    cfg = virQEMUDriverGetConfig(driver);
5547 5548 5549 5550

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

5551
    if (!(def = virDomainDefParseString(caps, driver->xmlconf, xml,
M
Matthias Bolte 已提交
5552
                                        QEMU_EXPECTED_VIRT_TYPES,
5553
                                        VIR_DOMAIN_XML_INACTIVE)))
5554
        goto cleanup;
5555

5556
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
5557 5558
        goto cleanup;

5559
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
5560 5561
        goto cleanup;

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

5565
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
5566 5567
        goto cleanup;

5568
    if (!(vm = virDomainObjListAdd(driver->domains,
5569
                                   driver->xmlconf,
5570 5571 5572 5573 5574
                                   def,
                                   0,
                                   &oldDef)))
        goto cleanup;

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

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

5604 5605
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
5606
                                     !oldDef ?
5607 5608
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
5609

5610
    VIR_INFO("Creating domain '%s'", vm->def->name);
5611
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
5612
    if (dom) dom->id = vm->def->id;
5613 5614

cleanup:
5615
    virDomainDefFree(oldDef);
5616
    virDomainDefFree(def);
5617
    if (vm)
5618
        virObjectUnlock(vm);
5619 5620
    if (event)
        qemuDomainEventQueue(driver, event);
5621
    virObjectUnref(qemuCaps);
5622
    virObjectUnref(caps);
5623
    virObjectUnref(cfg);
5624
    return dom;
D
Daniel P. Berrange 已提交
5625 5626
}

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

5639 5640
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
5641

5642
    cfg = virQEMUDriverGetConfig(driver);
5643
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
5644

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

5653
    if (!vm->persistent) {
5654 5655
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
5656 5657 5658
        goto cleanup;
    }

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

5672 5673 5674 5675 5676 5677 5678
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

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

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

5695 5696 5697
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
5698

5699
    VIR_INFO("Undefining domain '%s'", vm->def->name);
5700 5701 5702 5703 5704 5705 5706 5707

    /* 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 {
5708
        qemuDomainRemoveInactive(driver, vm);
5709 5710 5711
        vm = NULL;
    }

5712
    ret = 0;
D
Daniel P. Berrange 已提交
5713

5714
cleanup:
5715
    VIR_FREE(name);
5716
    if (vm)
5717
        virObjectUnlock(vm);
5718 5719
    if (event)
        qemuDomainEventQueue(driver, event);
5720
    virObjectUnref(cfg);
5721
    return ret;
D
Daniel P. Berrange 已提交
5722 5723
}

5724
static int
5725
qemuDomainUndefine(virDomainPtr dom)
5726 5727 5728 5729
{
    return qemuDomainUndefineFlags(dom, 0);
}

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

5744
    if (disk->driverName != NULL && !STREQ(disk->driverName, "qemu")) {
5745 5746 5747
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unsupported driver name '%s' for disk '%s'"),
                       disk->driverName, disk->src);
5748 5749 5750
        goto end;
    }

5751 5752 5753 5754 5755 5756
    if (qemuAddSharedDisk(driver, disk, vm->def->name) < 0)
        goto end;

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

5757 5758 5759
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto end;

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

5771 5772 5773
    switch (disk->device)  {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795
        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;

        if (!(dev_copy = virDomainDeviceDefCopy(caps, vm->def, dev))) {
            dev->data.disk = tmp;
            goto end;
        }
        dev->data.disk = tmp;

        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, orig_disk, false);
5796 5797 5798
        /* '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 */
5799 5800 5801 5802

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

    if (ret != 0 && cgroup) {
5835
        if (qemuTeardownDiskCgroup(vm, cgroup, disk) < 0)
5836 5837 5838
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(disk->src));
    }
5839

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

static int
5851
qemuDomainAttachDeviceControllerLive(virQEMUDriverPtr driver,
5852
                                     virDomainObjPtr vm,
5853
                                     virDomainDeviceDefPtr dev)
5854 5855 5856 5857 5858 5859
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

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

static int
qemuDomainAttachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5874
                           virDomainPtr dom)
5875
{
5876
    virQEMUDriverPtr driver = dom->conn->privateData;
5877 5878 5879 5880
    int ret = -1;

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

    case VIR_DOMAIN_DEVICE_CONTROLLER:
5888
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
5889 5890 5891 5892
        if (!ret)
            dev->data.controller = NULL;
        break;

5893 5894 5895 5896 5897 5898 5899
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

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

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = qemuDomainAttachHostDevice(driver, vm,
5910
                                         dev->data.hostdev);
5911 5912 5913 5914
        if (!ret)
            dev->data.hostdev = NULL;
        break;

5915 5916 5917 5918 5919 5920 5921
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

5922
    default:
5923 5924 5925
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
5926 5927 5928 5929 5930 5931 5932
        break;
    }

    return ret;
}

static int
5933
qemuDomainDetachDeviceDiskLive(virQEMUDriverPtr driver,
5934
                               virDomainObjPtr vm,
5935
                               virDomainDeviceDefPtr dev)
5936 5937 5938 5939 5940 5941
{
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_DISK:
5942
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5943
        if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
5944
            ret = qemuDomainDetachVirtioDiskDevice(driver, vm, dev);
O
Osier Yang 已提交
5945 5946
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                 disk->bus == VIR_DOMAIN_DISK_BUS_USB)
5947
            ret = qemuDomainDetachDiskDevice(driver, vm, dev);
5948
        else
5949 5950
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("This type of disk cannot be hot unplugged"));
5951 5952
        break;
    default:
5953 5954
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk device type '%s' cannot be detached"),
5955
                       virDomainDiskDeviceTypeToString(disk->device));
5956 5957
        break;
    }
5958

5959 5960
    if (ret == 0)
        ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));
5961

5962 5963 5964 5965
    return ret;
}

static int
5966
qemuDomainDetachDeviceControllerLive(virQEMUDriverPtr driver,
5967
                                     virDomainObjPtr vm,
5968
                                     virDomainDeviceDefPtr dev)
5969 5970 5971 5972 5973 5974
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5975
        ret = qemuDomainDetachPciControllerDevice(driver, vm, dev);
5976 5977
        break;
    default :
5978 5979 5980
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk controller bus '%s' cannot be hotunplugged."),
                       virDomainControllerTypeToString(cont->type));
5981 5982 5983 5984 5985 5986 5987
    }
    return ret;
}

static int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5988
                           virDomainPtr dom)
5989
{
5990
    virQEMUDriverPtr driver = dom->conn->privateData;
5991 5992 5993 5994
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5995
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
5996 5997
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5998
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
5999
        break;
6000 6001 6002
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
6003
    case VIR_DOMAIN_DEVICE_NET:
6004
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
6005 6006
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
6007
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
6008 6009
        break;
    default:
6010 6011
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("This type of device cannot be hot unplugged"));
6012 6013 6014 6015 6016 6017
        break;
    }

    return ret;
}

6018 6019 6020
static int
qemuDomainChangeDiskMediaLive(virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev,
6021
                              virQEMUDriverPtr driver,
6022 6023 6024
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
6025 6026
    virDomainDiskDefPtr orig_disk = NULL;
    virDomainDiskDefPtr tmp = NULL;
6027
    virCgroupPtr cgroup = NULL;
6028 6029
    virDomainDeviceDefPtr dev_copy = NULL;
    virCapsPtr caps = NULL;
6030
    int ret = -1;
6031

6032 6033 6034
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto end;

6035 6036
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup,
6037
                               vm->def->name, &cgroup, 0) != 0) {
6038 6039 6040
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to find cgroup for %s"),
                           vm->def->name);
6041 6042
            goto end;
        }
6043
        if (qemuSetupDiskCgroup(vm, cgroup, disk) < 0)
6044 6045 6046 6047 6048 6049
            goto end;
    }

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070
        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;

        if (!(dev_copy = virDomainDeviceDefCopy(caps, vm->def, dev))) {
            dev->data.disk = tmp;
            goto end;
        }
        dev->data.disk = tmp;

6071 6072 6073 6074
        /* Add the new disk src into shared disk hash table */
        if (qemuAddSharedDisk(driver, dev->data.disk, vm->def->name) < 0)
            goto end;

6075 6076
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, orig_disk, force);
        if (ret == 0) {
6077
            dev->data.disk = NULL;
6078 6079 6080 6081 6082 6083 6084
            /* Need to remove the shared disk entry for the original
             * disk src if the operation is either ejecting or updating.
             */
            if (orig_disk->src && STRNEQ_NULLABLE(orig_disk->src, disk->src))
                ignore_value(qemuRemoveSharedDisk(driver, dev_copy->data.disk,
                                                  vm->def->name));
        }
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
    dev = dev_copy = virDomainDeviceDefParse(caps, vm->def, xml,
6469 6470 6471 6472 6473 6474 6475 6476 6477 6478
                                             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.
         */
6479
        dev_copy = virDomainDeviceDefCopy(caps, vm->def, dev);
6480
        if (!dev_copy)
6481
            goto endjob;
6482
    }
6483

6484 6485 6486
    if (priv->qemuCaps)
        qemuCaps = virObjectRef(priv->qemuCaps);
    else if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, vm->def->emulator)))
6487 6488
        goto cleanup;

6489
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6490
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
6491 6492
            goto endjob;

6493
        /* Make a copy for updated domain. */
6494
        vmdef = virDomainObjCopyPersistentDef(caps, driver->xmlconf, vm);
6495 6496 6497 6498
        if (!vmdef)
            goto endjob;
        switch (action) {
        case QEMU_DEVICE_ATTACH:
6499
            ret = qemuDomainAttachDeviceConfig(qemuCaps, vmdef, dev);
6500 6501 6502 6503 6504
            break;
        case QEMU_DEVICE_DETACH:
            ret = qemuDomainDetachDeviceConfig(vmdef, dev);
            break;
        case QEMU_DEVICE_UPDATE:
6505
            ret = qemuDomainUpdateDeviceConfig(qemuCaps, vmdef, dev);
6506 6507
            break;
        default:
6508 6509
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown domain modify action %d"), action);
6510 6511
            break;
        }
6512

6513 6514 6515 6516 6517
        if (ret == -1)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6518 6519 6520
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto endjob;

6521 6522
        switch (action) {
        case QEMU_DEVICE_ATTACH:
6523
            ret = qemuDomainAttachDeviceLive(vm, dev_copy, dom);
6524 6525
            break;
        case QEMU_DEVICE_DETACH:
6526
            ret = qemuDomainDetachDeviceLive(vm, dev_copy, dom);
6527 6528
            break;
        case QEMU_DEVICE_UPDATE:
6529
            ret = qemuDomainUpdateDeviceLive(vm, dev_copy, dom, force);
6530 6531
            break;
        default:
6532 6533
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown domain modify action %d"), action);
6534
            ret = -1;
6535 6536
            break;
        }
6537 6538 6539

        if (ret == -1)
            goto endjob;
6540 6541
        /*
         * update domain status forcibly because the domain status may be
6542 6543
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
6544
         */
6545
        if (virDomainSaveStatus(driver->xmlconf, cfg->stateDir, vm) < 0) {
6546
            ret = -1;
6547 6548
            goto endjob;
        }
6549
    }
6550

6551
    /* Finally, if no error until here, we can save config. */
6552
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6553
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
6554
        if (!ret) {
6555
            virDomainObjAssignDef(vm, vmdef, false, NULL);
6556 6557 6558
            vmdef = NULL;
        }
    }
6559 6560

endjob:
6561
    if (qemuDomainObjEndJob(driver, vm) == 0)
6562 6563 6564
        vm = NULL;

cleanup:
6565
    virObjectUnref(qemuCaps);
6566
    virDomainDefFree(vmdef);
6567 6568
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
6569 6570
    virDomainDeviceDefFree(dev);
    if (vm)
6571
        virObjectUnlock(vm);
6572
    virObjectUnref(caps);
6573
    virObjectUnref(cfg);
6574 6575 6576
    return ret;
}

6577 6578 6579 6580 6581 6582
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_ATTACH);
}

6583 6584 6585
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
6586
                                       VIR_DOMAIN_AFFECT_LIVE);
6587
}
6588

6589

6590 6591 6592 6593
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
6594
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_UPDATE);
6595 6596
}

6597 6598 6599
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
6600
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_DETACH);
6601 6602
}

6603 6604 6605
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
6606
                                       VIR_DOMAIN_AFFECT_LIVE);
6607 6608
}

6609 6610
static int qemuDomainGetAutostart(virDomainPtr dom,
                                  int *autostart) {
6611 6612
    virDomainObjPtr vm;
    int ret = -1;
6613

6614
    if (!(vm = qemuDomObjFromDomain(dom)))
6615
        goto cleanup;
6616 6617

    *autostart = vm->autostart;
6618
    ret = 0;
6619

6620
cleanup:
6621
    if (vm)
6622
        virObjectUnlock(vm);
6623
    return ret;
6624 6625
}

6626 6627
static int qemuDomainSetAutostart(virDomainPtr dom,
                                  int autostart) {
6628
    virQEMUDriverPtr driver = dom->conn->privateData;
6629
    virDomainObjPtr vm;
6630 6631
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
6632
    virQEMUDriverConfigPtr cfg = NULL;
6633

6634
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
6635
    cfg = virQEMUDriverGetConfig(driver);
6636
    if (!vm) {
6637 6638
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6639 6640
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
6641
        goto cleanup;
6642 6643
    }

6644
    if (!vm->persistent) {
6645 6646
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
6647
        goto cleanup;
6648 6649
    }

6650 6651
    autostart = (autostart != 0);

6652
    if (vm->autostart != autostart) {
6653
        if ((configFile = virDomainConfigFile(cfg->configDir, vm->def->name)) == NULL)
6654
            goto cleanup;
6655
        if ((autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)) == NULL)
6656
            goto cleanup;
6657

6658
        if (autostart) {
6659
            if (virFileMakePath(cfg->autostartDir) < 0) {
6660
                virReportSystemError(errno,
6661
                                     _("cannot create autostart directory %s"),
6662
                                     cfg->autostartDir);
6663 6664
                goto cleanup;
            }
6665

6666
            if (symlink(configFile, autostartLink) < 0) {
6667
                virReportSystemError(errno,
6668 6669
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
6670 6671 6672 6673
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
6674
                virReportSystemError(errno,
6675 6676
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
6677 6678
                goto cleanup;
            }
6679 6680
        }

6681
        vm->autostart = autostart;
6682
    }
6683
    ret = 0;
6684

6685 6686 6687
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
6688
    if (vm)
6689
        virObjectUnlock(vm);
6690
    virObjectUnref(cfg);
6691
    return ret;
6692 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
/*
 * 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;
}


6728 6729 6730
static char *qemuGetSchedulerType(virDomainPtr dom,
                                  int *nparams)
{
6731
    virQEMUDriverPtr driver = dom->conn->privateData;
6732
    char *ret = NULL;
6733
    int rc;
6734

6735
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
6736 6737
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
6738
        goto cleanup;
6739 6740
    }

6741 6742 6743 6744 6745 6746 6747
    if (nparams) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        else if (rc == 0)
            *nparams = 1;
        else
6748
            *nparams = 5;
6749
    }
6750 6751 6752

    ret = strdup("posix");
    if (!ret)
6753
        virReportOOMError();
6754 6755

cleanup:
6756 6757 6758
    return ret;
}

6759 6760 6761 6762
/* 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
6763 6764
qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
                               virBlkioDeviceWeightPtr *dw, size_t *size)
6765 6766 6767 6768 6769 6770 6771
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
    int i;
    virBlkioDeviceWeightPtr result = NULL;

6772 6773 6774 6775 6776 6777
    *dw = NULL;
    *size = 0;

    if (STREQ(deviceWeightStr, ""))
        return 0;

6778 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
    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:
6839 6840
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unable to parse device weight '%s'"), deviceWeightStr);
6841 6842 6843 6844 6845 6846
cleanup:
    virBlkioDeviceWeightArrayClear(result, ndevices);
    VIR_FREE(result);
    return -1;
}

6847 6848
/* Modify dest_array to reflect all device weight changes described in
 * src_array.  */
6849
static int
6850 6851 6852 6853
qemuDomainMergeDeviceWeights(virBlkioDeviceWeightPtr *dest_array,
                             size_t *dest_size,
                             virBlkioDeviceWeightPtr src_array,
                             size_t src_size)
6854 6855
{
    int i, j;
6856
    virBlkioDeviceWeightPtr dest, src;
6857

6858
    for (i = 0; i < src_size; i++) {
6859 6860
        bool found = false;

6861 6862 6863 6864
        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
6865
                found = true;
6866
                dest->weight = src->weight;
6867 6868 6869 6870
                break;
            }
        }
        if (!found) {
6871
            if (!src->weight)
6872
                continue;
6873
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0) {
6874 6875 6876
                virReportOOMError();
                return -1;
            }
6877 6878 6879 6880
            dest = &(*dest_array)[*dest_size - 1];
            dest->path = src->path;
            dest->weight = src->weight;
            src->path = NULL;
6881 6882 6883 6884 6885 6886
        }
    }

    return 0;
}

6887 6888 6889 6890 6891
static int
qemuDomainSetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
6892
{
6893
    virQEMUDriverPtr driver = dom->conn->privateData;
6894 6895 6896
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6897
    virDomainDefPtr persistentDef = NULL;
6898
    int ret = -1;
6899
    virQEMUDriverConfigPtr cfg = NULL;
6900
    virCapsPtr caps = NULL;
6901

6902 6903
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6904 6905 6906 6907 6908 6909 6910
    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;
6911

6912
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
6913
    if (vm == NULL) {
6914 6915
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
6916 6917
        goto cleanup;
    }
6918
    cfg = virQEMUDriverGetConfig(driver);
6919 6920
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;
6921

6922
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
6923 6924
                                        &persistentDef) < 0)
        goto cleanup;
6925

6926 6927
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
6928 6929
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
6930 6931 6932 6933
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
6934 6935 6936
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
6937 6938 6939 6940
            goto cleanup;
        }
    }

6941
    ret = 0;
6942 6943
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        for (i = 0; i < nparams; i++) {
6944
            int rc;
6945 6946 6947 6948
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
6949 6950
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
6951 6952 6953
                    ret = -1;
                    continue;
                }
6954

6955 6956 6957 6958 6959 6960
                rc = virCgroupSetBlkioWeight(group, params[i].value.ui);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set blkio weight tunable"));
                    ret = -1;
                }
6961
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
6962
                size_t ndevices;
6963
                virBlkioDeviceWeightPtr devices = NULL;
6964 6965
                int j;

6966 6967 6968
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
6969 6970 6971
                    ret = -1;
                    continue;
                }
6972
                for (j = 0; j < ndevices; j++) {
6973
                    rc = virCgroupSetBlkioDeviceWeight(group,
6974 6975
                                                       devices[j].path,
                                                       devices[j].weight);
6976 6977 6978 6979
                    if (rc < 0) {
                        virReportSystemError(-rc,
                                             _("Unable to set io device weight "
                                               "for path %s"),
6980
                                             devices[j].path);
6981 6982 6983
                        break;
                    }
                }
6984 6985
                if (j != ndevices ||
                    qemuDomainMergeDeviceWeights(&vm->def->blkio.devices,
6986 6987 6988 6989 6990
                                                 &vm->def->blkio.ndevices,
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
6991
            }
6992
        }
E
Eric Blake 已提交
6993 6994 6995 6996
    }
    if (ret < 0)
        goto cleanup;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
6997 6998 6999
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

7000 7001 7002 7003 7004
        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) {
7005 7006
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
7007 7008 7009 7010 7011
                    ret = -1;
                    continue;
                }

                persistentDef->blkio.weight = params[i].value.ui;
7012 7013
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
                virBlkioDeviceWeightPtr devices = NULL;
7014
                size_t ndevices;
7015

7016 7017 7018
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
7019 7020 7021
                    ret = -1;
                    continue;
                }
7022 7023
                if (qemuDomainMergeDeviceWeights(&persistentDef->blkio.devices,
                                                 &persistentDef->blkio.ndevices,
7024 7025 7026 7027
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
7028 7029
            }
        }
A
Alex Jia 已提交
7030

7031
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
A
Alex Jia 已提交
7032
            ret = -1;
7033 7034 7035 7036 7037
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
7038
        virObjectUnlock(vm);
7039
    virObjectUnref(caps);
7040
    virObjectUnref(cfg);
7041 7042 7043
    return ret;
}

7044 7045 7046 7047 7048
static int
qemuDomainGetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
7049
{
7050
    virQEMUDriverPtr driver = dom->conn->privateData;
7051
    int i, j;
7052 7053
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7054
    virDomainDefPtr persistentDef = NULL;
7055 7056 7057
    unsigned int val;
    int ret = -1;
    int rc;
7058
    virCapsPtr caps = NULL;
7059

7060
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7061 7062
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7063

7064 7065 7066
    /* 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.  */
7067 7068
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7069
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7070 7071

    if (vm == NULL) {
7072 7073
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7074 7075 7076
        goto cleanup;
    }

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

7080 7081 7082 7083 7084 7085 7086
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

7087
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
7088 7089
                                        &persistentDef) < 0)
        goto cleanup;
7090

7091 7092
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
7093 7094
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
7095 7096 7097 7098
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7099 7100
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7101 7102 7103 7104 7105
            goto cleanup;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7106
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117
            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;
                }
7118 7119
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
7120 7121
                    goto cleanup;
                break;
7122 7123 7124 7125
            case 1: /* blkiotune.device_weight */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;
7126

7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143
                    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);
                }
7144 7145 7146 7147
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
7148 7149
                    goto cleanup;
                break;
7150 7151 7152 7153

            default:
                break;
                /* should not hit here */
7154
            }
7155 7156
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7157
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7158 7159 7160 7161 7162 7163 7164 7165
            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) {
7166 7167 7168
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_WEIGHT);
7169 7170 7171 7172
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
7173

7174 7175 7176
            case 1: /* blkiotune.device_weight */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
7177 7178
                    bool comma = false;

7179
                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
7180 7181 7182
                        if (!persistentDef->blkio.devices[j].weight)
                            continue;
                        if (comma)
7183
                            virBufferAddChar(&buf, ',');
7184 7185
                        else
                            comma = true;
7186 7187 7188 7189 7190 7191 7192 7193 7194
                        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);
7195 7196
                }
                if (!param->value.s) {
7197 7198 7199 7200 7201 7202 7203 7204 7205
                    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) {
7206 7207 7208
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
7209 7210 7211 7212
                    goto cleanup;
                }
                break;

7213 7214 7215 7216
            default:
                break;
                /* should not hit here */
            }
7217 7218 7219
        }
    }

7220 7221
    if (QEMU_NB_BLKIO_PARAM < *nparams)
        *nparams = QEMU_NB_BLKIO_PARAM;
7222 7223 7224 7225 7226 7227
    ret = 0;

cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
7228
        virObjectUnlock(vm);
7229
    virObjectUnref(caps);
7230 7231
    return ret;
}
7232

7233 7234 7235 7236 7237
static int
qemuDomainSetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              unsigned int flags)
7238
{
7239
    virQEMUDriverPtr driver = dom->conn->privateData;
7240
    virDomainDefPtr persistentDef = NULL;
7241 7242
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7243 7244 7245 7246 7247 7248
    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;
7249
    virQEMUDriverConfigPtr cfg = NULL;
7250
    int ret = -1;
7251
    int rc;
7252
    virCapsPtr caps = NULL;
7253

7254 7255
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7256

7257 7258 7259 7260 7261 7262 7263 7264 7265
    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;
7266 7267


7268 7269
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
7270

7271 7272
    cfg = virQEMUDriverGetConfig(driver);

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

7276
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
7277 7278
                                        &persistentDef) < 0)
        goto cleanup;
7279

7280
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7281
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7282 7283
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7284 7285 7286 7287
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7288 7289
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7290 7291 7292 7293
            goto cleanup;
        }
    }

7294
#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE)                                \
7295
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0)  \
7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306
        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

7307 7308

    /* It will fail if hard limit greater than swap hard limit anyway */
7309 7310
    if (set_swap_hard_limit && set_memory_hard_limit &&
        memory_hard_limit > swap_hard_limit) {
7311
        virReportError(VIR_ERR_INVALID_ARG, "%s",
7312 7313
                       _("memory hard_limit tunable value must be lower than "
                         "swap_hard_limit"));
7314 7315 7316
        goto cleanup;
    }

7317
    if (set_swap_hard_limit) {
7318 7319 7320 7321 7322 7323 7324
        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;
7325
        }
7326

7327 7328
        if (flags & VIR_DOMAIN_AFFECT_CONFIG)
            persistentDef->mem.swap_hard_limit = swap_hard_limit;
7329 7330
    }

7331
    if (set_memory_hard_limit) {
7332 7333 7334 7335 7336 7337 7338
        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;
7339
        }
7340

7341 7342 7343
        if (flags & VIR_DOMAIN_AFFECT_CONFIG)
            persistentDef->mem.hard_limit = memory_hard_limit;
    }
7344

7345
    if (set_memory_soft_limit) {
7346 7347 7348 7349 7350 7351 7352
        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;
7353 7354
        }

7355 7356
        if (flags & VIR_DOMAIN_AFFECT_CONFIG)
            persistentDef->mem.soft_limit = memory_soft_limit;
7357 7358
    }

7359 7360 7361 7362 7363 7364
    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
        goto cleanup;

    ret = 0;

7365 7366
cleanup:
    virCgroupFree(&group);
7367
    virObjectUnlock(vm);
7368
    virObjectUnref(caps);
7369
    virObjectUnref(cfg);
7370 7371 7372
    return ret;
}

7373 7374 7375 7376 7377
static int
qemuDomainGetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int *nparams,
                              unsigned int flags)
7378
{
7379
    virQEMUDriverPtr driver = dom->conn->privateData;
7380 7381 7382
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7383
    virDomainDefPtr persistentDef = NULL;
7384 7385
    int ret = -1;
    int rc;
7386
    virCapsPtr caps = NULL;
7387

7388
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7389 7390
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7391

7392 7393 7394
    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7395
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7396 7397

    if (vm == NULL) {
7398 7399
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7400 7401 7402
        goto cleanup;
    }

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

7406
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
7407 7408
                                        &persistentDef) < 0)
        goto cleanup;
7409

7410
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7411
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7412 7413
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7414 7415 7416 7417
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7418 7419
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7420 7421 7422 7423
            goto cleanup;
        }
    }

7424 7425 7426 7427 7428 7429 7430
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

7431
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7432
        for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
7433 7434 7435 7436
            virMemoryParameterPtr param = &params[i];

            switch (i) {
            case 0: /* fill memory hard limit here */
7437 7438 7439 7440
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.hard_limit) < 0)
7441 7442 7443 7444
                    goto cleanup;
                break;

            case 1: /* fill memory soft limit here */
7445 7446 7447 7448
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.soft_limit) < 0)
7449 7450 7451 7452
                    goto cleanup;
                break;

            case 2: /* fill swap hard limit here */
7453 7454 7455 7456
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.swap_hard_limit) < 0)
7457 7458 7459 7460 7461 7462 7463 7464 7465
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
7466 7467
    }

7468
    for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
7469
        virTypedParameterPtr param = &params[i];
7470
        unsigned long long val = 0;
7471

7472 7473 7474
        /* Coverity does not realize that if we get here, group is set.  */
        sa_assert(group);

7475
        switch (i) {
7476 7477 7478 7479 7480
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
7481
                goto cleanup;
7482
            }
7483 7484 7485
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7486
                goto cleanup;
7487 7488 7489 7490 7491 7492 7493
            break;

        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
7494
                goto cleanup;
7495
            }
7496 7497 7498
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7499
                goto cleanup;
7500 7501 7502
            break;

        case 2: /* fill swap hard limit here */
7503
            rc = virCgroupGetMemSwapHardLimit(group, &val);
7504 7505 7506
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
7507
                goto cleanup;
7508
            }
7509 7510 7511
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7512
                goto cleanup;
7513 7514 7515 7516 7517 7518 7519 7520
            break;

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

7521
out:
7522 7523
    if (QEMU_NB_MEM_PARAM < *nparams)
        *nparams = QEMU_NB_MEM_PARAM;
7524 7525
    ret = 0;

7526 7527 7528 7529
cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
7530
        virObjectUnlock(vm);
7531
    virObjectUnref(caps);
7532 7533 7534
    return ret;
}

7535 7536 7537 7538 7539 7540
static int
qemuDomainSetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
7541
    virQEMUDriverPtr driver = dom->conn->privateData;
7542 7543 7544 7545 7546
    int i;
    virDomainDefPtr persistentDef = NULL;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
7547
    virQEMUDriverConfigPtr cfg = NULL;
7548
    virCapsPtr caps = NULL;
7549 7550 7551

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7552 7553 7554 7555 7556 7557 7558
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_NUMA_MODE,
                                       VIR_TYPED_PARAM_INT,
                                       VIR_DOMAIN_NUMA_NODESET,
                                       VIR_TYPED_PARAM_STRING,
                                       NULL) < 0)
        return -1;
7559

7560
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7561 7562

    if (vm == NULL) {
7563 7564
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7565 7566
        goto cleanup;
    }
7567
    cfg = virQEMUDriverGetConfig(driver);
7568

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

7572
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
7573 7574 7575 7576 7577
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
7578 7579
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup cpuset controller is not mounted"));
7580 7581 7582 7583
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7584 7585 7586
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597
            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) {
7598 7599
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("can't change numa mode for running domain"));
7600 7601 7602 7603 7604 7605 7606 7607 7608
                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;
7609
            virBitmapPtr nodeset = NULL;
7610 7611
            char *nodeset_str = NULL;

7612 7613 7614
            if (virBitmapParse(params[i].value.s,
                               0, &nodeset,
                               VIR_DOMAIN_CPUMASK_LEN) < 0) {
7615 7616 7617 7618 7619
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to parse nodeset"));
                ret = -1;
                continue;
            }
7620 7621 7622 7623

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                if (vm->def->numatune.memory.mode !=
                    VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
7624 7625 7626
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("change of nodeset for running domain "
                                     "requires strict numa mode"));
7627
                    virBitmapFree(nodeset);
7628 7629 7630
                    ret = -1;
                    continue;
                }
7631 7632

                /* Ensure the cpuset string is formated before passing to cgroup */
7633
                if (!(nodeset_str = virBitmapFormat(nodeset))) {
7634 7635
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("Failed to format nodeset"));
7636
                    virBitmapFree(nodeset);
7637 7638 7639 7640 7641
                    ret = -1;
                    continue;
                }

                if ((rc = virCgroupSetCpusetMems(group, nodeset_str) != 0)) {
7642 7643
                    virReportSystemError(-rc, "%s",
                                         _("unable to set numa tunable"));
7644
                    virBitmapFree(nodeset);
7645
                    VIR_FREE(nodeset_str);
7646 7647 7648
                    ret = -1;
                    continue;
                }
7649
                VIR_FREE(nodeset_str);
7650 7651 7652

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

7655
                vm->def->numatune.memory.placement_mode =
G
Gao feng 已提交
7656
                    VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
7657
                vm->def->numatune.memory.nodemask = virBitmapNewCopy(nodeset);
7658 7659 7660
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7661
                virBitmapFree(persistentDef->numatune.memory.nodemask);
7662 7663

                persistentDef->numatune.memory.nodemask = nodeset;
7664
                persistentDef->numatune.memory.placement_mode =
G
Gao feng 已提交
7665
                    VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
7666
                nodeset = NULL;
7667
            }
7668
            virBitmapFree(nodeset);
7669 7670 7671 7672
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7673 7674
        if (!persistentDef->numatune.memory.placement_mode)
            persistentDef->numatune.memory.placement_mode =
G
Gao feng 已提交
7675
                VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO;
7676
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
7677 7678 7679 7680 7681 7682
            ret = -1;
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
7683
        virObjectUnlock(vm);
7684
    virObjectUnref(caps);
7685
    virObjectUnref(cfg);
7686 7687 7688 7689 7690 7691 7692 7693 7694
    return ret;
}

static int
qemuDomainGetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
7695
    virQEMUDriverPtr driver = dom->conn->privateData;
7696 7697 7698 7699 7700 7701 7702
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    char *nodeset = NULL;
    int ret = -1;
    int rc;
7703
    virCapsPtr caps = NULL;
7704 7705 7706 7707 7708 7709 7710 7711 7712 7713

    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;

7714
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7715 7716

    if (vm == NULL) {
7717 7718
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7719 7720 7721
        goto cleanup;
    }

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

7725
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736
                                        &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)) {
7737 7738
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7739 7740 7741 7742
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7743 7744 7745
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7746 7747 7748 7749 7750 7751 7752 7753 7754
            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 */
7755 7756
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
7757 7758 7759 7760 7761 7762 7763 7764 7765
                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) {
7766 7767
                nodeset = virBitmapFormat(persistentDef->numatune.memory.nodemask);
                if (!nodeset)
7768 7769 7770 7771 7772 7773 7774 7775 7776
                    nodeset = strdup("");
            } else {
                rc = virCgroupGetCpusetMems(group, &nodeset);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get numa nodeset"));
                    goto cleanup;
                }
            }
7777 7778
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
7779
                goto cleanup;
S
Stefan Berger 已提交
7780 7781 7782

            nodeset = NULL;

7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795
            break;

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

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

cleanup:
S
Stefan Berger 已提交
7796
    VIR_FREE(nodeset);
7797 7798
    virCgroupFree(&group);
    if (vm)
7799
        virObjectUnlock(vm);
7800
    virObjectUnref(caps);
7801 7802 7803
    return ret;
}

7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815
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 已提交
7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835
    /* 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);
        }
7836 7837 7838 7839 7840 7841 7842 7843 7844
    }

    return 0;

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

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

7879 7880 7881 7882 7883 7884 7885 7886 7887
#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;                                                       \
    }

7888 7889 7890 7891 7892
static int
qemuSetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int nparams,
                                unsigned int flags)
7893
{
7894
    virQEMUDriverPtr driver = dom->conn->privateData;
7895 7896 7897
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7898
    virDomainDefPtr vmdef = NULL;
7899 7900
    unsigned long long value_ul;
    long long value_l;
7901
    int ret = -1;
7902
    int rc;
7903
    virQEMUDriverConfigPtr cfg = NULL;
7904
    virCapsPtr caps = NULL;
7905

7906 7907
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7908 7909 7910 7911 7912 7913 7914
    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,
7915 7916 7917 7918
                                       VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                                       VIR_TYPED_PARAM_LLONG,
7919 7920
                                       NULL) < 0)
        return -1;
7921

7922
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
7923 7924

    if (vm == NULL) {
7925 7926
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7927 7928 7929
        goto cleanup;
    }

7930 7931
    cfg = virQEMUDriverGetConfig(driver);

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

7935
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
7936 7937
                                        &vmdef) < 0)
        goto cleanup;
7938

7939 7940
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
7941
        vmdef = virDomainObjCopyPersistentDef(caps, driver->xmlconf, vm);
7942 7943
        if (!vmdef)
            goto cleanup;
7944 7945
    }

7946
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7947
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
7948 7949
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
7950 7951 7952
            goto cleanup;
        }
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7953 7954 7955
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7956 7957 7958 7959
            goto cleanup;
        }
    }

7960
    for (i = 0; i < nparams; i++) {
7961
        virTypedParameterPtr param = &params[i];
7962 7963
        value_ul = param->value.ul;
        value_l = param->value.l;
7964

7965
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
7966
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7967
                if ((rc = virCgroupSetCpuShares(group, value_ul))) {
7968 7969 7970 7971
                    virReportSystemError(-rc, "%s",
                                         _("unable to set cpu shares tunable"));
                    goto cleanup;
                }
7972
                vm->def->cputune.shares = value_ul;
7973
            }
7974

7975 7976 7977
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.shares = value_ul;

7978
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
7979 7980 7981
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

7982 7983
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
                if ((rc = qemuSetVcpusBWLive(vm, group, value_ul, 0)))
7984
                    goto cleanup;
7985

7986
                vm->def->cputune.period = value_ul;
7987 7988
            }

7989
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
7990
                vmdef->cputune.period = params[i].value.ul;
7991

7992
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
7993 7994 7995
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

7996 7997
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
                if ((rc = qemuSetVcpusBWLive(vm, group, 0, value_l)))
7998
                    goto cleanup;
7999

8000
                vm->def->cputune.quota = value_l;
8001 8002
            }

8003 8004 8005
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.quota = value_l;

8006
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD)) {
8007 8008 8009
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

8010 8011
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
                if ((rc = qemuSetEmulatorBandwidthLive(vm, group, value_ul, 0)))
8012 8013
                    goto cleanup;

8014
                vm->def->cputune.emulator_period = value_ul;
8015 8016
            }

8017 8018 8019
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_period = value_ul;

8020
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA)) {
8021 8022 8023
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

8024 8025
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
                if ((rc = qemuSetEmulatorBandwidthLive(vm, group, 0, value_l)))
8026 8027
                    goto cleanup;

8028
                vm->def->cputune.emulator_quota = value_l;
8029 8030
            }

8031 8032
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_quota = value_l;
8033 8034
        }
    }
8035

8036
    if (virDomainSaveStatus(driver->xmlconf, cfg->stateDir, vm) < 0)
8037 8038 8039 8040
        goto cleanup;


    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8041
        rc = virDomainSaveConfig(cfg->configDir, vmdef);
8042 8043 8044
        if (rc < 0)
            goto cleanup;

8045
        virDomainObjAssignDef(vm, vmdef, false, NULL);
8046 8047 8048
        vmdef = NULL;
    }

8049 8050 8051
    ret = 0;

cleanup:
8052
    virDomainDefFree(vmdef);
8053 8054
    virCgroupFree(&group);
    if (vm)
8055
        virObjectUnlock(vm);
8056
    virObjectUnref(caps);
8057
    virObjectUnref(cfg);
8058 8059
    return ret;
}
8060
#undef SCHED_RANGE_CHECK
8061

8062 8063 8064 8065
static int
qemuSetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int nparams)
8066 8067 8068 8069
{
    return qemuSetSchedulerParametersFlags(dom,
                                           params,
                                           nparams,
8070
                                           VIR_DOMAIN_AFFECT_CURRENT);
8071 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
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;
}

8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174
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;
}

8175 8176 8177 8178 8179
static int
qemuGetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int *nparams,
                                unsigned int flags)
8180
{
8181
    virQEMUDriverPtr driver = dom->conn->privateData;
8182 8183
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
8184 8185 8186
    unsigned long long shares;
    unsigned long long period;
    long long quota;
8187 8188
    unsigned long long emulator_period;
    long long emulator_quota;
8189 8190
    int ret = -1;
    int rc;
8191
    bool cpu_bw_status = false;
8192
    int saved_nparams = 0;
8193
    virDomainDefPtr persistentDef;
8194
    virCapsPtr caps = NULL;
8195

8196
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
8197 8198
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
8199

8200 8201 8202
    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

8203 8204 8205 8206 8207 8208 8209
    if (*nparams > 1) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        cpu_bw_status = !!rc;
    }

8210
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
8211 8212

    if (vm == NULL) {
8213 8214
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8215 8216 8217
        goto cleanup;
    }

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

8221
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
8222 8223
                                        &persistentDef) < 0)
        goto cleanup;
8224

8225
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8226 8227 8228 8229
        shares = persistentDef->cputune.shares;
        if (*nparams > 1 && cpu_bw_status) {
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
8230 8231
            emulator_period = persistentDef->cputune.emulator_period;
            emulator_quota = persistentDef->cputune.emulator_quota;
8232
        }
8233
        goto out;
8234 8235
    }

8236
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8237 8238
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
8239 8240 8241
        goto cleanup;
    }

8242
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
8243 8244
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
8245 8246 8247
        goto cleanup;
    }

8248
    rc = virCgroupGetCpuShares(group, &shares);
8249
    if (rc != 0) {
8250
        virReportSystemError(-rc, "%s",
8251 8252 8253
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
8254 8255 8256 8257 8258 8259

    if (*nparams > 1 && cpu_bw_status) {
        rc = qemuGetVcpusBWLive(vm, group, &period, &quota);
        if (rc != 0)
            goto cleanup;
    }
8260 8261 8262 8263 8264 8265 8266 8267

    if (*nparams > 3 && cpu_bw_status) {
        rc = qemuGetEmulatorBandwidthLive(vm, group, &emulator_period,
                                          &emulator_quota);
        if (rc != 0)
            goto cleanup;
    }

8268
out:
8269 8270
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
8271
        goto cleanup;
8272 8273 8274 8275
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
8276 8277 8278
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
8279 8280 8281 8282 8283
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
8284 8285 8286
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
8287 8288 8289
                goto cleanup;
            saved_nparams++;
        }
8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307

        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++;
        }
8308 8309 8310 8311
    }

    *nparams = saved_nparams;

8312 8313 8314 8315 8316
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
8317
        virObjectUnlock(vm);
8318
    virObjectUnref(caps);
8319 8320 8321
    return ret;
}

8322 8323 8324 8325 8326 8327
static int
qemuGetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int *nparams)
{
    return qemuGetSchedulerParametersFlags(dom, params, nparams,
8328
                                           VIR_DOMAIN_AFFECT_CURRENT);
8329
}
8330

8331 8332 8333 8334 8335 8336 8337
/**
 * 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 已提交
8338 8339 8340 8341
qemuDomainBlockResize(virDomainPtr dom,
                      const char *path,
                      unsigned long long size,
                      unsigned int flags)
8342
{
8343
    virQEMUDriverPtr driver = dom->conn->privateData;
8344 8345 8346 8347 8348 8349
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1, i;
    char *device = NULL;
    virDomainDiskDefPtr disk = NULL;

E
Eric Blake 已提交
8350
    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
8351 8352

    if (path[0] == '\0') {
8353 8354
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("empty path"));
8355 8356 8357
        return -1;
    }

E
Eric Blake 已提交
8358 8359 8360
    /* We prefer operating on bytes.  */
    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
        if (size > ULLONG_MAX / 1024) {
8361 8362 8363
            virReportError(VIR_ERR_OVERFLOW,
                           _("size must be less than %llu"),
                           ULLONG_MAX / 1024);
E
Eric Blake 已提交
8364 8365 8366
            return -1;
        }
        size *= 1024;
8367 8368
    }

8369
    if (!(vm = qemuDomObjFromDomain(dom)))
8370 8371 8372 8373 8374 8375 8376 8377
        goto cleanup;

    priv = vm->privateData;

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

    if (!virDomainObjIsActive(vm)) {
8378 8379
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8380 8381 8382 8383
        goto endjob;
    }

    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8384 8385
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
8386
        goto endjob;
8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411
    }
    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)
8412
        virObjectUnlock(vm);
8413 8414 8415
    return ret;
}

8416 8417 8418 8419 8420
/* 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
8421 8422 8423
qemuDomainBlockStats(virDomainPtr dom,
                     const char *path,
                     struct _virDomainBlockStats *stats)
8424
{
8425
    virQEMUDriverPtr driver = dom->conn->privateData;
8426
    int i, ret = -1;
8427
    virDomainObjPtr vm;
8428
    virDomainDiskDefPtr disk = NULL;
8429
    qemuDomainObjPrivatePtr priv;
8430

8431
    if (!(vm = qemuDomObjFromDomain(dom)))
8432
        goto cleanup;
8433

8434
    if (!virDomainObjIsActive(vm)) {
8435 8436
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8437 8438 8439
        goto cleanup;
    }

8440
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8441 8442
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
8443
        goto cleanup;
8444
    }
8445
    disk = vm->def->disks[i];
8446

8447
    if (!disk->info.alias) {
8448 8449
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
8450
        goto cleanup;
8451
    }
8452

8453
    priv = vm->privateData;
8454 8455
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;
8456

8457
    if (!virDomainObjIsActive(vm)) {
8458 8459
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8460 8461
        goto endjob;
    }
8462

8463
    qemuDomainObjEnterMonitor(driver, vm);
8464 8465 8466 8467
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
8468
                                       NULL,
8469 8470
                                       &stats->wr_req,
                                       &stats->wr_bytes,
8471 8472 8473
                                       NULL,
                                       NULL,
                                       NULL,
8474 8475
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
8476

8477
endjob:
8478 8479
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
8480

8481
cleanup:
8482
    if (vm)
8483
        virObjectUnlock(vm);
8484
    return ret;
8485 8486
}

8487
static int
8488 8489 8490 8491 8492
qemuDomainBlockStatsFlags(virDomainPtr dom,
                          const char *path,
                          virTypedParameterPtr params,
                          int *nparams,
                          unsigned int flags)
8493
{
8494
    virQEMUDriverPtr driver = dom->conn->privateData;
8495 8496 8497 8498 8499 8500
    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;
8501
    virTypedParameterPtr param;
8502

8503 8504 8505 8506
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

8508
    if (!(vm = qemuDomObjFromDomain(dom)))
8509 8510
        goto cleanup;

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

8514
    if (!virDomainObjIsActive(vm)) {
8515 8516
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8517
        goto endjob;
8518 8519 8520
    }

    if (*nparams != 0) {
8521
        if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8522 8523
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
8524
            goto endjob;
8525
        }
8526
        disk = vm->def->disks[i];
8527 8528

        if (!disk->info.alias) {
8529 8530 8531
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("missing disk device alias name for %s"),
                            disk->dst);
8532
             goto endjob;
8533 8534 8535 8536 8537 8538 8539 8540 8541 8542
        }
    }

    priv = vm->privateData;
    VIR_DEBUG("priv=%p, params=%p, flags=%x", priv, params, flags);

    qemuDomainObjEnterMonitor(driver, vm);
    tmp = *nparams;
    ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);

8543
    if (tmp == 0 || ret < 0) {
8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564
        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;

8565 8566
    tmp = 0;
    ret = -1;
8567

8568 8569
    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
8570 8571
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
8572 8573 8574
            goto endjob;
        tmp++;
    }
8575

8576
    if (tmp < *nparams && wr_req != -1) {
8577
        param = &params[tmp];
8578 8579
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
8580 8581 8582
            goto endjob;
        tmp++;
    }
8583

8584
    if (tmp < *nparams && rd_bytes != -1) {
8585
        param = &params[tmp];
8586 8587
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
8588 8589 8590
            goto endjob;
        tmp++;
    }
8591

8592
    if (tmp < *nparams && rd_req != -1) {
8593
        param = &params[tmp];
8594 8595
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
8596 8597 8598
            goto endjob;
        tmp++;
    }
8599

8600
    if (tmp < *nparams && flush_req != -1) {
8601
        param = &params[tmp];
8602 8603
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ,
                                    VIR_TYPED_PARAM_LLONG, flush_req) < 0)
8604 8605 8606
            goto endjob;
        tmp++;
    }
8607

8608
    if (tmp < *nparams && wr_total_times != -1) {
8609
        param = &params[tmp];
8610 8611 8612
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, wr_total_times) < 0)
8613 8614 8615
            goto endjob;
        tmp++;
    }
8616

8617
    if (tmp < *nparams && rd_total_times != -1) {
8618
        param = &params[tmp];
8619 8620 8621
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, rd_total_times) < 0)
8622 8623 8624
            goto endjob;
        tmp++;
    }
8625

8626
    if (tmp < *nparams && flush_total_times != -1) {
8627
        param = &params[tmp];
8628 8629 8630 8631
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG,
                                    flush_total_times) < 0)
8632 8633
            goto endjob;
        tmp++;
8634 8635
    }

8636 8637 8638 8639 8640
    /* Field 'errs' is meaningless for QEMU, won't set it. */

    ret = 0;
    *nparams = tmp;

8641 8642 8643 8644 8645 8646
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

cleanup:
    if (vm)
8647
        virObjectUnlock(vm);
8648 8649 8650
    return ret;
}

8651
#ifdef __linux__
8652
static int
8653 8654 8655
qemuDomainInterfaceStats(virDomainPtr dom,
                         const char *path,
                         struct _virDomainInterfaceStats *stats)
8656
{
8657
    virDomainObjPtr vm;
8658
    int i;
8659
    int ret = -1;
8660

8661
    if (!(vm = qemuDomObjFromDomain(dom)))
8662
        goto cleanup;
8663

D
Daniel P. Berrange 已提交
8664
    if (!virDomainObjIsActive(vm)) {
8665 8666
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8667
        goto cleanup;
8668 8669 8670
    }

    /* Check the path is one of the domain's network interfaces. */
8671 8672
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
8673
            STREQ(vm->def->nets[i]->ifname, path)) {
8674 8675 8676
            ret = 0;
            break;
        }
8677 8678
    }

8679
    if (ret == 0)
8680
        ret = linuxDomainInterfaceStats(path, stats);
8681
    else
8682 8683
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path, '%s' is not a known interface"), path);
8684

8685
cleanup:
8686
    if (vm)
8687
        virObjectUnlock(vm);
8688 8689
    return ret;
}
8690
#else
8691
static int
E
Eric Blake 已提交
8692
qemuDomainInterfaceStats(virDomainPtr dom ATTRIBUTE_UNUSED,
8693 8694
                         const char *path ATTRIBUTE_UNUSED,
                         struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
8695
{
8696 8697
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("interface stats not implemented on this platform"));
8698 8699
    return -1;
}
8700
#endif
8701

8702 8703 8704 8705 8706 8707 8708
static int
qemuDomainSetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 unsigned int flags)
{
8709
    virQEMUDriverPtr driver = dom->conn->privateData;
8710 8711 8712 8713 8714 8715
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    virDomainNetDefPtr net = NULL, persistentNet = NULL;
8716
    virNetDevBandwidthPtr bandwidth = NULL, newBandwidth = NULL;
8717
    virQEMUDriverConfigPtr cfg = NULL;
8718
    virCapsPtr caps = NULL;
8719 8720 8721

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736
    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;
8737

8738
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
8739 8740

    if (vm == NULL) {
8741 8742
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8743 8744 8745
        goto cleanup;
    }

8746 8747
    cfg = virQEMUDriverGetConfig(driver);

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

8751
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
8752 8753 8754 8755 8756 8757
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        net = virDomainNetFind(vm->def, device);
        if (!net) {
8758 8759
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
8760 8761 8762 8763 8764 8765
            goto cleanup;
        }
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        persistentNet = virDomainNetFind(persistentDef, device);
        if (!persistentNet) {
8766 8767
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
8768 8769 8770 8771
            goto cleanup;
        }
    }

8772 8773 8774
    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
        (VIR_ALLOC(bandwidth->out) < 0)) {
8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796
        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;
        }
    }

8797
    /* average is mandatory, peak and burst are optional. So if no
8798
     * average is given, we free inbound/outbound here which causes
8799
     * inbound/outbound to not be set. */
8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814
    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
8815
         * here to prevent them from being lost. */
8816 8817
        if (bandwidth->in ||
            (net->bandwidth && net->bandwidth->in)) {
8818 8819 8820 8821
            if (VIR_ALLOC(newBandwidth->in) < 0) {
                virReportOOMError();
                goto cleanup;
            }
8822 8823 8824 8825 8826 8827 8828

            memcpy(newBandwidth->in,
                   bandwidth->in ? bandwidth->in : net->bandwidth->in,
                   sizeof(*newBandwidth->in));
        }
        if (bandwidth->out ||
            (net->bandwidth && net->bandwidth->out)) {
8829 8830 8831 8832
            if (VIR_ALLOC(newBandwidth->out) < 0) {
                virReportOOMError();
                goto cleanup;
            }
8833 8834 8835 8836

            memcpy(newBandwidth->out,
                   bandwidth->out ? bandwidth->out : net->bandwidth->out,
                   sizeof(*newBandwidth->out));
8837 8838
        }

8839
        if (virNetDevBandwidthSet(net->ifname, newBandwidth, false) < 0) {
8840 8841 8842
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot set bandwidth limits on %s"),
                           device);
8843 8844 8845 8846 8847
            goto cleanup;
        }

        virNetDevBandwidthFree(net->bandwidth);
        net->bandwidth = newBandwidth;
E
Eric Blake 已提交
8848
        newBandwidth = NULL;
8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866
    }
    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;
            }
        }

8867
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
8868 8869 8870 8871 8872 8873
            goto cleanup;
    }

    ret = 0;
cleanup:
    virNetDevBandwidthFree(bandwidth);
8874
    virNetDevBandwidthFree(newBandwidth);
8875 8876
    virCgroupFree(&group);
    if (vm)
8877
        virObjectUnlock(vm);
8878
    virObjectUnref(caps);
8879
    virObjectUnref(cfg);
8880 8881 8882 8883 8884 8885 8886 8887 8888 8889
    return ret;
}

static int
qemuDomainGetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int *nparams,
                                 unsigned int flags)
{
8890
    virQEMUDriverPtr driver = dom->conn->privateData;
8891 8892 8893 8894 8895 8896 8897
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainDefPtr persistentDef = NULL;
    virDomainNetDefPtr net = NULL;
    int ret = -1;
8898
    virCapsPtr caps = NULL;
8899 8900 8901 8902 8903 8904 8905

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

8906
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
8907 8908

    if (vm == NULL) {
8909 8910
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8911 8912 8913
        goto cleanup;
    }

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

8917
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlconf, vm, &flags,
8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932
                                        &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) {
8933 8934
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Can't find device %s"), device);
8935 8936 8937 8938
        goto cleanup;
    }

    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
8939
        switch (i) {
8940
        case 0: /* inbound.average */
8941 8942 8943
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8944 8945 8946 8947 8948
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->average;
            break;
        case 1: /* inbound.peak */
8949 8950 8951
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8952 8953 8954 8955 8956
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->peak;
            break;
        case 2: /* inbound.burst */
8957 8958 8959
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8960 8961 8962 8963 8964
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->burst;
            break;
        case 3: /* outbound.average */
8965 8966 8967
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8968 8969 8970 8971 8972
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->average;
            break;
        case 4: /* outbound.peak */
8973 8974 8975
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8976 8977 8978 8979 8980
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->peak;
            break;
        case 5: /* outbound.burst */
8981 8982 8983
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001
                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)
9002
        virObjectUnlock(vm);
9003
    virObjectUnref(caps);
9004 9005 9006
    return ret;
}

9007
static int
9008 9009 9010 9011
qemuDomainMemoryStats(virDomainPtr dom,
                      struct _virDomainMemoryStat *stats,
                      unsigned int nr_stats,
                      unsigned int flags)
9012
{
9013
    virQEMUDriverPtr driver = dom->conn->privateData;
9014
    virDomainObjPtr vm;
M
Martin Kletzander 已提交
9015
    int ret = -1;
9016

9017 9018
    virCheckFlags(0, -1);

9019
    if (!(vm = qemuDomObjFromDomain(dom)))
9020 9021
        goto cleanup;

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

M
Martin Kletzander 已提交
9025
    if (!virDomainObjIsActive(vm)) {
9026 9027
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
M
Martin Kletzander 已提交
9028
    } else {
9029
        qemuDomainObjPrivatePtr priv = vm->privateData;
9030
        qemuDomainObjEnterMonitor(driver, vm);
9031
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
9032
        qemuDomainObjExitMonitor(driver, vm);
M
Martin Kletzander 已提交
9033 9034 9035

        if (ret >= 0 && ret < nr_stats) {
            long rss;
9036
            if (qemuGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) {
9037 9038
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("cannot get RSS for domain"));
M
Martin Kletzander 已提交
9039 9040 9041 9042 9043 9044 9045
            } else {
                stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
                stats[ret].val = rss;
                ret++;
            }

        }
9046 9047
    }

9048
    if (qemuDomainObjEndJob(driver, vm) == 0)
9049 9050
        vm = NULL;

9051 9052
cleanup:
    if (vm)
9053
        virObjectUnlock(vm);
9054 9055 9056
    return ret;
}

9057
static int
9058 9059 9060 9061 9062
qemuDomainBlockPeek(virDomainPtr dom,
                    const char *path,
                    unsigned long long offset, size_t size,
                    void *buffer,
                    unsigned int flags)
9063
{
9064
    virDomainObjPtr vm;
9065 9066
    int fd = -1, ret = -1;
    const char *actual;
9067

E
Eric Blake 已提交
9068 9069
    virCheckFlags(0, -1);

9070
    if (!(vm = qemuDomObjFromDomain(dom)))
9071
        goto cleanup;
9072 9073

    if (!path || path[0] == '\0') {
9074 9075
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
9076
        goto cleanup;
9077 9078
    }

9079 9080
    /* Check the path belongs to this domain.  */
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
9081 9082
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path '%s'"), path);
9083
        goto cleanup;
9084
    }
9085
    path = actual;
9086

9087 9088 9089 9090 9091 9092 9093
    /* 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;
    }
9094

9095 9096 9097 9098 9099 9100 9101 9102 9103
    /* 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;
9104 9105
    }

9106 9107
    ret = 0;

9108
cleanup:
9109
    VIR_FORCE_CLOSE(fd);
9110
    if (vm)
9111
        virObjectUnlock(vm);
9112 9113 9114
    return ret;
}

R
Richard W.M. Jones 已提交
9115
static int
9116 9117 9118 9119
qemuDomainMemoryPeek(virDomainPtr dom,
                     unsigned long long offset, size_t size,
                     void *buffer,
                     unsigned int flags)
R
Richard W.M. Jones 已提交
9120
{
9121
    virQEMUDriverPtr driver = dom->conn->privateData;
9122
    virDomainObjPtr vm;
9123
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
9124
    int fd = -1, ret = -1;
9125
    qemuDomainObjPrivatePtr priv;
9126
    virQEMUDriverConfigPtr cfg = NULL;
R
Richard W.M. Jones 已提交
9127

9128 9129
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

9130
    if (!(vm = qemuDomObjFromDomain(dom)))
9131 9132
        goto cleanup;

9133 9134
    cfg = virQEMUDriverGetConfig(driver);

9135
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
9136 9137
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
9138
        goto cleanup;
R
Richard W.M. Jones 已提交
9139 9140
    }

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

D
Daniel P. Berrange 已提交
9144
    if (!virDomainObjIsActive(vm)) {
9145 9146
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9147
        goto endjob;
R
Richard W.M. Jones 已提交
9148 9149
    }

9150
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", cfg->cacheDir) < 0) {
9151
        virReportOOMError();
9152
        goto endjob;
9153 9154
    }

R
Richard W.M. Jones 已提交
9155
    /* Create a temporary filename. */
9156
    if ((fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
9157
        virReportSystemError(errno,
9158
                             _("mkostemp(\"%s\") failed"), tmp);
9159
        goto endjob;
R
Richard W.M. Jones 已提交
9160 9161
    }

9162
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
9163

9164
    priv = vm->privateData;
9165
    qemuDomainObjEnterMonitor(driver, vm);
9166
    if (flags == VIR_MEMORY_VIRTUAL) {
9167
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
9168
            qemuDomainObjExitMonitor(driver, vm);
9169
            goto endjob;
9170
        }
9171
    } else {
9172
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
9173
            qemuDomainObjExitMonitor(driver, vm);
9174
            goto endjob;
9175
        }
R
Richard W.M. Jones 已提交
9176
    }
9177
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
9178 9179

    /* Read the memory file into buffer. */
9180
    if (saferead(fd, buffer, size) == (ssize_t) -1) {
9181 9182 9183
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
9184
        goto endjob;
R
Richard W.M. Jones 已提交
9185 9186 9187
    }

    ret = 0;
9188

9189
endjob:
9190
    if (qemuDomainObjEndJob(driver, vm) == 0)
9191
        vm = NULL;
9192

9193
cleanup:
9194
    VIR_FORCE_CLOSE(fd);
9195 9196
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
9197
    VIR_FREE(tmp);
9198
    if (vm)
9199
        virObjectUnlock(vm);
9200
    virObjectUnref(cfg);
R
Richard W.M. Jones 已提交
9201 9202 9203
    return ret;
}

9204

9205 9206 9207 9208
static int qemuDomainGetBlockInfo(virDomainPtr dom,
                                  const char *path,
                                  virDomainBlockInfoPtr info,
                                  unsigned int flags) {
9209
    virQEMUDriverPtr driver = dom->conn->privateData;
9210 9211 9212 9213
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
9214
    virStorageFileMetadata *meta = NULL;
9215
    virDomainDiskDefPtr disk = NULL;
9216
    struct stat sb;
9217
    int i;
9218
    int format;
9219
    virQEMUDriverConfigPtr cfg = NULL;
9220 9221 9222

    virCheckFlags(0, -1);

9223
    if (!(vm = qemuDomObjFromDomain(dom)))
9224 9225
        goto cleanup;

9226 9227
    cfg = virQEMUDriverGetConfig(driver);

9228
    if (!path || path[0] == '\0') {
9229 9230
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
9231 9232 9233 9234
        goto cleanup;
    }

    /* Check the path belongs to this domain. */
9235
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9236 9237
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path %s not assigned to domain"), path);
9238 9239
        goto cleanup;
    }
9240 9241
    disk = vm->def->disks[i];
    if (!disk->src) {
9242 9243 9244
        virReportError(VIR_ERR_INVALID_ARG,
                       _("disk %s does not currently have a source assigned"),
                       path);
9245 9246 9247
        goto cleanup;
    }
    path = disk->src;
9248 9249

    /* The path is correct, now try to open it and get its size. */
9250
    fd = open(path, O_RDONLY);
9251 9252 9253 9254 9255 9256 9257
    if (fd == -1) {
        virReportSystemError(errno,
                             _("failed to open path '%s'"), path);
        goto cleanup;
    }

    /* Probe for magic formats */
9258 9259
    if (disk->format) {
        format = disk->format;
9260
    } else {
9261 9262 9263 9264
        if (cfg->allowDiskFormatProbing) {
            if ((format = virStorageFileProbeFormat(disk->src,
                                                    cfg->user,
                                                    cfg->group)) < 0)
9265 9266
                goto cleanup;
        } else {
9267 9268 9269
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no disk format for %s and probing is disabled"),
                           disk->src);
9270
            goto cleanup;
9271
        }
9272 9273
    }

9274
    if (!(meta = virStorageFileGetMetadataFromFD(path, fd, format)))
9275 9276 9277 9278 9279 9280 9281 9282 9283 9284
        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)) {
9285
#ifndef WIN32
9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298
        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.
         */
9299
        end = lseek(fd, 0, SEEK_END);
9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310
        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 */
9311 9312
    if (meta->capacity)
        info->capacity = meta->capacity;
9313

9314
    /* Set default value .. */
9315 9316
    info->allocation = info->physical;

9317 9318 9319
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
9320
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
9321
        format != VIR_STORAGE_FILE_RAW &&
9322 9323
        S_ISBLK(sb.st_mode) &&
        virDomainObjIsActive(vm)) {
9324
        qemuDomainObjPrivatePtr priv = vm->privateData;
9325

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

9329
        if (virDomainObjIsActive(vm)) {
9330
            qemuDomainObjEnterMonitor(driver, vm);
9331 9332 9333 9334
            ret = qemuMonitorGetBlockExtent(priv->mon,
                                            disk->info.alias,
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
9335
        } else {
9336
            ret = 0;
9337
        }
9338 9339 9340

        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
9341 9342 9343
    } else {
        ret = 0;
    }
9344 9345

cleanup:
9346
    virStorageFileFreeMetadata(meta);
9347
    VIR_FORCE_CLOSE(fd);
9348
    if (vm)
9349
        virObjectUnlock(vm);
9350
    virObjectUnref(cfg);
9351 9352 9353 9354
    return ret;
}


9355
static int
9356 9357 9358 9359
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
9360
{
9361
    virQEMUDriverPtr driver = conn->privateData;
9362 9363
    int ret;

9364 9365 9366
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
9367

9368
    return ret;
9369 9370
}

9371

9372
static int
9373 9374
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
9375
{
9376
    virQEMUDriverPtr driver = conn->privateData;
9377 9378
    int ret;

9379 9380 9381
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
9382

9383
    return ret;
9384 9385
}

9386 9387 9388 9389 9390 9391 9392 9393 9394

static int
qemuDomainEventRegisterAny(virConnectPtr conn,
                           virDomainPtr dom,
                           int eventID,
                           virConnectDomainEventGenericCallback callback,
                           void *opaque,
                           virFreeCallback freecb)
{
9395
    virQEMUDriverPtr driver = conn->privateData;
9396 9397
    int ret;

9398 9399 9400 9401
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
9402
        ret = -1;
9403 9404 9405 9406 9407 9408 9409 9410 9411

    return ret;
}


static int
qemuDomainEventDeregisterAny(virConnectPtr conn,
                             int callbackID)
{
9412
    virQEMUDriverPtr driver = conn->privateData;
9413 9414
    int ret;

9415 9416 9417
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
9418 9419 9420 9421 9422

    return ret;
}


9423 9424 9425
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
9426

C
Chris Lalancette 已提交
9427 9428 9429 9430 9431 9432
/* 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
9433 9434 9435 9436 9437 9438
qemuDomainMigratePrepareTunnel(virConnectPtr dconn,
                               virStreamPtr st,
                               unsigned long flags,
                               const char *dname,
                               unsigned long resource ATTRIBUTE_UNUSED,
                               const char *dom_xml)
C
Chris Lalancette 已提交
9439
{
9440
    virQEMUDriverPtr driver = dconn->privateData;
C
Chris Lalancette 已提交
9441
    int ret = -1;
9442

9443
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9444

C
Chris Lalancette 已提交
9445
    if (!dom_xml) {
9446 9447
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
9448 9449 9450
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9451 9452
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
C
Chris Lalancette 已提交
9453 9454 9455
        goto cleanup;
    }
    if (st == NULL) {
9456 9457
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
9458 9459 9460
        goto cleanup;
    }

9461
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9462 9463 9464
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9465 9466 9467
        goto cleanup;
    }

9468 9469
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
L
liguang 已提交
9470
                                     st, dname, dom_xml, flags);
9471

C
Chris Lalancette 已提交
9472 9473 9474 9475
cleanup:
    return ret;
}

D
Daniel Veillard 已提交
9476 9477 9478 9479
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
9480
static int ATTRIBUTE_NONNULL(5)
9481 9482 9483 9484 9485 9486 9487 9488 9489
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 已提交
9490
{
9491
    virQEMUDriverPtr driver = dconn->privateData;
9492
    int ret = -1;
9493

9494
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
9495

9496
    *uri_out = NULL;
D
Daniel Veillard 已提交
9497

9498
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9499 9500 9501
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9502 9503 9504
        goto cleanup;
    }

C
Chris Lalancette 已提交
9505 9506 9507 9508
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9509 9510
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
9511 9512 9513
        goto cleanup;
    }

D
Daniel Veillard 已提交
9514
    if (!dom_xml) {
9515 9516
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9517
        goto cleanup;
D
Daniel Veillard 已提交
9518 9519
    }

9520 9521 9522 9523
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
9524
    ret = qemuMigrationPrepareDirect(driver, dconn,
9525
                                     NULL, 0, NULL, NULL, /* No cookies */
9526
                                     uri_in, uri_out,
L
liguang 已提交
9527
                                     dname, dom_xml, flags);
D
Daniel Veillard 已提交
9528

9529 9530 9531
cleanup:
    return ret;
}
C
Chris Lalancette 已提交
9532

D
Daniel Veillard 已提交
9533

9534 9535
/* Perform is the second step, and it runs on the source host. */
static int
9536 9537 9538 9539 9540 9541 9542
qemuDomainMigratePerform(virDomainPtr dom,
                         const char *cookie,
                         int cookielen,
                         const char *uri,
                         unsigned long flags,
                         const char *dname,
                         unsigned long resource)
9543
{
9544
    virQEMUDriverPtr driver = dom->conn->privateData;
9545 9546
    virDomainObjPtr vm;
    int ret = -1;
9547
    const char *dconnuri = NULL;
9548

9549
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
9550

9551
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9552 9553 9554
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9555 9556 9557
        goto cleanup;
    }

9558
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
D
Daniel Veillard 已提交
9559
    if (!vm) {
9560 9561
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9562 9563
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9564
        goto cleanup;
D
Daniel Veillard 已提交
9565 9566
    }

9567 9568 9569 9570 9571
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

9572 9573 9574 9575 9576 9577
    /* 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
     */
9578
    ret = qemuMigrationPerform(driver, dom->conn, vm,
9579
                               NULL, dconnuri, uri, cookie, cookielen,
9580
                               NULL, NULL, /* No output cookies in v2 */
9581
                               flags, dname, resource, false);
9582

9583
cleanup:
9584
    return ret;
D
Daniel Veillard 已提交
9585 9586
}

9587

D
Daniel Veillard 已提交
9588 9589
/* Finish is the third and final step, and it runs on the destination host. */
static virDomainPtr
9590 9591 9592 9593 9594 9595 9596
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 已提交
9597
{
9598
    virQEMUDriverPtr driver = dconn->privateData;
9599 9600
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
9601

9602
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
9603

9604
    vm = virDomainObjListFindByName(driver->domains, dname);
D
Daniel Veillard 已提交
9605
    if (!vm) {
9606 9607
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
9608
        goto cleanup;
D
Daniel Veillard 已提交
9609 9610
    }

9611 9612 9613 9614
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
9615
    dom = qemuMigrationFinish(driver, dconn, vm,
9616
                              NULL, 0, NULL, NULL, /* No cookies */
9617
                              flags, retcode, false);
9618

9619 9620
cleanup:
    return dom;
D
Daniel Veillard 已提交
9621 9622
}

9623

9624 9625 9626 9627 9628 9629
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
9630
                        const char *xmlin,
9631 9632 9633
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
9634
                        const char *dname,
9635 9636
                        unsigned long resource ATTRIBUTE_UNUSED)
{
9637
    virQEMUDriverPtr driver = domain->conn->privateData;
9638 9639
    virDomainObjPtr vm;
    char *xml = NULL;
9640
    enum qemuDomainAsyncJob asyncJob;
9641

9642
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9643

9644
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
9645 9646 9647
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
9648 9649
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9650 9651 9652
        goto cleanup;
    }

9653 9654 9655
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cleanup;
9656
        asyncJob = QEMU_ASYNC_JOB_MIGRATION_OUT;
9657
    } else {
9658
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
9659
            goto cleanup;
9660
        asyncJob = QEMU_ASYNC_JOB_NONE;
9661 9662
    }

L
liguang 已提交
9663
    if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
9664 9665
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9666 9667 9668
        goto endjob;
    }

9669 9670 9671
    /* Check if there is any ejected media.
     * We don't want to require them on the destination.
     */
L
liguang 已提交
9672 9673
    if (!(flags & VIR_MIGRATE_OFFLINE) &&
        qemuDomainCheckEjectableMedia(driver, vm, asyncJob) < 0)
9674 9675
        goto endjob;

9676
    if (!(xml = qemuMigrationBegin(driver, vm, xmlin, dname,
9677 9678
                                   cookieout, cookieoutlen,
                                   flags)))
9679 9680 9681 9682 9683 9684 9685
        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.
         */
9686 9687
        if (virQEMUCloseCallbacksSet(driver->closeCallbacks, vm, domain->conn,
                                     qemuMigrationCleanup) < 0)
9688
            goto endjob;
9689 9690
        if (qemuMigrationJobContinue(vm) == 0) {
            vm = NULL;
9691 9692
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("domain disappeared"));
9693 9694 9695 9696 9697 9698 9699
            VIR_FREE(xml);
            if (cookieout)
                VIR_FREE(*cookieout);
        }
    } else {
        goto endjob;
    }
9700 9701

cleanup:
9702
    if (vm)
9703
        virObjectUnlock(vm);
9704
    return xml;
9705 9706 9707 9708 9709 9710 9711 9712 9713 9714

endjob:
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobFinish(driver, vm) == 0)
            vm = NULL;
    } else {
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    }
    goto cleanup;
9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729
}

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)
{
9730
    virQEMUDriverPtr driver = dconn->privateData;
9731 9732
    int ret = -1;

9733
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9734 9735 9736 9737 9738 9739 9740

    *uri_out = NULL;

    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9741 9742
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Tunnelled migration requested but invalid RPC method called"));
9743 9744 9745 9746
        goto cleanup;
    }

    if (!dom_xml) {
9747 9748
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9749 9750 9751 9752 9753 9754 9755
        goto cleanup;
    }

    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
L
liguang 已提交
9756
                                     dname, dom_xml, flags);
9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774

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)
{
9775
    virQEMUDriverPtr driver = dconn->privateData;
9776 9777
    int ret = -1;

9778
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9779 9780

    if (!dom_xml) {
9781 9782
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9783 9784 9785
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9786 9787
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
9788 9789 9790
        goto cleanup;
    }
    if (st == NULL) {
9791 9792
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("tunnelled migration requested but NULL stream passed"));
9793 9794 9795 9796 9797 9798
        goto cleanup;
    }

    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
L
liguang 已提交
9799
                                     st, dname, dom_xml, flags);
9800 9801 9802 9803 9804 9805 9806 9807

cleanup:
    return ret;
}


static int
qemuDomainMigratePerform3(virDomainPtr dom,
9808
                          const char *xmlin,
9809 9810 9811 9812
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
9813
                          const char *dconnuri,
9814 9815 9816 9817 9818
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
9819
    virQEMUDriverPtr driver = dom->conn->privateData;
9820 9821 9822
    virDomainObjPtr vm;
    int ret = -1;

9823
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9824

9825
    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
9826 9827 9828
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9829 9830
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9831 9832 9833
        goto cleanup;
    }

9834
    ret = qemuMigrationPerform(driver, dom->conn, vm, xmlin,
9835
                               dconnuri, uri, cookiein, cookieinlen,
9836
                               cookieout, cookieoutlen,
9837
                               flags, dname, resource, true);
9838 9839 9840 9841 9842 9843

cleanup:
    return ret;
}


9844
static virDomainPtr
9845 9846 9847 9848 9849 9850
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
9851
                         const char *dconnuri ATTRIBUTE_UNUSED,
9852 9853
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
9854
                         int cancelled)
9855
{
9856
    virQEMUDriverPtr driver = dconn->privateData;
9857
    virDomainObjPtr vm;
9858
    virDomainPtr dom = NULL;
9859

9860
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9861

9862
    vm = virDomainObjListFindByName(driver->domains, dname);
9863
    if (!vm) {
9864 9865
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
9866 9867 9868
        goto cleanup;
    }

9869 9870 9871 9872
    dom = qemuMigrationFinish(driver, dconn, vm,
                              cookiein, cookieinlen,
                              cookieout, cookieoutlen,
                              flags, cancelled, true);
9873 9874

cleanup:
9875
    return dom;
9876 9877 9878 9879 9880 9881 9882 9883 9884
}

static int
qemuDomainMigrateConfirm3(virDomainPtr domain,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned long flags,
                          int cancelled)
{
9885
    virQEMUDriverPtr driver = domain->conn->privateData;
9886 9887
    virDomainObjPtr vm;
    int ret = -1;
9888
    enum qemuMigrationJobPhase phase;
9889
    virQEMUDriverConfigPtr cfg = NULL;
9890

9891
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9892

9893
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
9894 9895 9896
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
9897 9898
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9899 9900 9901
        goto cleanup;
    }

9902 9903
    cfg = virQEMUDriverGetConfig(driver);

9904
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
9905 9906
        goto cleanup;

9907 9908 9909 9910 9911 9912
    if (cancelled)
        phase = QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED;
    else
        phase = QEMU_MIGRATION_PHASE_CONFIRM3;

    qemuMigrationJobStartPhase(driver, vm, phase);
9913 9914
    virQEMUCloseCallbacksUnset(driver->closeCallbacks, vm,
                               qemuMigrationCleanup);
9915

9916 9917
    ret = qemuMigrationConfirm(driver, domain->conn, vm,
                               cookiein, cookieinlen,
9918 9919
                               flags, cancelled);

9920
    if (qemuMigrationJobFinish(driver, vm) == 0) {
9921 9922 9923 9924
        vm = NULL;
    } else if (!virDomainObjIsActive(vm) &&
               (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE))) {
        if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
9925
            virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm);
9926
        qemuDomainRemoveInactive(driver, vm);
9927 9928 9929
        vm = NULL;
    }

9930
cleanup:
9931
    if (vm)
9932
        virObjectUnlock(vm);
9933
    virObjectUnref(cfg);
9934 9935 9936 9937
    return ret;
}


9938
static int
9939 9940 9941 9942 9943
qemuNodeDeviceGetPciInfo(virNodeDevicePtr dev,
                         unsigned *domain,
                         unsigned *bus,
                         unsigned *slot,
                         unsigned *function)
9944 9945 9946 9947 9948 9949 9950 9951 9952 9953
{
    virNodeDeviceDefPtr def = NULL;
    virNodeDevCapsDefPtr cap;
    char *xml = NULL;
    int ret = -1;

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto out;

9954
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971
    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) {
9972 9973
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device %s is not a PCI device"), dev->name);
9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
9985
qemuNodeDeviceDettach(virNodeDevicePtr dev)
9986
{
9987
    virQEMUDriverPtr driver = dev->conn->privateData;
9988
    virPCIDevicePtr pci;
9989 9990
    unsigned domain, bus, slot, function;
    int ret = -1;
9991
    bool in_inactive_list = false;
9992

9993
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
9994 9995
        return -1;

9996
    pci = virPCIDeviceNew(domain, bus, slot, function);
9997 9998 9999
    if (!pci)
        return -1;

10000 10001
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
10002
    in_inactive_list = virPCIDeviceListFind(driver->inactivePciHostdevs, pci);
10003

10004 10005
    if (virPCIDeviceDetach(pci, driver->activePciHostdevs,
                           driver->inactivePciHostdevs, "pci-stub") < 0)
10006 10007 10008 10009
        goto out;

    ret = 0;
out:
10010 10011
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
10012
    if (in_inactive_list)
10013
        virPCIDeviceFree(pci);
10014 10015 10016 10017
    return ret;
}

static int
10018
qemuNodeDeviceReAttach(virNodeDevicePtr dev)
10019
{
10020
    virQEMUDriverPtr driver = dev->conn->privateData;
10021 10022
    virPCIDevicePtr pci;
    virPCIDevicePtr other;
10023 10024 10025
    unsigned domain, bus, slot, function;
    int ret = -1;

10026
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
10027 10028
        return -1;

10029
    pci = virPCIDeviceNew(domain, bus, slot, function);
10030 10031 10032
    if (!pci)
        return -1;

10033 10034
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
10035
    other = virPCIDeviceListFind(driver->activePciHostdevs, pci);
10036
    if (other) {
10037
        const char *other_name = virPCIDeviceGetUsedBy(other);
10038 10039

        if (other_name)
10040 10041
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use by domain %s"),
10042
                           virPCIDeviceGetName(pci), other_name);
10043
        else
10044 10045
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use"),
10046
                           virPCIDeviceGetName(pci));
10047
        goto out;
10048 10049
    }

10050
    virPCIDeviceReattachInit(pci);
10051

10052 10053
    if (virPCIDeviceReattach(pci, driver->activePciHostdevs,
                             driver->inactivePciHostdevs, "pci-stub") < 0)
10054 10055 10056 10057
        goto out;

    ret = 0;
out:
10058 10059
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
10060
    virPCIDeviceFree(pci);
10061 10062 10063 10064
    return ret;
}

static int
10065
qemuNodeDeviceReset(virNodeDevicePtr dev)
10066
{
10067
    virQEMUDriverPtr driver = dev->conn->privateData;
10068
    virPCIDevicePtr pci;
10069 10070 10071
    unsigned domain, bus, slot, function;
    int ret = -1;

10072
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
10073 10074
        return -1;

10075
    pci = virPCIDeviceNew(domain, bus, slot, function);
10076 10077 10078
    if (!pci)
        return -1;

10079 10080
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
10081

10082 10083
    if (virPCIDeviceReset(pci, driver->activePciHostdevs,
                          driver->inactivePciHostdevs) < 0)
10084 10085 10086 10087
        goto out;

    ret = 0;
out:
10088 10089
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
10090
    virPCIDeviceFree(pci);
10091 10092 10093
    return ret;
}

10094 10095 10096
static int
qemuCPUCompare(virConnectPtr conn,
               const char *xmlDesc,
E
Eric Blake 已提交
10097
               unsigned int flags)
10098
{
10099
    virQEMUDriverPtr driver = conn->privateData;
10100
    int ret = VIR_CPU_COMPARE_ERROR;
10101
    virCapsPtr caps = NULL;
10102

E
Eric Blake 已提交
10103 10104
    virCheckFlags(0, VIR_CPU_COMPARE_ERROR);

10105 10106 10107 10108 10109
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!caps->host.cpu ||
        !caps->host.cpu->model) {
10110 10111
        VIR_WARN("cannot get host CPU capabilities");
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
E
Eric Blake 已提交
10112
    } else {
10113
        ret = cpuCompareXML(caps->host.cpu, xmlDesc);
E
Eric Blake 已提交
10114
    }
10115

10116 10117
cleanup:
    virObjectUnref(caps);
10118 10119 10120
    return ret;
}

10121

10122 10123 10124 10125
static char *
qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED,
                const char **xmlCPUs,
                unsigned int ncpus,
E
Eric Blake 已提交
10126
                unsigned int flags)
10127 10128 10129
{
    char *cpu;

E
Eric Blake 已提交
10130 10131
    virCheckFlags(0, NULL);

10132 10133 10134 10135 10136
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0);

    return cpu;
}

10137 10138 10139 10140 10141 10142 10143

static int qemuDomainGetJobInfo(virDomainPtr dom,
                                virDomainJobInfoPtr info) {
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

10144
    if (!(vm = qemuDomObjFromDomain(dom)))
10145 10146 10147 10148 10149
        goto cleanup;

    priv = vm->privateData;

    if (virDomainObjIsActive(vm)) {
10150
        if (priv->job.asyncJob && !priv->job.dump_memory_only) {
10151
            memcpy(info, &priv->job.info, sizeof(*info));
10152 10153 10154 10155 10156 10157

            /* 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
             */
10158
            if (virTimeMillisNow(&info->timeElapsed) < 0)
10159
                goto cleanup;
10160
            info->timeElapsed -= priv->job.start;
10161 10162 10163 10164 10165
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
10166 10167
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10168 10169 10170 10171 10172 10173 10174
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
10175
        virObjectUnlock(vm);
10176 10177 10178 10179
    return ret;
}


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


10320
static int qemuDomainAbortJob(virDomainPtr dom) {
10321
    virQEMUDriverPtr driver = dom->conn->privateData;
10322 10323 10324 10325
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

10326
    if (!(vm = qemuDomObjFromDomain(dom)))
10327 10328
        goto cleanup;

10329 10330
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
10331

10332
    if (!virDomainObjIsActive(vm)) {
10333 10334
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10335
        goto endjob;
10336 10337
    }

10338 10339
    priv = vm->privateData;

10340
    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
10341 10342
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no job is active on the domain"));
10343 10344
        goto endjob;
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
10345 10346 10347
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot abort incoming migration;"
                         " use virDomainDestroy instead"));
10348 10349 10350 10351
        goto endjob;
    }

    VIR_DEBUG("Cancelling job at client request");
10352
    qemuDomainObjAbortAsyncJob(vm);
10353
    qemuDomainObjEnterMonitor(driver, vm);
10354 10355 10356 10357 10358 10359
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

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

cleanup:
    if (vm)
10363
        virObjectUnlock(vm);
10364 10365 10366 10367
    return ret;
}


10368 10369 10370 10371 10372
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
10373
    virQEMUDriverPtr driver = dom->conn->privateData;
10374 10375 10376 10377
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

10378
    virCheckFlags(0, -1);
10379

10380 10381
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
10382

10383 10384 10385
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

10386
    if (!virDomainObjIsActive(vm)) {
10387 10388
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10389
        goto endjob;
10390 10391 10392 10393
    }

    priv = vm->privateData;

10394
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
10395 10396
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not being migrated"));
10397
        goto endjob;
10398 10399
    }

10400
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
10401
    qemuDomainObjEnterMonitor(driver, vm);
10402 10403 10404 10405 10406 10407
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

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

cleanup:
    if (vm)
10411
        virObjectUnlock(vm);
10412 10413 10414
    return ret;
}

10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 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
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;
}

10520 10521 10522 10523 10524
static int
qemuDomainMigrateSetMaxSpeed(virDomainPtr dom,
                             unsigned long bandwidth,
                             unsigned int flags)
{
10525
    virQEMUDriverPtr driver = dom->conn->privateData;
10526 10527 10528 10529 10530 10531
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

10532 10533
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
10534 10535

    priv = vm->privateData;
10536 10537 10538
    if (virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
            goto cleanup;
10539

10540
        if (!virDomainObjIsActive(vm)) {
10541 10542
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is not running"));
10543 10544 10545
            goto endjob;
        }

10546 10547 10548 10549
        VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
        qemuDomainObjExitMonitor(driver, vm);
10550

10551 10552
        if (ret == 0)
            priv->migMaxBandwidth = bandwidth;
10553

10554
endjob:
10555 10556 10557 10558 10559 10560
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    } else {
        priv->migMaxBandwidth = bandwidth;
        ret = 0;
    }
10561 10562 10563

cleanup:
    if (vm)
10564
        virObjectUnlock(vm);
10565 10566 10567
    return ret;
}

10568 10569 10570 10571 10572 10573
static int
qemuDomainMigrateGetMaxSpeed(virDomainPtr dom,
                             unsigned long *bandwidth,
                             unsigned int flags)
{
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
10574
    qemuDomainObjPrivatePtr priv;
10575 10576 10577 10578
    int ret = -1;

    virCheckFlags(0, -1);

10579
    if (!(vm = qemuDomObjFromDomain(dom)))
10580 10581
        goto cleanup;

J
Jim Fehlig 已提交
10582 10583
    priv = vm->privateData;
    *bandwidth = priv->migMaxBandwidth;
10584 10585 10586 10587
    ret = 0;

cleanup:
    if (vm)
10588
        virObjectUnlock(vm);
10589 10590 10591
    return ret;
}

10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603
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
10604
qemuDomainPrepareDiskChainElement(virQEMUDriverPtr driver,
10605 10606 10607
                                  virDomainObjPtr vm,
                                  virCgroupPtr cgroup,
                                  virDomainDiskDefPtr disk,
10608
                                  const char *file,
10609 10610 10611 10612 10613 10614 10615 10616 10617 10618
                                  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;
10619
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
10620

10621
    disk->src = (char *) file; /* casting away const is safe here */
10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633
    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);
10634
    } else if (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648
                                       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;
10649
    virObjectUnref(cfg);
10650 10651 10652 10653
    return ret;
}


10654
static int
10655
qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) {
10656 10657 10658 10659
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int freezed;

    if (priv->agentError) {
10660
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
10661 10662
                       _("QEMU guest agent is not "
                         "available due to an error"));
10663 10664 10665
        return -1;
    }
    if (!priv->agent) {
10666 10667
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
10668 10669 10670
        return -1;
    }

10671
    qemuDomainObjEnterAgent(vm);
10672
    freezed = qemuAgentFSFreeze(priv->agent);
10673
    qemuDomainObjExitAgent(vm);
10674 10675 10676 10677 10678

    return freezed;
}

static int
10679
qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report)
E
Eric Blake 已提交
10680
{
10681 10682
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int thawed;
E
Eric Blake 已提交
10683
    virErrorPtr err = NULL;
10684 10685

    if (priv->agentError) {
E
Eric Blake 已提交
10686
        if (report)
10687
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
10688 10689
                           _("QEMU guest agent is not "
                             "available due to an error"));
10690 10691 10692
        return -1;
    }
    if (!priv->agent) {
E
Eric Blake 已提交
10693
        if (report)
10694 10695
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
10696 10697 10698
        return -1;
    }

10699
    qemuDomainObjEnterAgent(vm);
E
Eric Blake 已提交
10700
    if (!report)
10701
        err = virSaveLastError();
10702
    thawed = qemuAgentFSThaw(priv->agent);
10703 10704
    if (!report)
        virSetError(err);
10705
    qemuDomainObjExitAgent(vm);
10706

10707
    virFreeError(err);
10708 10709 10710
    return thawed;
}

10711 10712
/* The domain is expected to be locked and inactive. */
static int
10713
qemuDomainSnapshotCreateInactiveInternal(virQEMUDriverPtr driver,
10714 10715
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap)
10716
{
E
Eric Blake 已提交
10717
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
10718 10719
}

10720 10721
/* The domain is expected to be locked and inactive. */
static int
10722
qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
10723 10724 10725 10726 10727 10728 10729 10730 10731
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap,
                                         bool reuse)
{
    int i;
    virDomainSnapshotDiskDefPtr snapdisk;
    virDomainDiskDefPtr defdisk;
    virCommandPtr cmd = NULL;
    const char *qemuImgPath;
10732 10733
    virBitmapPtr created = NULL;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
10734 10735 10736
    int ret = -1;

    if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
10737
        goto cleanup;
10738 10739 10740

    if (!(created = virBitmapNew(snap->def->ndisks))) {
        virReportOOMError();
10741
        goto cleanup;
10742 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
    }

    /* 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 {
10771
            if (!cfg->allowDiskFormatProbing) {
10772 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
                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 */
10819
    if (ret < 0 && created) {
10820 10821 10822 10823 10824 10825 10826 10827 10828
        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);
10829
    virObjectUnref(cfg);
10830 10831 10832 10833

    return ret;
}

10834

10835 10836
/* The domain is expected to be locked and active. */
static int
10837
qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
10838
                                       virQEMUDriverPtr driver,
10839 10840 10841
                                       virDomainObjPtr *vmptr,
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
10842 10843 10844
{
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
10845
    virDomainEventPtr event = NULL;
10846 10847
    bool resume = false;
    int ret = -1;
10848

10849
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
10850 10851
        return -1;

10852
    if (!virDomainObjIsActive(vm)) {
10853 10854
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10855 10856 10857
        goto endjob;
    }

J
Jiri Denemark 已提交
10858
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
10859 10860 10861 10862
        /* 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.
         */
10863 10864
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
10865 10866 10867 10868
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
10869 10870
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
10871 10872 10873 10874
            goto cleanup;
        }
    }

10875
    qemuDomainObjEnterMonitor(driver, vm);
10876
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
10877
    qemuDomainObjExitMonitor(driver, vm);
10878 10879 10880 10881 10882 10883
    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);
10884
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
10885 10886 10887 10888 10889 10890 10891
        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;
    }
10892

10893 10894
cleanup:
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
10895
        qemuProcessStartCPUs(driver, vm, conn,
10896
                             VIR_DOMAIN_RUNNING_UNPAUSED,
10897 10898 10899 10900 10901 10902 10903 10904
                             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"));
        }
10905 10906
    }

10907
endjob:
10908
    if (vm && qemuDomainObjEndJob(driver, vm) == 0) {
10909 10910
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
10911
        *vmptr = NULL;
10912 10913
        ret = -1;
    }
10914

10915 10916 10917
    if (event)
        qemuDomainEventQueue(driver, event);

10918 10919 10920
    return ret;
}

10921
static int
E
Eric Blake 已提交
10922 10923
qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
                          unsigned int *flags)
10924 10925 10926 10927 10928
{
    int ret = -1;
    int i;
    bool active = virDomainObjIsActive(vm);
    struct stat st;
10929
    bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
10930
    bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
10931
    bool found_internal = false;
10932 10933
    int external = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
10934

E
Eric Blake 已提交
10935
    if (def->state == VIR_DOMAIN_DISK_SNAPSHOT &&
10936
        reuse && !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
10937 10938
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("reuse is not supported with this QEMU binary"));
10939 10940 10941
        goto cleanup;
    }

10942 10943
    for (i = 0; i < def->ndisks; i++) {
        virDomainSnapshotDiskDefPtr disk = &def->disks[i];
E
Eric Blake 已提交
10944
        virDomainDiskDefPtr dom_disk = vm->def->disks[i];
10945 10946

        switch (disk->snapshot) {
E
Eric Blake 已提交
10947
        case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
E
Eric Blake 已提交
10948 10949 10950 10951 10952
            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;
10953
            }
10954 10955
            if (vm->def->disks[i]->format > 0 &&
                vm->def->disks[i]->format != VIR_STORAGE_FILE_QCOW2) {
10956 10957 10958 10959
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("internal snapshot for disk %s unsupported "
                                 "for storage type %s"),
                               disk->name,
10960 10961
                               virStorageFileFormatTypeToString(
                                   vm->def->disks[i]->format));
10962 10963
                goto cleanup;
            }
E
Eric Blake 已提交
10964 10965 10966 10967 10968 10969 10970
            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;
            }
10971
            found_internal = true;
10972 10973
            break;

E
Eric Blake 已提交
10974
        case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
10975 10976 10977 10978
            if (!disk->format) {
                disk->format = VIR_STORAGE_FILE_QCOW2;
            } else if (disk->format != VIR_STORAGE_FILE_QCOW2 &&
                       disk->format != VIR_STORAGE_FILE_QED) {
10979 10980 10981
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot format for disk %s "
                                 "is unsupported: %s"),
10982 10983
                               disk->name,
                               virStorageFileFormatTypeToString(disk->format));
10984 10985 10986 10987 10988 10989 10990 10991
                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;
10992 10993 10994 10995 10996
                } else if (reuse) {
                    virReportSystemError(errno,
                                         _("missing existing file for disk %s: %s"),
                                         disk->name, disk->file);
                    goto cleanup;
10997
                }
10998
            } else if (!S_ISBLK(st.st_mode) && st.st_size && !reuse) {
10999 11000 11001 11002
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot file for disk %s already "
                                 "exists and is not a block device: %s"),
                               disk->name, disk->file);
11003 11004
                goto cleanup;
            }
11005
            external++;
11006 11007
            break;

E
Eric Blake 已提交
11008
        case VIR_DOMAIN_SNAPSHOT_LOCATION_NONE:
11009 11010
            break;

E
Eric Blake 已提交
11011
        case VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT:
11012
        default:
11013 11014
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unexpected code path"));
11015 11016 11017 11018
            goto cleanup;
        }
    }

11019 11020 11021
    /* internal snapshot requires a disk image to store the memory image to */
    if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL &&
        !found_internal) {
11022
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
11023
                       _("internal checkpoints require at least "
11024
                         "one disk to be selected for snapshot"));
11025 11026
        goto cleanup;
    }
11027

11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049
    /* 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 已提交
11050
    if (def->state != VIR_DOMAIN_DISK_SNAPSHOT && active) {
11051
        if (external == 1 ||
11052
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
11053 11054
            *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC;
        } else if (atomic && external > 1) {
11055 11056 11057
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("atomic live snapshot of multiple disks "
                             "is unsupported"));
11058 11059 11060
            goto cleanup;
        }
    }
11061 11062 11063 11064 11065 11066 11067 11068 11069

    ret = 0;

cleanup:
    return ret;
}

/* The domain is expected to hold monitor lock.  */
static int
11070
qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
11071
                                         virDomainObjPtr vm,
11072
                                         virCgroupPtr cgroup,
11073
                                         virDomainSnapshotDiskDefPtr snap,
11074
                                         virDomainDiskDefPtr disk,
11075
                                         virDomainDiskDefPtr persistDisk,
11076 11077
                                         virJSONValuePtr actions,
                                         bool reuse)
11078 11079 11080 11081
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *device = NULL;
    char *source = NULL;
11082 11083
    int format = snap->format;
    const char *formatStr = NULL;
11084
    char *persistSource = NULL;
11085
    int ret = -1;
11086 11087
    int fd = -1;
    bool need_unlink = false;
11088

E
Eric Blake 已提交
11089
    if (snap->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
11090 11091
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected code path"));
11092 11093 11094 11095 11096
        return -1;
    }

    if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
        !(source = strdup(snap->file)) ||
11097
        (persistDisk &&
11098
         !(persistSource = strdup(source)))) {
11099 11100 11101 11102
        virReportOOMError();
        goto cleanup;
    }

11103 11104
    /* create the stub file and set selinux labels; manipulate disk in
     * place, in a way that can be reverted on failure. */
11105 11106 11107 11108 11109 11110 11111
    if (!reuse) {
        fd = qemuOpenFile(driver, source, O_WRONLY | O_TRUNC | O_CREAT,
                          &need_unlink, NULL);
        if (fd < 0)
            goto cleanup;
        VIR_FORCE_CLOSE(fd);
    }
11112

11113 11114 11115 11116 11117 11118 11119 11120
    /* 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;
11121

11122 11123 11124 11125
    if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, source,
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, source,
                                          VIR_DISK_CHAIN_NO_ACCESS);
11126 11127 11128 11129
        goto cleanup;
    }

    /* create the actual snapshot */
11130 11131
    if (snap->format)
        formatStr = virStorageFileFormatTypeToString(snap->format);
11132
    ret = qemuMonitorDiskSnapshot(priv->mon, actions, device, source,
11133
                                  formatStr, reuse);
11134 11135 11136 11137 11138
    virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
    if (ret < 0)
        goto cleanup;

    /* Update vm in place to match changes.  */
11139
    need_unlink = false;
11140 11141 11142
    VIR_FREE(disk->src);
    disk->src = source;
    source = NULL;
11143
    disk->format = format;
11144 11145 11146 11147
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
11148
        persistDisk->format = format;
11149
    }
11150 11151

cleanup:
11152 11153
    if (need_unlink && unlink(source))
        VIR_WARN("unable to unlink just-created %s", source);
11154 11155
    VIR_FREE(device);
    VIR_FREE(source);
11156
    VIR_FREE(persistSource);
11157 11158 11159
    return ret;
}

11160 11161 11162 11163
/* The domain is expected to hold monitor lock.  This is the
 * counterpart to qemuDomainSnapshotCreateSingleDiskActive, called
 * only on a failed transaction. */
static void
11164
qemuDomainSnapshotUndoSingleDiskActive(virQEMUDriverPtr driver,
11165
                                       virDomainObjPtr vm,
11166
                                       virCgroupPtr cgroup,
11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177
                                       virDomainDiskDefPtr origdisk,
                                       virDomainDiskDefPtr disk,
                                       virDomainDiskDefPtr persistDisk,
                                       bool need_unlink)
{
    char *source = NULL;
    char *persistSource = NULL;
    struct stat st;

    if (!(source = strdup(origdisk->src)) ||
        (persistDisk &&
11178
         !(persistSource = strdup(source)))) {
11179 11180 11181 11182
        virReportOOMError();
        goto cleanup;
    }

11183 11184
    qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, origdisk->src,
                                      VIR_DISK_CHAIN_NO_ACCESS);
11185
    if (need_unlink && stat(disk->src, &st) == 0 &&
11186
        S_ISREG(st.st_mode) && unlink(disk->src) < 0)
11187 11188 11189 11190 11191 11192
        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;
11193
    disk->format = origdisk->format;
11194 11195 11196 11197
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
11198
        persistDisk->format = origdisk->format;
11199 11200 11201 11202 11203 11204 11205
    }

cleanup:
    VIR_FREE(source);
    VIR_FREE(persistSource);
}

11206 11207
/* The domain is expected to be locked and active. */
static int
11208
qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
11209
                                   virDomainObjPtr vm,
11210
                                   virDomainSnapshotObjPtr snap,
11211 11212
                                   unsigned int flags,
                                   enum qemuDomainAsyncJob asyncJob)
11213
{
11214 11215
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virJSONValuePtr actions = NULL;
11216 11217
    int ret = -1;
    int i;
11218
    bool persist = false;
11219
    bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
11220
    virCgroupPtr cgroup = NULL;
11221
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
11222

11223
    if (!virDomainObjIsActive(vm)) {
11224 11225
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11226
        goto cleanup;
11227 11228
    }

11229 11230
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
11231 11232 11233
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
11234
        goto cleanup;
11235 11236 11237
    }
    /* 'cgroup' is still NULL if cgroups are disabled.  */

11238
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
11239
        if (!(actions = virJSONValueNewArray())) {
11240 11241 11242
            virReportOOMError();
            goto cleanup;
        }
11243
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DISK_SNAPSHOT)) {
11244 11245 11246 11247
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live disk snapshot not supported with this "
                         "QEMU binary"));
        goto cleanup;
11248
    }
11249 11250

    /* No way to roll back if first disk succeeds but later disks
11251
     * fail, unless we have transaction support.
E
Eric Blake 已提交
11252
     * Based on earlier qemuDomainSnapshotPrepare, all
11253 11254
     * disks in this list are now either SNAPSHOT_NO, or
     * SNAPSHOT_EXTERNAL with a valid file name and qcow2 format.  */
11255 11256 11257
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;

11258
    for (i = 0; i < snap->def->ndisks; i++) {
11259 11260
        virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
11261
        if (snap->def->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
11262
            continue;
11263 11264 11265 11266 11267 11268 11269 11270 11271
        if (vm->newDef) {
            int indx = virDomainDiskIndexByName(vm->newDef,
                                                vm->def->disks[i]->dst,
                                                false);
            if (indx >= 0) {
                persistDisk = vm->newDef->disks[indx];
                persist = true;
            }
        }
11272

11273
        ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm, cgroup,
11274
                                                       &snap->def->disks[i],
11275
                                                       vm->def->disks[i],
11276 11277
                                                       persistDisk, actions,
                                                       reuse);
11278 11279 11280
        if (ret < 0)
            break;
    }
11281 11282 11283
    if (actions) {
        if (ret == 0)
            ret = qemuMonitorTransaction(priv->mon, actions);
E
Eric Blake 已提交
11284
        virJSONValueFree(actions);
11285 11286 11287 11288 11289 11290
        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 已提交
11291 11292
                if (snap->def->disks[i].snapshot ==
                    VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
11293 11294 11295 11296 11297 11298 11299 11300 11301
                    continue;
                if (vm->newDef) {
                    int indx = virDomainDiskIndexByName(vm->newDef,
                                                        vm->def->disks[i]->dst,
                                                        false);
                    if (indx >= 0)
                        persistDisk = vm->newDef->disks[indx];
                }

11302
                qemuDomainSnapshotUndoSingleDiskActive(driver, vm, cgroup,
11303 11304 11305 11306 11307 11308 11309
                                                       snap->def->dom->disks[i],
                                                       vm->def->disks[i],
                                                       persistDisk,
                                                       need_unlink);
            }
        }
    }
11310
    qemuDomainObjExitMonitor(driver, vm);
11311 11312 11313 11314

cleanup:
    virCgroupFree(&cgroup);

11315
    if (ret == 0 || !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
11316
        if (virDomainSaveStatus(driver->xmlconf, cfg->stateDir, vm) < 0 ||
11317
            (persist && virDomainSaveConfig(cfg->configDir, vm->newDef) < 0))
11318 11319
            ret = -1;
    }
11320
    virObjectUnref(cfg);
11321 11322 11323 11324 11325 11326 11327

    return ret;
}


static int
qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
11328
                                       virQEMUDriverPtr driver,
11329 11330 11331 11332 11333 11334 11335 11336 11337 11338
                                       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;
11339
    bool memory_unlink = false;
11340
    bool atomic = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC);
11341
    bool transaction = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION);
11342
    int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
11343
    bool pmsuspended = false;
11344

11345
    if (qemuDomainObjBeginAsyncJob(driver, vm,
11346
                                             QEMU_ASYNC_JOB_SNAPSHOT) < 0)
11347 11348
        goto cleanup;

11349 11350 11351 11352 11353
    /* 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) {
11354
        if (qemuDomainSnapshotFSFreeze(vm) < 0) {
11355 11356 11357 11358 11359 11360 11361 11362
            /* helper reported the error */
            thaw = -1;
            goto endjob;
        } else {
            thaw = 1;
        }
    }

11363 11364 11365 11366 11367
    /* 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) {
11368 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
        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) {
11397 11398 11399 11400
        /* check if migration is possible */
        if (!qemuMigrationIsAllowed(driver, vm, vm->def, false))
            goto endjob;

11401 11402 11403 11404 11405 11406 11407 11408 11409
        /* 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,
11410
                                        xml, QEMU_SAVE_FORMAT_RAW,
11411 11412 11413 11414
                                        resume, 0,
                                        QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
            goto endjob;

11415 11416 11417
        /* the memory image was created, remove it on errors */
        memory_unlink = true;

11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433
        /* 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 */
11434 11435 11436 11437 11438
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        virDomainEventPtr event;

        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
11439
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
11440 11441 11442
        virDomainAuditStop(vm, "from-snapshot");
        /* We already filtered the _HALT flag for persistent domains
         * only, so this end job never drops the last reference.  */
11443
        ignore_value(qemuDomainObjEndAsyncJob(driver, vm));
11444
        resume = false;
E
Eric Blake 已提交
11445
        thaw = 0;
11446 11447 11448
        vm = NULL;
        if (event)
            qemuDomainEventQueue(driver, event);
11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460
    } 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);
11461 11462
    }

11463
    ret = 0;
11464 11465

endjob:
11466 11467 11468
    if (resume && vm && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
11469
                             QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
11470 11471 11472 11473 11474 11475 11476 11477 11478 11479
        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"));
        }
11480

11481 11482
        ret = -1;
        goto cleanup;
11483
    }
E
Eric Blake 已提交
11484
    if (vm && thaw != 0 &&
11485
        qemuDomainSnapshotFSThaw(vm, thaw > 0) < 0) {
E
Eric Blake 已提交
11486 11487 11488 11489
        /* helper reported the error, if it was needed */
        if (thaw > 0)
            ret = -1;
    }
11490
    if (vm && !qemuDomainObjEndAsyncJob(driver, vm)) {
11491
        /* Only possible if a transient vm quit while our locks were down,
11492 11493
         * in which case we don't want to save snapshot metadata.
         */
11494 11495
        *vmptr = NULL;
        ret = -1;
11496 11497
    }

11498 11499
cleanup:
    VIR_FREE(xml);
11500 11501
    if (memory_unlink && ret < 0)
        unlink(snap->def->file);
11502

11503 11504 11505
    return ret;
}

11506

11507 11508 11509 11510
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
                            const char *xmlDesc,
                            unsigned int flags)
C
Chris Lalancette 已提交
11511
{
11512
    virQEMUDriverPtr driver = domain->conn->privateData;
C
Chris Lalancette 已提交
11513
    virDomainObjPtr vm = NULL;
11514
    char *xml = NULL;
C
Chris Lalancette 已提交
11515 11516 11517
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
11518
    virDomainSnapshotDefPtr def = NULL;
11519
    bool update_current = true;
11520
    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
11521
    virDomainSnapshotObjPtr other = NULL;
11522 11523
    int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
    int align_match = true;
11524
    virQEMUDriverConfigPtr cfg = NULL;
11525
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
11526

11527 11528
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
11529
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
11530
                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
11531
                  VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
11532
                  VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
11533
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
11534 11535
                  VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
                  VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
11536 11537 11538

    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
        !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
11539 11540
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("quiesce requires disk-only"));
11541 11542
        return NULL;
    }
11543 11544 11545 11546 11547 11548 11549

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

C
Chris Lalancette 已提交
11551
    virUUIDFormat(domain->uuid, uuidstr);
11552
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
C
Chris Lalancette 已提交
11553
    if (!vm) {
11554 11555
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
11556 11557 11558
        goto cleanup;
    }

11559 11560
    cfg = virQEMUDriverGetConfig(driver);

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

11564
    if (qemuProcessAutoDestroyActive(driver, vm)) {
11565 11566
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is marked for auto destroy"));
11567 11568
        goto cleanup;
    }
E
Eric Blake 已提交
11569 11570 11571 11572 11573 11574
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }

11575
    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
11576 11577
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot halt after transient domain snapshot"));
11578 11579
        goto cleanup;
    }
11580 11581 11582
    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) ||
        !virDomainObjIsActive(vm))
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE;
11583

11584
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, caps, driver->xmlconf,
11585 11586
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
11587 11588
        goto cleanup;

11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606
    /* 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;
        }
11607 11608
    }

11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627
    /* 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;
    }

11628 11629 11630 11631
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* Prevent circular chains */
        if (def->parent) {
            if (STREQ(def->name, def->parent)) {
11632 11633 11634
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot set snapshot %s as its own parent"),
                               def->name);
11635 11636
                goto cleanup;
            }
11637
            other = virDomainSnapshotFindByName(vm->snapshots, def->parent);
11638
            if (!other) {
11639 11640 11641
                virReportError(VIR_ERR_INVALID_ARG,
                               _("parent %s for snapshot %s not found"),
                               def->parent, def->name);
11642 11643 11644 11645
                goto cleanup;
            }
            while (other->def->parent) {
                if (STREQ(other->def->parent, def->name)) {
11646 11647 11648
                    virReportError(VIR_ERR_INVALID_ARG,
                                   _("parent %s would create cycle to %s"),
                                   other->def->name, def->name);
11649 11650
                    goto cleanup;
                }
11651
                other = virDomainSnapshotFindByName(vm->snapshots,
11652 11653 11654 11655 11656 11657 11658 11659 11660 11661
                                                    other->def->parent);
                if (!other) {
                    VIR_WARN("snapshots are inconsistent for %s",
                             vm->def->name);
                    break;
                }
            }
        }

        /* Check that any replacement is compatible */
11662 11663 11664 11665 11666 11667 11668 11669 11670
        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;

        }
11671

11672 11673
        if (def->dom &&
            memcmp(def->dom->uuid, domain->uuid, VIR_UUID_BUFLEN)) {
11674 11675 11676
            virReportError(VIR_ERR_INVALID_ARG,
                           _("definition for snapshot %s must use uuid %s"),
                           def->name, uuidstr);
11677 11678
            goto cleanup;
        }
11679

11680
        other = virDomainSnapshotFindByName(vm->snapshots, def->name);
11681 11682 11683 11684 11685
        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)) {
11686 11687 11688 11689
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot change between online and offline "
                                 "snapshot state in snapshot %s"),
                               def->name);
11690 11691
                goto cleanup;
            }
11692

11693 11694
            if ((other->def->state == VIR_DOMAIN_DISK_SNAPSHOT) !=
                (def->state == VIR_DOMAIN_DISK_SNAPSHOT)) {
11695 11696 11697 11698
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot change between disk snapshot and "
                                 "system checkpoint in snapshot %s"),
                               def->name);
11699 11700
                goto cleanup;
            }
11701

11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712
            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;
                }
            }
11713

11714 11715
            if (def->dom) {
                if (def->state == VIR_DOMAIN_DISK_SNAPSHOT ||
11716
                    virDomainSnapshotDefIsExternal(def)) {
11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731
                    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;
                }
            }

11732 11733 11734 11735
            if (other == vm->current_snapshot) {
                update_current = true;
                vm->current_snapshot = NULL;
            }
11736

11737 11738
            /* Drop and rebuild the parent relationship, but keep all
             * child relations by reusing snap.  */
11739
            virDomainSnapshotDropParent(other);
11740
            virDomainSnapshotDefFree(other->def);
11741 11742
            other->def = def;
            def = NULL;
11743
            snap = other;
11744 11745 11746 11747 11748 11749 11750 11751 11752 11753
        } 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;
11754
            }
11755
        }
11756 11757 11758
    } else {
        /* Easiest way to clone inactive portion of vm->def is via
         * conversion in and back out of xml.  */
11759
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
11760
            !(def->dom = virDomainDefParseString(caps, driver->xmlconf, xml,
11761 11762 11763 11764
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE)))
            goto cleanup;

11765
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
11766 11767
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
11768 11769 11770 11771
            if (virDomainObjIsActive(vm))
                def->state = VIR_DOMAIN_DISK_SNAPSHOT;
            else
                def->state = VIR_DOMAIN_SHUTOFF;
11772
            def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
11773 11774 11775 11776
        } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            def->state = virDomainObjGetState(vm, NULL);
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
11777 11778
        } else {
            def->state = virDomainObjGetState(vm, NULL);
11779 11780 11781
            def->memory = (def->state == VIR_DOMAIN_SHUTOFF ?
                           VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
                           VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL);
11782
        }
E
Eric Blake 已提交
11783 11784 11785 11786
        if (virDomainSnapshotAlignDisks(def, align_location,
                                        align_match) < 0 ||
            qemuDomainSnapshotPrepare(vm, def, &flags) < 0)
            goto cleanup;
11787 11788
    }

11789 11790 11791 11792 11793 11794
    if (!snap) {
        if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
            goto cleanup;

        def = NULL;
    }
C
Chris Lalancette 已提交
11795

11796 11797
    if (update_current)
        snap->def->current = true;
11798
    if (vm->current_snapshot) {
11799 11800 11801 11802 11803 11804
        if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
            snap->def->parent = strdup(vm->current_snapshot->def->name);
            if (snap->def->parent == NULL) {
                virReportOOMError();
                goto cleanup;
            }
11805
        }
11806
        if (update_current) {
11807 11808
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
11809
                                                cfg->snapshotDir) < 0)
11810 11811 11812
                goto cleanup;
            vm->current_snapshot = NULL;
        }
11813
    }
11814

C
Chris Lalancette 已提交
11815
    /* actually do the snapshot */
11816 11817
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* XXX Should we validate that the redefined snapshot even
11818 11819
         * makes sense, such as checking that qemu-img recognizes the
         * snapshot name in at least one of the domain's disks?  */
11820 11821 11822 11823 11824 11825 11826 11827 11828 11829 11830 11831 11832
    } 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 已提交
11833
    } else {
11834 11835 11836 11837 11838 11839 11840 11841 11842 11843 11844 11845 11846
        /* 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 已提交
11847 11848
    }

11849
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
11850 11851 11852 11853 11854 11855
     * 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:
11856
    if (vm) {
11857
        if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
11858
            if (qemuDomainSnapshotWriteMetadata(vm, snap,
11859
                                                cfg->snapshotDir) < 0) {
11860 11861 11862 11863 11864 11865 11866 11867
                /* 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);
11868 11869 11870
            } else {
                if (update_current)
                    vm->current_snapshot = snap;
11871
                other = virDomainSnapshotFindByName(vm->snapshots,
11872 11873 11874 11875 11876
                                                    snap->def->parent);
                snap->parent = other;
                other->nchildren++;
                snap->sibling = other->first_child;
                other->first_child = snap;
11877
            }
11878
        } else if (snap) {
11879
            virDomainSnapshotObjListRemove(vm->snapshots, snap);
11880
        }
11881
        virObjectUnlock(vm);
11882 11883
    }
    virDomainSnapshotDefFree(def);
11884
    VIR_FREE(xml);
11885
    virObjectUnref(caps);
11886
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
11887 11888 11889 11890 11891
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
11892
                                       unsigned int flags)
C
Chris Lalancette 已提交
11893 11894 11895 11896
{
    virDomainObjPtr vm = NULL;
    int n = -1;

11897
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
11898
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11899

11900
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11901 11902
        goto cleanup;

11903
    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
11904
                                         flags);
C
Chris Lalancette 已提交
11905 11906 11907

cleanup:
    if (vm)
11908
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11909 11910 11911 11912
    return n;
}

static int qemuDomainSnapshotNum(virDomainPtr domain,
11913
                                 unsigned int flags)
C
Chris Lalancette 已提交
11914 11915 11916 11917
{
    virDomainObjPtr vm = NULL;
    int n = -1;

11918
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
11919
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11920

11921
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11922 11923
        goto cleanup;

11924
    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
C
Chris Lalancette 已提交
11925 11926 11927

cleanup:
    if (vm)
11928
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11929 11930 11931
    return n;
}

11932 11933 11934 11935 11936 11937 11938 11939 11940 11941
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);

11942
    if (!(vm = qemuDomObjFromDomain(domain)))
11943 11944
        goto cleanup;

11945
    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
11946 11947 11948

cleanup:
    if (vm)
11949
        virObjectUnlock(vm);
11950 11951 11952
    return n;
}

11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963
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 |
11964
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11965

11966
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11967 11968
        goto cleanup;

11969
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11970 11971
        goto cleanup;

11972
    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
11973
                                         flags);
11974 11975 11976

cleanup:
    if (vm)
11977
        virObjectUnlock(vm);
11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989
    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 |
11990
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11991

11992
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11993 11994
        goto cleanup;

11995
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11996 11997
        goto cleanup;

11998
    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
11999 12000 12001

cleanup:
    if (vm)
12002
        virObjectUnlock(vm);
12003 12004 12005
    return n;
}

12006 12007 12008 12009 12010 12011 12012 12013 12014 12015 12016 12017
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);

12018
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
12019 12020
        goto cleanup;

12021
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
12022 12023
        goto cleanup;

12024
    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
12025 12026 12027 12028
                               flags);

cleanup:
    if (vm)
12029
        virObjectUnlock(vm);
12030 12031 12032
    return n;
}

C
Chris Lalancette 已提交
12033 12034
static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
12035
                                                           unsigned int flags)
C
Chris Lalancette 已提交
12036 12037 12038 12039 12040
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

12041 12042
    virCheckFlags(0, NULL);

12043
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
12044 12045
        goto cleanup;

12046
    if (!(snap = qemuSnapObjFromName(vm, name)))
C
Chris Lalancette 已提交
12047 12048 12049 12050 12051 12052
        goto cleanup;

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
    if (vm)
12053
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12054 12055 12056 12057
    return snapshot;
}

static int qemuDomainHasCurrentSnapshot(virDomainPtr domain,
12058
                                        unsigned int flags)
C
Chris Lalancette 已提交
12059 12060 12061 12062
{
    virDomainObjPtr vm;
    int ret = -1;

12063 12064
    virCheckFlags(0, -1);

12065
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
12066 12067 12068 12069 12070 12071
        goto cleanup;

    ret = (vm->current_snapshot != NULL);

cleanup:
    if (vm)
12072
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12073 12074 12075
    return ret;
}

12076 12077 12078 12079 12080 12081 12082 12083 12084 12085
static virDomainSnapshotPtr
qemuDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

12086
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
12087 12088
        goto cleanup;

12089
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
12090 12091 12092
        goto cleanup;

    if (!snap->def->parent) {
12093 12094 12095
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snap->def->name);
12096 12097 12098 12099 12100 12101 12102
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);

cleanup:
    if (vm)
12103
        virObjectUnlock(vm);
12104 12105 12106
    return parent;
}

C
Chris Lalancette 已提交
12107
static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
12108
                                                      unsigned int flags)
C
Chris Lalancette 已提交
12109 12110 12111 12112
{
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

12113 12114
    virCheckFlags(0, NULL);

12115
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
12116 12117 12118
        goto cleanup;

    if (!vm->current_snapshot) {
12119 12120
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                       _("the domain does not have a current snapshot"));
C
Chris Lalancette 已提交
12121 12122 12123 12124 12125 12126 12127
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);

cleanup:
    if (vm)
12128
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12129 12130 12131
    return snapshot;
}

12132 12133
static char *qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                                          unsigned int flags)
C
Chris Lalancette 已提交
12134 12135 12136 12137 12138 12139
{
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

12140
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
12141

12142
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
C
Chris Lalancette 已提交
12143 12144
        goto cleanup;

12145
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
12146
        goto cleanup;
12147 12148

    virUUIDFormat(snapshot->domain->uuid, uuidstr);
C
Chris Lalancette 已提交
12149

12150
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
12151 12152 12153

cleanup:
    if (vm)
12154
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12155 12156 12157
    return xml;
}

12158 12159 12160 12161 12162 12163 12164 12165 12166 12167
static int
qemuDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

12168
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
12169 12170
        goto cleanup;

12171
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
12172 12173 12174 12175 12176 12177 12178
        goto cleanup;

    ret = (vm->current_snapshot &&
           STREQ(snapshot->name, vm->current_snapshot->def->name));

cleanup:
    if (vm)
12179
        virObjectUnlock(vm);
12180 12181 12182 12183 12184 12185 12186 12187 12188 12189 12190 12191 12192 12193
    return ret;
}


static int
qemuDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

12194
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
12195 12196
        goto cleanup;

12197
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
12198 12199 12200 12201 12202 12203 12204 12205 12206
        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)
12207
        virObjectUnlock(vm);
12208 12209 12210
    return ret;
}

12211 12212
/* The domain is expected to be locked and inactive. */
static int
12213
qemuDomainSnapshotRevertInactive(virQEMUDriverPtr driver,
E
Eric Blake 已提交
12214
                                 virDomainObjPtr vm,
12215 12216 12217
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
12218
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
12219 12220 12221
    return ret > 0 ? -1 : ret;
}

C
Chris Lalancette 已提交
12222
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
12223
                                      unsigned int flags)
C
Chris Lalancette 已提交
12224
{
12225
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
12226 12227 12228 12229 12230
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainEventPtr event = NULL;
12231
    virDomainEventPtr event2 = NULL;
12232
    int detail;
C
Chris Lalancette 已提交
12233 12234
    qemuDomainObjPrivatePtr priv;
    int rc;
12235
    virDomainDefPtr config = NULL;
12236
    virQEMUDriverConfigPtr cfg = NULL;
12237
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
12238

12239
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
12240 12241
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
12242

12243 12244 12245 12246 12247 12248 12249 12250 12251 12252
    /* 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
12253 12254
     * Also, several transitions occur even if we fail partway through,
     * and use of FORCE can cause multiple transitions.
12255 12256
     */

C
Chris Lalancette 已提交
12257
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
12258
    vm = virDomainObjListFindByUUID(driver->domains, snapshot->domain->uuid);
C
Chris Lalancette 已提交
12259
    if (!vm) {
12260 12261
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
12262 12263
        goto cleanup;
    }
12264 12265 12266

    cfg = virQEMUDriverGetConfig(driver);

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

E
Eric Blake 已提交
12270 12271 12272 12273 12274
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }
C
Chris Lalancette 已提交
12275

12276
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
12277 12278
        goto cleanup;

12279 12280 12281 12282 12283
    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) {
12284 12285 12286
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("transient domain needs to request run or pause "
                         "to revert to inactive snapshot"));
12287 12288
        goto cleanup;
    }
12289
    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
12290 12291 12292
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("revert to external disk snapshot not supported "
                         "yet"));
12293 12294
        goto cleanup;
    }
12295 12296
    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
        if (!snap->def->dom) {
12297 12298 12299
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                           _("snapshot '%s' lacks domain '%s' rollback info"),
                           snap->def->name, vm->def->name);
12300 12301 12302 12303 12304 12305 12306
            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))) {
12307 12308
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                           _("must respawn qemu to start inactive snapshot"));
12309 12310 12311 12312
            goto cleanup;
        }
    }

12313

12314 12315 12316
    if (vm->current_snapshot) {
        vm->current_snapshot->def->current = false;
        if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
12317
                                            cfg->snapshotDir) < 0)
12318 12319 12320 12321 12322 12323
            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?  */
    }

12324
    /* Prepare to copy the snapshot inactive xml as the config of this
12325
     * domain.
12326 12327 12328
     *
     * XXX Should domain snapshots track live xml rather
     * than inactive xml?  */
12329
    snap->def->current = true;
12330
    if (snap->def->dom) {
12331
        config = virDomainDefCopy(caps, driver->xmlconf, snap->def->dom, true);
12332 12333 12334
        if (!config)
            goto cleanup;
    }
C
Chris Lalancette 已提交
12335

12336
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
12337 12338 12339 12340
        goto cleanup;

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {
12341 12342 12343 12344 12345 12346 12347 12348 12349
        /* 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 已提交
12350
        if (virDomainObjIsActive(vm)) {
12351
            /* Transitions 5, 6, 8, 9 */
12352 12353
            /* Check for ABI compatibility.  */
            if (config && !virDomainDefCheckABIStability(vm->def, config)) {
12354 12355 12356 12357 12358
                virErrorPtr err = virGetLastError();

                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
                    /* Re-spawn error using correct category. */
                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
12359 12360
                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                                       err->str2);
12361 12362 12363
                    goto endjob;
                }
                virResetError(err);
12364 12365
                qemuProcessStop(driver, vm,
                                VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12366 12367 12368 12369 12370 12371 12372 12373
                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;
12374 12375
            }

C
Chris Lalancette 已提交
12376
            priv = vm->privateData;
12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391
            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)) {
12392 12393
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("guest unexpectedly quit"));
12394 12395 12396
                    goto endjob;
                }
            }
12397
            qemuDomainObjEnterMonitor(driver, vm);
C
Chris Lalancette 已提交
12398
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
12399
            qemuDomainObjExitMonitor(driver, vm);
12400 12401 12402
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
12403
                goto endjob;
12404
            }
12405
            if (config)
12406
                virDomainObjAssignDef(vm, config, false, NULL);
E
Eric Blake 已提交
12407
        } else {
12408
            /* Transitions 2, 3 */
12409
        load:
12410
            was_stopped = true;
12411
            if (config)
12412
                virDomainObjAssignDef(vm, config, false, NULL);
12413

12414 12415 12416 12417
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, snap,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  VIR_QEMU_PROCESS_START_PAUSED);
12418
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
12419 12420 12421 12422
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
12423
            if (rc < 0)
12424
                goto endjob;
C
Chris Lalancette 已提交
12425 12426
        }

12427
        /* Touch up domain state.  */
12428 12429 12430
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
12431 12432 12433 12434 12435 12436 12437 12438 12439 12440 12441 12442 12443
            /* 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)) {
12444 12445
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
12446 12447 12448 12449 12450
                goto endjob;
            }
            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
                                      QEMU_ASYNC_JOB_NONE);
H
Hu Tao 已提交
12451
            if (rc < 0)
12452
                goto endjob;
12453 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 12466 12467
            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 已提交
12468
        }
E
Eric Blake 已提交
12469
    } else {
12470
        /* Transitions 1, 4, 7 */
12471 12472 12473
        /* 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 已提交
12474 12475 12476
         */

        if (virDomainObjIsActive(vm)) {
12477
            /* Transitions 4, 7 */
12478
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12479
            virDomainAuditStop(vm, "from-snapshot");
12480
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
C
Chris Lalancette 已提交
12481 12482
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
12483
                                             detail);
12484 12485
        }

E
Eric Blake 已提交
12486
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
12487
            if (!vm->persistent) {
12488
                if (qemuDomainObjEndJob(driver, vm) > 0)
12489
                    qemuDomainRemoveInactive(driver, vm);
12490
                vm = NULL;
12491
                goto cleanup;
12492
            }
12493
            goto endjob;
C
Chris Lalancette 已提交
12494
        }
12495
        if (config)
12496
            virDomainObjAssignDef(vm, config, false, NULL);
12497

12498 12499 12500 12501
        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;
12502 12503 12504
            unsigned int start_flags = 0;

            start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
12505 12506 12507

            if (event)
                qemuDomainEventQueue(driver, event);
12508 12509 12510 12511
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, NULL,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  start_flags);
12512 12513 12514 12515
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
                    if (qemuDomainObjEndJob(driver, vm) > 0)
12516
                        qemuDomainRemoveInactive(driver, vm);
12517 12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532
                    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 已提交
12533 12534 12535 12536
    }

    ret = 0;

12537
endjob:
12538
    if (vm && qemuDomainObjEndJob(driver, vm) == 0)
C
Chris Lalancette 已提交
12539 12540
        vm = NULL;

12541
cleanup:
12542 12543
    if (vm && ret == 0) {
        if (qemuDomainSnapshotWriteMetadata(vm, snap,
12544
                                            cfg->snapshotDir) < 0)
12545 12546 12547 12548 12549 12550
            ret = -1;
        else
            vm->current_snapshot = snap;
    } else if (snap) {
        snap->def->current = false;
    }
12551
    if (event) {
C
Chris Lalancette 已提交
12552
        qemuDomainEventQueue(driver, event);
12553 12554 12555
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
12556
    if (vm)
12557
        virObjectUnlock(vm);
12558
    virObjectUnref(caps);
12559
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
12560 12561 12562 12563

    return ret;
}

12564 12565 12566 12567

typedef struct _virQEMUSnapReparent virQEMUSnapReparent;
typedef virQEMUSnapReparent *virQEMUSnapReparentPtr;
struct _virQEMUSnapReparent {
12568
    virQEMUDriverConfigPtr cfg;
12569
    virDomainSnapshotObjPtr parent;
12570 12571
    virDomainObjPtr vm;
    int err;
12572
    virDomainSnapshotObjPtr last;
12573 12574 12575 12576
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
12577
                                   const void *name ATTRIBUTE_UNUSED,
12578 12579 12580
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
12581
    virQEMUSnapReparentPtr rep = data;
12582 12583 12584 12585 12586

    if (rep->err < 0) {
        return;
    }

12587
    VIR_FREE(snap->def->parent);
12588
    snap->parent = rep->parent;
12589

12590
    if (rep->parent->def) {
12591
        snap->def->parent = strdup(rep->parent->def->name);
12592

12593 12594 12595 12596
        if (snap->def->parent == NULL) {
            virReportOOMError();
            rep->err = -1;
            return;
12597 12598
        }
    }
12599

12600 12601 12602
    if (!snap->sibling)
        rep->last = snap;

12603
    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
12604
                                               rep->cfg->snapshotDir);
12605 12606
}

12607

C
Chris Lalancette 已提交
12608 12609 12610
static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                                    unsigned int flags)
{
12611
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
12612 12613 12614 12615
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
12616 12617
    virQEMUSnapRemove rem;
    virQEMUSnapReparent rep;
12618
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
12619
    int external = 0;
12620
    virQEMUDriverConfigPtr cfg = NULL;
C
Chris Lalancette 已提交
12621

12622
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
12623 12624
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
12625

C
Chris Lalancette 已提交
12626
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
12627
    vm = virDomainObjListFindByUUID(driver->domains, snapshot->domain->uuid);
C
Chris Lalancette 已提交
12628
    if (!vm) {
12629 12630
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
12631 12632 12633
        goto cleanup;
    }

12634
    cfg = virQEMUDriverGetConfig(driver);
12635
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
12636 12637
        goto cleanup;

12638
    if (!metadata_only) {
12639
        if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
12640
            virDomainSnapshotIsExternal(snap))
12641 12642
            external++;
        if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
E
Eric Blake 已提交
12643
            virDomainSnapshotForEachDescendant(snap,
12644 12645 12646
                                               qemuDomainSnapshotCountExternal,
                                               &external);
        if (external) {
12647 12648 12649
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("deletion of %d external disk snapshots not "
                             "supported yet"), external);
12650 12651 12652 12653
            goto cleanup;
        }
    }

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

12657 12658
    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
C
Chris Lalancette 已提交
12659 12660
        rem.driver = driver;
        rem.vm = vm;
12661
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
12662
        rem.err = 0;
12663
        rem.current = false;
E
Eric Blake 已提交
12664
        virDomainSnapshotForEachDescendant(snap,
E
Eric Blake 已提交
12665
                                           qemuDomainSnapshotDiscardAll,
12666
                                           &rem);
C
Chris Lalancette 已提交
12667
        if (rem.err < 0)
12668
            goto endjob;
12669 12670 12671 12672
        if (rem.current) {
            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
                snap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, snap,
12673
                                                    cfg->snapshotDir) < 0) {
12674 12675 12676
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("failed to set snapshot '%s' as current"),
                                   snap->def->name);
12677 12678 12679 12680
                    snap->def->current = false;
                    goto endjob;
                }
            }
12681
            vm->current_snapshot = snap;
12682
        }
12683
    } else if (snap->nchildren) {
12684
        rep.cfg = cfg;
12685
        rep.parent = snap->parent;
12686 12687
        rep.vm = vm;
        rep.err = 0;
12688
        rep.last = NULL;
E
Eric Blake 已提交
12689
        virDomainSnapshotForEachChild(snap,
12690 12691
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
12692 12693
        if (rep.err < 0)
            goto endjob;
12694
        /* Can't modify siblings during ForEachChild, so do it now.  */
12695 12696 12697
        snap->parent->nchildren += snap->nchildren;
        rep.last->sibling = snap->parent->first_child;
        snap->parent->first_child = snap->first_child;
C
Chris Lalancette 已提交
12698 12699
    }

12700 12701 12702
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
        snap->nchildren = 0;
        snap->first_child = NULL;
12703
        ret = 0;
12704
    } else {
12705
        virDomainSnapshotDropParent(snap);
12706
        ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
12707
    }
C
Chris Lalancette 已提交
12708

12709
endjob:
12710
    if (qemuDomainObjEndJob(driver, vm) == 0)
12711 12712
        vm = NULL;

C
Chris Lalancette 已提交
12713 12714
cleanup:
    if (vm)
12715
        virObjectUnlock(vm);
12716
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
12717 12718
    return ret;
}
12719

12720 12721 12722
static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
                                    char **result, unsigned int flags)
{
12723
    virQEMUDriverPtr driver = domain->conn->privateData;
12724 12725 12726
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
12727
    bool hmp;
12728

12729
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
12730

12731
    if (!(vm = qemuDomObjFromDomain(domain)))
12732 12733 12734
        goto cleanup;

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

12740
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
12741 12742 12743
        goto cleanup;

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

12749 12750
    priv = vm->privateData;

12751
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
12752

12753 12754
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

12755
    qemuDomainObjEnterMonitor(driver, vm);
12756
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
12757
    qemuDomainObjExitMonitor(driver, vm);
12758 12759

endjob:
12760
    if (qemuDomainObjEndJob(driver, vm) == 0) {
12761 12762 12763 12764 12765
        vm = NULL;
    }

cleanup:
    if (vm)
12766
        virObjectUnlock(vm);
12767 12768 12769
    return ret;
}

12770

12771
static virDomainPtr qemuDomainAttach(virConnectPtr conn,
12772
                                     unsigned int pid_value,
12773 12774
                                     unsigned int flags)
{
12775
    virQEMUDriverPtr driver = conn->privateData;
12776 12777 12778 12779 12780
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
12781
    pid_t pid = pid_value;
12782
    char *pidfile = NULL;
12783
    virQEMUCapsPtr qemuCaps = NULL;
12784
    virCapsPtr caps = NULL;
12785 12786 12787

    virCheckFlags(0, NULL);

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

12791
    if (!(def = qemuParseCommandLinePid(caps, driver->xmlconf, pid,
12792 12793 12794 12795
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

    if (!monConfig) {
12796 12797
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("No monitor connection for pid %u"), pid_value);
12798 12799 12800
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
12801 12802 12803 12804 12805
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot connect to monitor connection of type '%s' "
                         "for pid %u"),
                       virDomainChrTypeToString(monConfig->type),
                       pid_value);
12806 12807 12808 12809
        goto cleanup;
    }

    if (!(def->name) &&
12810
        virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0) {
12811 12812 12813 12814
        virReportOOMError();
        goto cleanup;
    }

12815
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
12816 12817
        goto cleanup;

12818
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
12819 12820
        goto cleanup;

12821
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
12822 12823
        goto cleanup;

12824
    if (!(vm = virDomainObjListAdd(driver->domains,
12825
                                   driver->xmlconf,
12826 12827 12828 12829
                                   def,
                                   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->xmlconf, 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->xmlconf, 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->xmlconf, 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->xmlconf, 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;
}