qemu_driver.c 400.2 KB
Newer Older
D
Daniel P. Berrange 已提交
1
/*
2
 * qemu_driver.c: core driver methods for managing qemu guests
D
Daniel P. Berrange 已提交
3
 *
4
 * Copyright (C) 2006-2012 Red Hat, Inc.
D
Daniel P. Berrange 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * 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
#include <sys/utsname.h>
38 39 40 41
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
42
#include <stdio.h>
43
#include <sys/wait.h>
44
#include <sys/ioctl.h>
45
#include <sys/un.h>
46
#include <byteswap.h>
D
Daniel P. Berrange 已提交
47

48

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

#include "virterror_internal.h"
#include "logging.h"
#include "datatypes.h"
65
#include "buf.h"
66
#include "util.h"
67
#include "nodeinfo.h"
68
#include "stats_linux.h"
69
#include "capabilities.h"
70
#include "memory.h"
71
#include "uuid.h"
72
#include "domain_conf.h"
73
#include "domain_audit.h"
74 75
#include "node_device_conf.h"
#include "pci.h"
76
#include "hostusb.h"
77
#include "processinfo.h"
C
Chris Lalancette 已提交
78
#include "libvirt_internal.h"
79
#include "xml.h"
80
#include "cpu/cpu.h"
81
#include "sysinfo.h"
82
#include "domain_nwfilter.h"
83
#include "hooks.h"
84
#include "storage_file.h"
E
Eric Blake 已提交
85
#include "virfile.h"
86
#include "fdstream.h"
87
#include "configmake.h"
H
Hu Tao 已提交
88
#include "threadpool.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

96 97
#define VIR_FROM_THIS VIR_FROM_QEMU

98 99
#define QEMU_NB_MEM_PARAM  3

100 101
#define QEMU_NB_BLOCK_IO_TUNE_PARAM  6

102 103
#define QEMU_NB_NUMA_PARAM 2

E
Eric Blake 已提交
104 105 106
#define QEMU_NB_TOTAL_CPU_STAT_PARAM 3
#define QEMU_NB_PER_CPU_STAT_PARAM 1

107 108 109
#if HAVE_LINUX_KVM_H
# include <linux/kvm.h>
#endif
110

111 112
/* device for kvm ioctls */
#define KVM_DEVICE "/dev/kvm"
113

114 115 116 117 118 119 120 121 122 123 124
/* 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

125
#define QEMU_NB_BLKIO_PARAM  2
126

127 128
#define QEMU_NB_BANDWIDTH_PARAM 6

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

131 132
static int qemudShutdown(void);

133 134 135
static int qemuDomainObjStart(virConnectPtr conn,
                              struct qemud_driver *driver,
                              virDomainObjPtr vm,
136
                              unsigned int flags);
J
Jiri Denemark 已提交
137

138
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
139

140
struct qemud_driver *qemu_driver = NULL;
141 142


143 144 145 146
struct qemuAutostartData {
    struct qemud_driver *driver;
    virConnectPtr conn;
};
147

148
static void
149 150
qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED,
                    void *opaque)
151 152 153
{
    virDomainObjPtr vm = payload;
    struct qemuAutostartData *data = opaque;
154
    virErrorPtr err;
155 156 157 158
    int flags = 0;

    if (data->driver->autoStartBypassCache)
        flags |= VIR_DOMAIN_START_BYPASS_CACHE;
159 160

    virDomainObjLock(vm);
161
    virResetLastError();
162 163 164 165 166 167 168 169 170 171 172 173
    if (vm->autostart &&
        !virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJobWithDriver(data->driver, vm,
                                            QEMU_JOB_MODIFY) < 0) {
            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) {
174
            err = virGetLastError();
175
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
176
                      vm->def->name,
177
                      err ? err->message : _("unknown error"));
178
        }
179

180
        if (qemuDomainObjEndJob(data->driver, vm) == 0)
181
            vm = NULL;
182
    }
183

184
cleanup:
185 186
    if (vm)
        virDomainObjUnlock(vm);
187 188
}

189

190
static void
191 192
qemuAutostartDomains(struct qemud_driver *driver)
{
193 194 195 196 197
    /* 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
     */
198 199 200
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
201
    /* Ignoring NULL conn which is mostly harmless here */
202
    struct qemuAutostartData data = { driver, conn };
203

204
    qemuDriverLock(driver);
205
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
206
    qemuDriverUnlock(driver);
207

208 209
    if (conn)
        virConnectClose(conn);
210 211
}

212
static int
213
qemuSecurityInit(struct qemud_driver *driver)
214
{
215
    virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName,
216 217 218 219
                                                      driver->allowDiskFormatProbing,
                                                      driver->securityDefaultConfined,
                                                      driver->securityRequireConfined);

220 221
    if (!mgr)
        goto error;
D
Daniel Veillard 已提交
222

223 224 225 226
    if (driver->privileged) {
        virSecurityManagerPtr dac = virSecurityManagerNewDAC(driver->user,
                                                             driver->group,
                                                             driver->allowDiskFormatProbing,
227 228
                                                             driver->securityDefaultConfined,
                                                             driver->securityRequireConfined,
229 230 231
                                                             driver->dynamicOwnership);
        if (!dac)
            goto error;
232

233
        if (!(driver->securityManager = virSecurityManagerNewStack(mgr,
E
Eric Blake 已提交
234 235 236
                                                                   dac))) {

            virSecurityManagerFree(dac);
237
            goto error;
E
Eric Blake 已提交
238
        }
239 240 241
    } else {
        driver->securityManager = mgr;
    }
D
Daniel Veillard 已提交
242

243
    return 0;
244

245
error:
246
    VIR_ERROR(_("Failed to initialize security drivers"));
247 248 249
    virSecurityManagerFree(mgr);
    return -1;
}
250

251

252 253 254 255 256
static virCapsPtr
qemuCreateCapabilities(virCapsPtr oldcaps,
                       struct qemud_driver *driver)
{
    virCapsPtr caps;
257

258 259 260 261
    /* Basic host arch / guest machine capabilities */
    if (!(caps = qemuCapsInit(oldcaps))) {
        virReportOOMError();
        return NULL;
262 263
    }

264 265 266 267 268 269
    if (driver->allowDiskFormatProbing) {
        caps->defaultDiskDriverName = NULL;
        caps->defaultDiskDriverType = NULL;
    } else {
        caps->defaultDiskDriverName = "qemu";
        caps->defaultDiskDriverType = "raw";
270 271
    }

272 273
    qemuDomainSetPrivateDataHooks(caps);
    qemuDomainSetNamespaceHooks(caps);
274

275 276 277 278
    if (virGetHostUUID(caps->host.host_uuid)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot get the host uuid"));
        goto err_exit;
279
    }
280

281 282
    /* Security driver data */
    const char *doi, *model;
283

284 285 286 287 288 289 290
    doi = virSecurityManagerGetDOI(driver->securityManager);
    model = virSecurityManagerGetModel(driver->securityManager);
    if (STRNEQ(model, "none")) {
        if (!(caps->host.secModel.model = strdup(model)))
            goto no_memory;
        if (!(caps->host.secModel.doi = strdup(doi)))
            goto no_memory;
291
    }
292

293 294
    VIR_DEBUG("Initialized caps for security driver \"%s\" with "
              "DOI \"%s\"", model, doi);
295

296
    return caps;
297

298 299 300 301
no_memory:
    virReportOOMError();
err_exit:
    virCapabilitiesFree(caps);
302 303 304
    return NULL;
}

305
static void qemuDomainSnapshotLoad(void *payload,
306
                                   const void *name ATTRIBUTE_UNUSED,
307
                                   void *data)
308
{
309 310 311 312 313 314 315 316 317
    virDomainObjPtr vm = (virDomainObjPtr)payload;
    char *baseDir = (char *)data;
    char *snapDir = NULL;
    DIR *dir = NULL;
    struct dirent *entry;
    char *xmlStr;
    int ret;
    char *fullpath;
    virDomainSnapshotDefPtr def = NULL;
318
    virDomainSnapshotObjPtr snap = NULL;
319
    virDomainSnapshotObjPtr current = NULL;
320
    char ebuf[1024];
321
    unsigned int flags = (VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE |
322
                          VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
323
                          VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL);
324

325 326 327 328
    virDomainObjLock(vm);
    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);
329
        goto cleanup;
330 331
    }

332 333
    VIR_INFO("Scanning for snapshots for domain %s in %s", vm->def->name,
             snapDir);
334

335 336 337 338 339
    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)));
340
        goto cleanup;
341 342
    }

343 344 345
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.')
            continue;
346

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

351
        if (virAsprintf(&fullpath, "%s/%s", snapDir, entry->d_name) < 0) {
352
            VIR_ERROR(_("Failed to allocate memory for path"));
353 354
            continue;
        }
355

356 357 358 359 360 361 362 363
        ret = virFileReadAll(fullpath, 1024*1024*1, &xmlStr);
        if (ret < 0) {
            /* 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;
        }
364

365 366 367
        def = virDomainSnapshotDefParseString(xmlStr, qemu_driver->caps,
                                              QEMU_EXPECTED_VIRT_TYPES,
                                              flags);
368 369
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
370 371
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
                      fullpath);
372 373 374 375
            VIR_FREE(fullpath);
            VIR_FREE(xmlStr);
            continue;
        }
376

377 378 379
        snap = virDomainSnapshotAssignDef(&vm->snapshots, def);
        if (snap == NULL) {
            virDomainSnapshotDefFree(def);
380 381 382 383
        } else if (snap->def->current) {
            current = snap;
            if (!vm->current_snapshot)
                vm->current_snapshot = snap;
384
        }
385

386 387
        VIR_FREE(fullpath);
        VIR_FREE(xmlStr);
388 389
    }

390 391 392 393 394 395
    if (vm->current_snapshot != current) {
        VIR_ERROR(_("Too many snapshots claiming to be current for domain %s"),
                  vm->def->name);
        vm->current_snapshot = NULL;
    }

396 397 398 399
    if (virDomainSnapshotUpdateRelations(&vm->snapshots) < 0)
        VIR_ERROR(_("Snapshots have inconsistent relations for domain %s"),
                  vm->def->name);

400 401 402 403 404 405 406 407
    /* 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.
     */
408

409
    virResetLastError();
410

411 412 413 414
cleanup:
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
415 416 417
    virDomainObjUnlock(vm);
}

418 419 420 421 422
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
423
static int
424 425 426 427 428
qemudStartup(int privileged) {
    char *base = NULL;
    char *driverConf = NULL;
    int rc;
    virConnectPtr conn = NULL;
429

430 431
    if (VIR_ALLOC(qemu_driver) < 0)
        return -1;
432

433
    if (virMutexInit(&qemu_driver->lock) < 0) {
434
        VIR_ERROR(_("cannot initialize mutex"));
435 436
        VIR_FREE(qemu_driver);
        return -1;
437
    }
438 439
    qemuDriverLock(qemu_driver);
    qemu_driver->privileged = privileged;
440

441 442
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;
443

444 445
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;
446

447
    /* Init domain events */
448
    qemu_driver->domainEventState = virDomainEventStateNew();
449
    if (!qemu_driver->domainEventState)
450
        goto error;
451

452 453 454 455
    /* Allocate bitmap for vnc port reservation */
    if ((qemu_driver->reservedVNCPorts =
         virBitmapAlloc(QEMU_VNC_PORT_MAX - QEMU_VNC_PORT_MIN)) == NULL)
        goto out_of_memory;
456

457 458 459
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();
460

461 462 463 464
    if (privileged) {
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
465

466 467
        if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL)
            goto out_of_memory;
468

469 470 471
        if (virAsprintf(&qemu_driver->stateDir,
                      "%s/run/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
472

473 474 475
        if (virAsprintf(&qemu_driver->libDir,
                      "%s/lib/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
476

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
        if (virAsprintf(&qemu_driver->cacheDir,
                      "%s/cache/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->saveDir,
                      "%s/lib/libvirt/qemu/save", LOCALSTATEDIR) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->snapshotDir,
                        "%s/lib/libvirt/qemu/snapshot", LOCALSTATEDIR) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->autoDumpPath,
                        "%s/lib/libvirt/qemu/dump", LOCALSTATEDIR) == -1)
            goto out_of_memory;
    } else {
        uid_t uid = geteuid();
        char *userdir = virGetUserDirectory(uid);
        if (!userdir)
            goto error;
494

495 496 497 498 499
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
            goto out_of_memory;
        }
500

501 502 503 504 505
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
            goto out_of_memory;
        }
        VIR_FREE(userdir);
506

507 508 509 510 511 512 513 514 515 516 517 518
        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->libDir, "%s/qemu/lib", base) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->cacheDir, "%s/qemu/cache", base) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->saveDir, "%s/qemu/save", base) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->autoDumpPath, "%s/qemu/dump", base) == -1)
            goto out_of_memory;
519
    }
H
Hu Tao 已提交
520

521
    if (virFileMakePath(qemu_driver->stateDir) < 0) {
522 523 524 525
        char ebuf[1024];
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
H
Hu Tao 已提交
526
    }
527
    if (virFileMakePath(qemu_driver->libDir) < 0) {
528 529 530 531 532
        char ebuf[1024];
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
533
    if (virFileMakePath(qemu_driver->cacheDir) < 0) {
534 535 536 537 538
        char ebuf[1024];
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
539
    if (virFileMakePath(qemu_driver->saveDir) < 0) {
540 541 542 543 544
        char ebuf[1024];
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
                  qemu_driver->saveDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
545
    if (virFileMakePath(qemu_driver->snapshotDir) < 0) {
546 547 548 549 550
        char ebuf[1024];
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
                  qemu_driver->snapshotDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
551
    if (virFileMakePath(qemu_driver->autoDumpPath) < 0) {
552 553 554 555
        char ebuf[1024];
        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
                  qemu_driver->autoDumpPath, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
556 557
    }

558 559 560 561 562 563 564
    /* Configuration paths are either ~/.libvirt/qemu/... (session) or
     * /etc/libvirt/qemu/... (system).
     */
    if (virAsprintf(&driverConf, "%s/qemu.conf", base) < 0 ||
        virAsprintf(&qemu_driver->configDir, "%s/qemu", base) < 0 ||
        virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) < 0)
        goto out_of_memory;
565

566
    VIR_FREE(base);
567

568 569 570 571 572
    rc = virCgroupForDriver("qemu", &qemu_driver->cgroup, privileged, 1);
    if (rc < 0) {
        char buf[1024];
        VIR_INFO("Unable to create cgroup for driver: %s",
                 virStrerror(-rc, buf, sizeof(buf)));
573 574
    }

575 576 577 578
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
        goto error;
    }
    VIR_FREE(driverConf);
579

580 581 582 583 584 585 586 587
    /* We should always at least have the 'nop' manager, so
     * NULLs here are a fatal error
     */
    if (!qemu_driver->lockManager) {
        VIR_ERROR(_("Missing lock manager implementation"));
        goto error;
    }

588 589
    if (qemuSecurityInit(qemu_driver) < 0)
        goto error;
590

591 592 593
    if ((qemu_driver->caps = qemuCreateCapabilities(NULL,
                                                    qemu_driver)) == NULL)
        goto error;
594

595
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
596
        goto error;
597

598 599 600
    if ((qemu_driver->activeUsbHostdevs = usbDeviceListNew()) == NULL)
        goto error;

601 602 603
    if ((qemu_driver->inactivePciHostdevs = pciDeviceListNew()) == NULL)
        goto error;

604 605 606 607 608 609
    if (privileged) {
        if (chown(qemu_driver->libDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to user %d:%d"),
                                 qemu_driver->libDir, qemu_driver->user, qemu_driver->group);
            goto error;
610
        }
611
        if (chown(qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group) < 0) {
612
            virReportSystemError(errno,
613 614 615
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
616
        }
617 618 619 620 621 622 623 624 625 626 627
        if (chown(qemu_driver->saveDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->saveDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
        if (chown(qemu_driver->snapshotDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->snapshotDir, qemu_driver->user, qemu_driver->group);
            goto error;
628
        }
629
    }
630

631 632 633 634 635 636
    /* 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
637
     */
638 639 640 641 642
    if (qemu_driver->hugetlbfs_mount &&
        qemu_driver->hugetlbfs_mount[0] == '/') {
        char *mempath = NULL;
        if (virAsprintf(&mempath, "%s/libvirt/qemu", qemu_driver->hugetlbfs_mount) < 0)
            goto out_of_memory;
643

644 645
        if (virFileMakePath(mempath) < 0) {
            virReportSystemError(errno,
646 647 648
                                 _("unable to create hugepage path %s"), mempath);
            VIR_FREE(mempath);
            goto error;
649
        }
650 651 652 653 654 655 656
        if (qemu_driver->privileged &&
            chown(mempath, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership on %s to %d:%d"),
                                 mempath, qemu_driver->user, qemu_driver->group);
            VIR_FREE(mempath);
            goto error;
G
Guido Günther 已提交
657
        }
E
Eric Blake 已提交
658

659
        qemu_driver->hugepage_path = mempath;
660
    }
661

662 663 664
    if (qemuProcessAutoDestroyInit(qemu_driver) < 0)
        goto error;

665 666 667
    if (qemuDriverCloseCallbackInit(qemu_driver) < 0)
        goto error;

668 669 670 671 672
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
M
Matthias Bolte 已提交
673 674
                                1, QEMU_EXPECTED_VIRT_TYPES,
                                NULL, NULL) < 0)
675
        goto error;
676

677 678 679
    conn = virConnectOpen(qemu_driver->privileged ?
                          "qemu:///system" :
                          "qemu:///session");
680

681
    qemuProcessReconnectAll(conn, qemu_driver);
682

683 684 685 686 687
    /* Then inactive persistent configs */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->configDir,
                                qemu_driver->autostartDir,
M
Matthias Bolte 已提交
688 689
                                0, QEMU_EXPECTED_VIRT_TYPES,
                                NULL, NULL) < 0)
690
        goto error;
691

692

693 694
    virHashForEach(qemu_driver->domains.objs, qemuDomainSnapshotLoad,
                   qemu_driver->snapshotDir);
695

696
    qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, processWatchdogEvent, qemu_driver);
697 698
    if (!qemu_driver->workerPool)
        goto error;
699

700 701 702 703
    qemuDriverUnlock(qemu_driver);

    qemuAutostartDomains(qemu_driver);

704 705
    if (conn)
        virConnectClose(conn);
706

707
    return 0;
708

709 710 711 712 713 714 715 716 717 718
out_of_memory:
    virReportOOMError();
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
    if (conn)
        virConnectClose(conn);
    VIR_FREE(base);
    VIR_FREE(driverConf);
    qemudShutdown();
719
    return -1;
720 721
}

722 723 724
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;
725

726 727 728 729 730 731 732
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
E
Eric Blake 已提交
733
    }
734
}
E
Eric Blake 已提交
735

736 737 738 739 740 741 742 743 744 745
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
    if (!qemu_driver)
        return 0;
746

747 748 749 750 751
    qemuDriverLock(qemu_driver);
    virDomainLoadAllConfigs(qemu_driver->caps,
                            &qemu_driver->domains,
                            qemu_driver->configDir,
                            qemu_driver->autostartDir,
M
Matthias Bolte 已提交
752 753
                            0, QEMU_EXPECTED_VIRT_TYPES,
                            qemudNotifyLoadDomain, qemu_driver);
754
    qemuDriverUnlock(qemu_driver);
755

756
    qemuAutostartDomains(qemu_driver);
757

758 759
    return 0;
}
S
Stefan Berger 已提交
760

761 762 763 764 765 766 767 768 769 770 771
/**
 * qemudActive:
 *
 * Checks if the QEmu daemon is active, i.e. has an active domain or
 * an active network
 *
 * Returns 1 if active, 0 otherwise
 */
static int
qemudActive(void) {
    int active = 0;
772

773 774
    if (!qemu_driver)
        return 0;
775

776 777 778 779 780 781
    /* XXX having to iterate here is not great because it requires many locks */
    qemuDriverLock(qemu_driver);
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
    qemuDriverUnlock(qemu_driver);
    return active;
}
782

783 784 785 786 787 788 789 790
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
    int i;
791

792 793
    if (!qemu_driver)
        return -1;
794

795 796
    qemuDriverLock(qemu_driver);
    pciDeviceListFree(qemu_driver->activePciHostdevs);
797
    pciDeviceListFree(qemu_driver->inactivePciHostdevs);
798
    usbDeviceListFree(qemu_driver->activeUsbHostdevs);
799
    virCapabilitiesFree(qemu_driver->caps);
800

801 802
    virDomainObjListDeinit(&qemu_driver->domains);
    virBitmapFree(qemu_driver->reservedVNCPorts);
803

804
    virSysinfoDefFree(qemu_driver->hostsysinfo);
805

806
    qemuProcessAutoDestroyShutdown(qemu_driver);
807
    qemuDriverCloseCallbackShutdown(qemu_driver);
808

809 810 811 812 813 814 815 816
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
    VIR_FREE(qemu_driver->logDir);
    VIR_FREE(qemu_driver->stateDir);
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
    VIR_FREE(qemu_driver->saveDir);
    VIR_FREE(qemu_driver->snapshotDir);
E
Eric Blake 已提交
817
    VIR_FREE(qemu_driver->qemuImgBinary);
818 819 820 821 822 823 824 825 826 827 828 829
    VIR_FREE(qemu_driver->autoDumpPath);
    VIR_FREE(qemu_driver->vncTLSx509certdir);
    VIR_FREE(qemu_driver->vncListen);
    VIR_FREE(qemu_driver->vncPassword);
    VIR_FREE(qemu_driver->vncSASLdir);
    VIR_FREE(qemu_driver->spiceTLSx509certdir);
    VIR_FREE(qemu_driver->spiceListen);
    VIR_FREE(qemu_driver->spicePassword);
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
    VIR_FREE(qemu_driver->saveImageFormat);
    VIR_FREE(qemu_driver->dumpImageFormat);
830

831
    virSecurityManagerFree(qemu_driver->securityManager);
832

833
    ebtablesContextFree(qemu_driver->ebtables);
834

835 836 837 838
    if (qemu_driver->cgroupDeviceACL) {
        for (i = 0 ; qemu_driver->cgroupDeviceACL[i] != NULL ; i++)
            VIR_FREE(qemu_driver->cgroupDeviceACL[i]);
        VIR_FREE(qemu_driver->cgroupDeviceACL);
S
Stefan Berger 已提交
839 840
    }

841
    /* Free domain callback list */
842
    virDomainEventStateFree(qemu_driver->domainEventState);
D
Daniel P. Berrange 已提交
843

844
    virCgroupFree(&qemu_driver->cgroup);
845

846 847
    virLockManagerPluginUnref(qemu_driver->lockManager);

848 849 850 851
    qemuDriverUnlock(qemu_driver);
    virMutexDestroy(&qemu_driver->lock);
    virThreadPoolFree(qemu_driver->workerPool);
    VIR_FREE(qemu_driver);
852

853
    return 0;
854 855
}

856

857
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
858
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
859
                                  unsigned int flags)
860
{
E
Eric Blake 已提交
861 862
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

863
    if (conn->uri == NULL) {
864 865 866
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

M
Martin Kletzander 已提交
867
        conn->uri = virURIParse(qemu_driver->privileged ?
868 869
                                "qemu:///system" :
                                "qemu:///session");
870
        if (!conn->uri) {
871
            virReportOOMError();
872 873
            return VIR_DRV_OPEN_ERROR;
        }
874 875 876 877 878 879 880 881 882 883
    } else {
        /* If URI isn't 'qemu' its definitely not for us */
        if (conn->uri->scheme == NULL ||
            STRNEQ(conn->uri->scheme, "qemu"))
            return VIR_DRV_OPEN_DECLINED;

        /* Allow remote driver to deal with URIs with hostname server */
        if (conn->uri->server != NULL)
            return VIR_DRV_OPEN_DECLINED;

884
        if (qemu_driver == NULL) {
885 886
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("qemu state driver is not active"));
887 888 889
            return VIR_DRV_OPEN_ERROR;
        }

890
        if (conn->uri->path == NULL) {
891 892 893 894 895
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no QEMU URI path given, try %s"),
                            qemu_driver->privileged
                            ? "qemu:///system"
                            : "qemu:///session");
896 897 898
                return VIR_DRV_OPEN_ERROR;
        }

899
        if (qemu_driver->privileged) {
900 901
            if (STRNEQ (conn->uri->path, "/system") &&
                STRNEQ (conn->uri->path, "/session")) {
902 903 904
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///system"),
                                conn->uri->path);
905 906 907 908
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
909 910 911
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///session"),
                                conn->uri->path);
912 913 914
                return VIR_DRV_OPEN_ERROR;
            }
        }
915 916 917 918 919 920 921
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
922
    struct qemud_driver *driver = conn->privateData;
923 924

    /* Get rid of callbacks registered for this conn */
925
    qemuDriverLock(driver);
926 927
    virDomainEventStateDeregisterConn(conn,
                                      driver->domainEventState);
928
    qemuProcessAutoDestroyRun(driver, conn);
929
    qemuDriverCloseCallbackRunAll(driver, conn);
930
    qemuDriverUnlock(driver);
931 932 933 934 935 936

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
937 938 939 940 941
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
942
    case VIR_DRV_FEATURE_MIGRATION_V2:
943
    case VIR_DRV_FEATURE_MIGRATION_V3:
944
    case VIR_DRV_FEATURE_MIGRATION_P2P:
945
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
946
    case VIR_DRV_FEATURE_FD_PASSING:
947
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
948 949 950
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
951 952 953
    }
}

954
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
955
    return "QEMU";
956 957
}

958

959 960 961 962 963 964 965 966 967 968 969 970
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;
}

971 972 973 974 975
static int qemuIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}

976

977 978 979 980
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
981

982 983
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
984
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
985
        return -1;
986 987 988 989 990 991
    }

    r = ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_NR_VCPUS);
    if (r > 0)
        maxvcpus = r;

992
    VIR_FORCE_CLOSE(fd);
993 994 995 996
    return maxvcpus;
}


E
Eric Blake 已提交
997 998 999 1000
static char *
qemuGetSysinfo(virConnectPtr conn, unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
1001
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
1002 1003 1004 1005 1006 1007 1008 1009 1010

    virCheckFlags(0, NULL);

    if (!driver->hostsysinfo) {
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("Host SMBIOS information is not available"));
        return NULL;
    }

1011 1012 1013 1014 1015 1016 1017
    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
    if (virBufferError(&buf)) {
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&buf);
E
Eric Blake 已提交
1018 1019
}

1020
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
1021 1022 1023
    if (!type)
        return 16;

1024
    if (STRCASEEQ(type, "qemu"))
1025 1026
        return 16;

1027
    if (STRCASEEQ(type, "kvm"))
1028
        return kvmGetMaxVCPUs();
1029

1030
    if (STRCASEEQ(type, "kqemu"))
1031
        return 1;
1032

1033 1034
    qemuReportError(VIR_ERR_INVALID_ARG,
                    _("unknown type '%s'"), type);
1035 1036 1037
    return -1;
}

1038

1039
static char *qemudGetCapabilities(virConnectPtr conn) {
1040
    struct qemud_driver *driver = conn->privateData;
1041
    virCapsPtr caps = NULL;
1042
    char *xml = NULL;
1043

1044
    qemuDriverLock(driver);
1045

1046
    if ((caps = qemuCreateCapabilities(qemu_driver->caps,
1047
                                       qemu_driver)) == NULL) {
1048 1049 1050
        virCapabilitiesFree(caps);
        goto cleanup;
    }
1051

1052
    virCapabilitiesFree(qemu_driver->caps);
1053 1054 1055
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1056
        virReportOOMError();
1057 1058

cleanup:
1059
    qemuDriverUnlock(driver);
1060

1061
    return xml;
1062 1063 1064
}


1065
static int
1066
qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
1067
                    pid_t pid, int tid)
1068 1069
{
    char *proc;
D
Daniel P. Berrange 已提交
1070
    FILE *pidinfo;
1071
    unsigned long long usertime, systime;
1072
    long rss;
1073 1074
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
1075

1076 1077
    /* In general, we cannot assume pid_t fits in int; but /proc parsing
     * is specific to Linux where int works fine.  */
1078
    if (tid)
1079
        ret = virAsprintf(&proc, "/proc/%d/task/%d/stat", (int) pid, tid);
1080
    else
1081
        ret = virAsprintf(&proc, "/proc/%d/stat", (int) pid);
1082
    if (ret < 0)
D
Daniel P. Berrange 已提交
1083 1084 1085 1086
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
1087 1088 1089 1090
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
1091 1092
        if (vm_rss)
            *vm_rss = 0;
1093
        VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1094 1095
        return 0;
    }
1096
    VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1097

1098 1099 1100 1101 1102 1103
    /* 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 */
1104
               "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
1105 1106
               /* startstack -> processor */
               "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
1107
               &usertime, &systime, &rss, &cpu) != 4) {
1108
        VIR_FORCE_FCLOSE(pidinfo);
1109
        VIR_WARN("cannot parse process status data");
1110
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
1111 1112 1113 1114 1115 1116 1117 1118
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
1119 1120 1121 1122 1123
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

1124 1125 1126 1127 1128 1129
    /* 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 已提交
1130

1131 1132

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

1135
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
1136 1137 1138 1139 1140

    return 0;
}


1141
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
1142
                                          int id) {
1143 1144 1145 1146
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1147
    qemuDriverLock(driver);
1148
    vm  = virDomainFindByID(&driver->domains, id);
1149
    qemuDriverUnlock(driver);
1150 1151

    if (!vm) {
1152 1153
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching id %d"), id);
1154
        goto cleanup;
1155 1156
    }

1157
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1158
    if (dom) dom->id = vm->def->id;
1159 1160

cleanup:
1161 1162
    if (vm)
        virDomainObjUnlock(vm);
1163 1164
    return dom;
}
1165

1166
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
1167
                                            const unsigned char *uuid) {
1168 1169 1170
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1171

1172
    qemuDriverLock(driver);
1173
    vm = virDomainFindByUUID(&driver->domains, uuid);
1174 1175
    qemuDriverUnlock(driver);

1176
    if (!vm) {
1177 1178
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
1179 1180
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1181
        goto cleanup;
1182 1183
    }

1184
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1185
    if (dom) dom->id = vm->def->id;
1186 1187

cleanup:
1188 1189
    if (vm)
        virDomainObjUnlock(vm);
1190 1191
    return dom;
}
1192

1193
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
1194
                                            const char *name) {
1195 1196 1197
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1198

1199
    qemuDriverLock(driver);
1200
    vm = virDomainFindByName(&driver->domains, name);
1201 1202
    qemuDriverUnlock(driver);

1203
    if (!vm) {
1204 1205
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), name);
1206
        goto cleanup;
1207 1208
    }

1209
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1210
    if (dom) dom->id = vm->def->id;
1211 1212

cleanup:
1213 1214
    if (vm)
        virDomainObjUnlock(vm);
1215 1216 1217
    return dom;
}

1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228

static int qemuDomainIsActive(virDomainPtr dom)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    qemuDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!obj) {
E
Eric Blake 已提交
1229 1230 1231 1232
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}

static int qemuDomainIsPersistent(virDomainPtr dom)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    qemuDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!obj) {
E
Eric Blake 已提交
1253 1254 1255 1256
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}

1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
static int qemuDomainIsUpdated(virDomainPtr dom)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    qemuDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!obj) {
E
Eric Blake 已提交
1277 1278 1279 1280
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1281 1282 1283 1284 1285 1286 1287 1288 1289
        goto cleanup;
    }
    ret = obj->updated;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}
1290

1291
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
1292 1293 1294
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

1295
    qemuDriverLock(driver);
1296
    if (qemuCapsExtractVersion(driver->caps, &driver->qemuVersion) < 0)
1297
        goto cleanup;
1298

1299
    *version = driver->qemuVersion;
1300 1301 1302
    ret = 0;

cleanup:
1303
    qemuDriverUnlock(driver);
1304
    return ret;
D
Daniel P. Berrange 已提交
1305 1306
}

1307
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
1308
    struct qemud_driver *driver = conn->privateData;
1309
    int n;
1310

1311
    qemuDriverLock(driver);
1312
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1313
    qemuDriverUnlock(driver);
1314

1315
    return n;
D
Daniel P. Berrange 已提交
1316
}
1317

1318
static int qemudNumDomains(virConnectPtr conn) {
1319
    struct qemud_driver *driver = conn->privateData;
1320
    int n;
1321

1322
    qemuDriverLock(driver);
1323
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1324
    qemuDriverUnlock(driver);
1325

1326
    return n;
D
Daniel P. Berrange 已提交
1327
}
1328

1329
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
1330
                                      unsigned int flags) {
1331
    struct qemud_driver *driver = conn->privateData;
1332
    virDomainDefPtr def;
1333
    virDomainObjPtr vm = NULL;
1334
    virDomainPtr dom = NULL;
1335
    virDomainEventPtr event = NULL;
1336
    virDomainEventPtr event2 = NULL;
D
Daniel P. Berrange 已提交
1337

1338 1339
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_AUTODESTROY, NULL);
1340

1341
    qemuDriverLock(driver);
1342
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1343
                                        QEMU_EXPECTED_VIRT_TYPES,
1344
                                        VIR_DOMAIN_XML_INACTIVE)))
1345
        goto cleanup;
1346

1347
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1348 1349
        goto cleanup;

1350 1351
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
1352

1353 1354 1355
    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

1356
    if (qemuDomainAssignAddresses(def) < 0)
1357 1358
        goto cleanup;

1359
    if (!(vm = virDomainAssignDef(driver->caps,
1360
                                  &driver->domains,
1361
                                  def, false)))
1362 1363 1364
        goto cleanup;

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

1366
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
1367 1368
        goto cleanup; /* XXXX free the 'vm' we created ? */

1369
    if (qemuProcessStart(conn, driver, vm, NULL, true,
1370
                         (flags & VIR_DOMAIN_START_PAUSED) != 0,
1371
                         (flags & VIR_DOMAIN_START_AUTODESTROY) != 0,
1372
                         -1, NULL, NULL, VIR_NETDEV_VPORT_PROFILE_OP_CREATE) < 0) {
1373
        virDomainAuditStart(vm, "booted", false);
1374
        if (qemuDomainObjEndJob(driver, vm) > 0)
1375
            qemuDomainRemoveInactive(driver, vm);
1376
        vm = NULL;
1377
        goto cleanup;
D
Daniel P. Berrange 已提交
1378
    }
1379 1380 1381 1382

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392
    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);
    }
1393
    virDomainAuditStart(vm, "booted", true);
D
Daniel P. Berrange 已提交
1394

1395
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1396
    if (dom) dom->id = vm->def->id;
1397

1398
    if (vm &&
1399
        qemuDomainObjEndJob(driver, vm) == 0)
1400
        vm = NULL;
1401

1402 1403
cleanup:
    virDomainDefFree(def);
1404 1405
    if (vm)
        virDomainObjUnlock(vm);
1406
    if (event) {
1407
        qemuDomainEventQueue(driver, event);
1408 1409 1410
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
1411
    qemuDriverUnlock(driver);
1412
    return dom;
D
Daniel P. Berrange 已提交
1413 1414 1415
}


1416
static int qemudDomainSuspend(virDomainPtr dom) {
1417 1418 1419
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1420
    virDomainEventPtr event = NULL;
1421
    qemuDomainObjPrivatePtr priv;
1422 1423
    virDomainPausedReason reason;
    int eventDetail;
1424

1425
    qemuDriverLock(driver);
1426
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1427

D
Daniel P. Berrange 已提交
1428
    if (!vm) {
1429 1430
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1431 1432
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1433
        goto cleanup;
D
Daniel P. Berrange 已提交
1434
    }
D
Daniel P. Berrange 已提交
1435
    if (!virDomainObjIsActive(vm)) {
1436 1437
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1438
        goto cleanup;
D
Daniel P. Berrange 已提交
1439
    }
1440 1441 1442

    priv = vm->privateData;

1443
    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) {
1444 1445
        reason = VIR_DOMAIN_PAUSED_MIGRATION;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED;
1446
    } else {
1447 1448 1449
        reason = VIR_DOMAIN_PAUSED_USER;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
    }
1450

1451 1452 1453 1454 1455 1456 1457 1458 1459
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_SUSPEND) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
1460
        if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) {
1461
            goto endjob;
1462
        }
1463 1464 1465
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         eventDetail);
D
Daniel P. Berrange 已提交
1466
    }
1467 1468 1469
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto endjob;
    ret = 0;
1470

1471
endjob:
1472
    if (qemuDomainObjEndJob(driver, vm) == 0)
1473
        vm = NULL;
1474

1475
cleanup:
1476 1477
    if (vm)
        virDomainObjUnlock(vm);
1478

1479
    if (event)
1480
        qemuDomainEventQueue(driver, event);
1481
    qemuDriverUnlock(driver);
1482
    return ret;
D
Daniel P. Berrange 已提交
1483 1484 1485
}


1486
static int qemudDomainResume(virDomainPtr dom) {
1487 1488 1489
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1490
    virDomainEventPtr event = NULL;
1491

1492
    qemuDriverLock(driver);
1493
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1494

D
Daniel P. Berrange 已提交
1495
    if (!vm) {
1496 1497
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1498 1499
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1500
        goto cleanup;
D
Daniel P. Berrange 已提交
1501
    }
1502

1503
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
1504 1505
        goto cleanup;

D
Daniel P. Berrange 已提交
1506
    if (!virDomainObjIsActive(vm)) {
1507 1508
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1509
        goto endjob;
D
Daniel P. Berrange 已提交
1510
    }
J
Jiri Denemark 已提交
1511 1512
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
        if (qemuProcessStartCPUs(driver, vm, dom->conn,
1513 1514
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
1515
            if (virGetLastError() == NULL)
1516 1517
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resume operation failed"));
1518
            goto endjob;
1519
        }
1520 1521 1522
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
1523
    }
1524
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
1525
        goto endjob;
1526 1527
    ret = 0;

1528
endjob:
1529
    if (qemuDomainObjEndJob(driver, vm) == 0)
1530
        vm = NULL;
1531

1532
cleanup:
1533 1534
    if (vm)
        virDomainObjUnlock(vm);
1535
    if (event)
1536
        qemuDomainEventQueue(driver, event);
1537
    qemuDriverUnlock(driver);
1538
    return ret;
D
Daniel P. Berrange 已提交
1539 1540
}

1541
static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) {
1542 1543 1544
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1545
    qemuDomainObjPrivatePtr priv;
1546 1547 1548 1549
    bool useAgent = false;

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
1550

1551
    qemuDriverLock(driver);
1552
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1553 1554
    qemuDriverUnlock(driver);

1555
    if (!vm) {
1556 1557
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1558 1559
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1560
        goto cleanup;
1561 1562
    }

1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573
    priv = vm->privateData;

    if ((flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT) ||
        (!(flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
         priv->agent))
        useAgent = true;

    if (useAgent) {
        if (priv->agentError) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("QEMU guest agent is not available due to an error"));
1574
            goto cleanup;
1575 1576 1577 1578
        }
        if (!priv->agent) {
            qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                            _("QEMU guest agent is not configured"));
1579
            goto cleanup;
1580 1581 1582
        }
    }

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

D
Daniel P. Berrange 已提交
1586
    if (!virDomainObjIsActive(vm)) {
1587 1588
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1589
        goto endjob;
1590 1591
    }

1592 1593 1594 1595 1596 1597
    if (useAgent) {
        qemuDomainObjEnterAgent(driver, vm);
        ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_POWERDOWN);
        qemuDomainObjExitAgent(driver, vm);
    } else {
        qemuDomainSetFakeReboot(driver, vm, false);
1598

1599 1600 1601 1602
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSystemPowerdown(priv->mon);
        qemuDomainObjExitMonitor(driver, vm);
    }
1603

1604
endjob:
1605
    if (qemuDomainObjEndJob(driver, vm) == 0)
1606
        vm = NULL;
1607

1608
cleanup:
1609 1610
    if (vm)
        virDomainObjUnlock(vm);
1611
    return ret;
1612 1613
}

1614 1615 1616 1617
static int qemuDomainShutdown(virDomainPtr dom) {
    return qemuDomainShutdownFlags(dom, 0);
}

1618

1619 1620 1621 1622 1623
static int qemuDomainReboot(virDomainPtr dom, unsigned int flags) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
1624
    bool useAgent = false;
1625

1626 1627
    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT , -1);
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

1641 1642
    priv = vm->privateData;

1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668
    if ((flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT) ||
        (!(flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
         priv->agent))
        useAgent = true;

    if (useAgent) {
        if (priv->agentError) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("QEMU guest agent is not available due to an error"));
            goto cleanup;
        }
        if (!priv->agent) {
            qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                            _("QEMU guest agent is not configured"));
            goto cleanup;
        }
    } else {
#if HAVE_YAJL
        if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
            if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) {
                qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                _("Reboot is not supported with this QEMU binary"));
                goto cleanup;
            }
        } else {
#endif
1669
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
1670
                            _("Reboot is not supported without the JSON monitor"));
1671
            goto cleanup;
1672
#if HAVE_YAJL
1673
        }
1674 1675
#endif
    }
1676

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

1680 1681 1682 1683 1684
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }
1685

1686 1687 1688 1689 1690
    if (useAgent) {
        qemuDomainObjEnterAgent(driver, vm);
        ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_REBOOT);
        qemuDomainObjExitAgent(driver, vm);
    } else {
1691
        qemuDomainObjEnterMonitor(driver, vm);
1692
        ret = qemuMonitorSystemPowerdown(priv->mon);
1693
        qemuDomainObjExitMonitor(driver, vm);
1694

1695 1696
        if (ret == 0)
            qemuDomainSetFakeReboot(driver, vm, true);
1697 1698
    }

1699 1700 1701 1702
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

1703 1704 1705 1706 1707 1708 1709
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
static int
qemuDomainReset(virDomainPtr dom, unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

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

    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        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)
        virDomainObjUnlock(vm);
    return ret;
}


1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771
/* Count how many snapshots in a set have external disk snapshots.  */
static void
qemuDomainSnapshotCountExternal(void *payload,
                                const void *name ATTRIBUTE_UNUSED,
                                void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    int *count = data;

    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT)
        (*count)++;
}

1772 1773 1774 1775
static int
qemuDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
1776 1777 1778
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1779
    virDomainEventPtr event = NULL;
1780
    qemuDomainObjPrivatePtr priv;
1781

1782
    virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1);
1783

1784
    qemuDriverLock(driver);
1785
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
1786
    if (!vm) {
1787 1788
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1789 1790
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1791
        goto cleanup;
D
Daniel P. Berrange 已提交
1792
    }
1793

1794 1795
    priv = vm->privateData;

1796
    qemuDomainSetFakeReboot(driver, vm, false);
1797

1798 1799 1800 1801 1802
    /* 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
     */
1803
    if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
1804
        if (qemuProcessKill(driver, vm, 0) < 0) {
1805
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
1806 1807 1808 1809
                            _("failed to kill qemu process with SIGTERM"));
            goto cleanup;
        }
    } else {
1810
        ignore_value(qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE));
1811
    }
1812

1813 1814 1815 1816 1817
    /* We need to prevent monitor EOF callback from doing our work (and sending
     * misleading events) while the vm is unlocked inside BeginJob API
     */
    priv->beingDestroyed = true;

1818
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_DESTROY) < 0)
1819 1820
        goto cleanup;

1821 1822
    priv->beingDestroyed = false;

D
Daniel P. Berrange 已提交
1823
    if (!virDomainObjIsActive(vm)) {
1824 1825
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1826
        goto endjob;
1827
    }
1828

J
Jiri Denemark 已提交
1829
    qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_DESTROYED);
1830 1831 1832
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1833
    virDomainAuditStop(vm, "destroyed");
1834

1835
    if (!vm->persistent) {
1836
        if (qemuDomainObjEndJob(driver, vm) > 0)
1837
            qemuDomainRemoveInactive(driver, vm);
1838 1839
        vm = NULL;
    }
1840 1841
    ret = 0;

1842
endjob:
1843
    if (vm &&
1844
        qemuDomainObjEndJob(driver, vm) == 0)
1845
        vm = NULL;
1846

1847
cleanup:
1848 1849
    if (vm)
        virDomainObjUnlock(vm);
1850 1851
    if (event)
        qemuDomainEventQueue(driver, event);
1852
    qemuDriverUnlock(driver);
1853
    return ret;
D
Daniel P. Berrange 已提交
1854 1855
}

1856 1857 1858 1859 1860
static int
qemuDomainDestroy(virDomainPtr dom)
{
    return qemuDomainDestroyFlags(dom, 0);
}
D
Daniel P. Berrange 已提交
1861

1862
static char *qemudDomainGetOSType(virDomainPtr dom) {
1863 1864 1865
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1866

1867
    qemuDriverLock(driver);
1868
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1869
    qemuDriverUnlock(driver);
1870
    if (!vm) {
1871 1872
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1873 1874
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1875
        goto cleanup;
1876 1877
    }

1878
    if (!(type = strdup(vm->def->os.type)))
1879
        virReportOOMError();
1880 1881

cleanup:
1882 1883
    if (vm)
        virDomainObjUnlock(vm);
1884 1885 1886
    return type;
}

1887
/* Returns max memory in kb, 0 if error */
1888 1889 1890
static unsigned long long
qemuDomainGetMaxMemory(virDomainPtr dom)
{
1891 1892
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1893
    unsigned long long ret = 0;
1894

1895
    qemuDriverLock(driver);
1896
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1897 1898
    qemuDriverUnlock(driver);

1899
    if (!vm) {
1900 1901
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1902 1903
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1904
        goto cleanup;
1905 1906
    }

1907
    ret = vm->def->mem.max_balloon;
1908 1909

cleanup:
1910 1911
    if (vm)
        virDomainObjUnlock(vm);
1912
    return ret;
1913 1914
}

1915 1916
static int qemudDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                     unsigned int flags) {
1917
    struct qemud_driver *driver = dom->conn->privateData;
1918
    qemuDomainObjPrivatePtr priv;
1919
    virDomainObjPtr vm;
1920
    virDomainDefPtr persistentDef = NULL;
1921
    int ret = -1, r;
1922

1923 1924
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
1925
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
1926

1927
    qemuDriverLock(driver);
1928
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1929
    qemuDriverUnlock(driver);
1930
    if (!vm) {
1931 1932
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1933 1934
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1935
        goto cleanup;
1936 1937
    }

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

1941 1942
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
1943
        goto endjob;
1944

1945 1946 1947
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */

1948
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
1949 1950 1951
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot resize the maximum memory on an "
                              "active domain"));
1952
            goto endjob;
1953
        }
1954

1955
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
1956 1957
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
1958 1959 1960 1961
            persistentDef->mem.max_balloon = newmem;
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
            ret = virDomainSaveConfig(driver->configDir, persistentDef);
1962 1963 1964
            goto endjob;
        }

1965 1966 1967 1968 1969 1970 1971 1972 1973
    } else {
        /* resize the current memory */

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

1974
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
1975
            priv = vm->privateData;
1976
            qemuDomainObjEnterMonitor(driver, vm);
1977
            r = qemuMonitorSetBalloon(priv->mon, newmem);
1978
            qemuDomainObjExitMonitor(driver, vm);
1979 1980
            virDomainAuditMemory(vm, vm->def->mem.cur_balloon, newmem, "update",
                                 r == 1);
1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
            if (r < 0)
                goto endjob;

            /* Lack of balloon support is a fatal error */
            if (r == 0) {
                qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                _("cannot set memory of an active domain"));
                goto endjob;
            }
        }

1992
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
1993
            sa_assert(persistentDef);
1994 1995 1996 1997
            persistentDef->mem.cur_balloon = newmem;
            ret = virDomainSaveConfig(driver->configDir, persistentDef);
            goto endjob;
        }
1998
    }
1999

2000
    ret = 0;
2001
endjob:
2002
    if (qemuDomainObjEndJob(driver, vm) == 0)
2003
        vm = NULL;
2004

2005
cleanup:
2006 2007
    if (vm)
        virDomainObjUnlock(vm);
2008
    return ret;
2009 2010
}

2011 2012
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
2013
    return qemudDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
2014 2015
}

2016 2017 2018 2019 2020
static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
{
    return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
}

2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047
static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

    priv = vm->privateData;

2048
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
2049
        goto cleanup;
2050 2051 2052 2053 2054 2055 2056

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

2057
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2058 2059
    ret = qemuMonitorInjectNMI(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2060 2061

endjob:
2062
    if (qemuDomainObjEndJob(driver, vm) == 0) {
2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
        vm = NULL;
        goto cleanup;
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087
static int qemuDomainSendKey(virDomainPtr domain,
                             unsigned int codeset,
                             unsigned int holdtime,
                             unsigned int *keycodes,
                             int nkeycodes,
                             unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2088 2089
    /* translate the keycode to RFB for qemu driver */
    if (codeset != VIR_KEYCODE_SET_RFB) {
2090 2091 2092 2093
        int i;
        int keycode;

        for (i = 0; i < nkeycodes; i++) {
2094
            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_RFB,
2095 2096 2097
                                               keycodes[i]);
            if (keycode < 0) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
2098
             _("cannot translate keycode %u of %s codeset to rfb keycode"),
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124
                                keycodes[i],
                                virKeycodeSetTypeToString(codeset));
                return -1;
            }
            keycodes[i] = keycode;
        }
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    priv = vm->privateData;

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

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

2128
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2129 2130
    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2131 2132 2133

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
2134 2135 2136 2137 2138 2139 2140 2141 2142
        vm = NULL;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

2143
static int qemudDomainGetInfo(virDomainPtr dom,
2144 2145
                              virDomainInfoPtr info)
{
2146 2147 2148
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2149
    int err;
2150
    unsigned long long balloon;
2151

2152
    qemuDriverLock(driver);
2153
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2154
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
2155
    if (!vm) {
2156 2157
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2158 2159
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
2160
        goto cleanup;
D
Daniel P. Berrange 已提交
2161 2162
    }

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

D
Daniel P. Berrange 已提交
2165
    if (!virDomainObjIsActive(vm)) {
2166
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2167
    } else {
2168
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) {
E
Eric Blake 已提交
2169 2170
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("cannot read cputime for domain"));
2171
            goto cleanup;
D
Daniel P. Berrange 已提交
2172 2173 2174
        }
    }

2175
    info->maxMem = vm->def->mem.max_balloon;
2176

D
Daniel P. Berrange 已提交
2177
    if (virDomainObjIsActive(vm)) {
2178
        qemuDomainObjPrivatePtr priv = vm->privateData;
2179 2180 2181

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
2182
            info->memory = vm->def->mem.max_balloon;
2183
        } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
2184
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
2185
                goto cleanup;
2186 2187 2188
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
2189
                qemuDomainObjEnterMonitor(driver, vm);
2190
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
2191
                qemuDomainObjExitMonitor(driver, vm);
2192
            }
2193
            if (qemuDomainObjEndJob(driver, vm) == 0) {
2194
                vm = NULL;
2195 2196 2197
                goto cleanup;
            }

2198 2199 2200 2201 2202 2203 2204
            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) {
2205
                /* Balloon not supported, so maxmem is always the allocation */
2206
                info->memory = vm->def->mem.max_balloon;
2207
            } else {
2208
                info->memory = balloon;
2209
            }
2210
        } else {
2211
            info->memory = vm->def->mem.cur_balloon;
2212
        }
2213
    } else {
2214
        info->memory = vm->def->mem.cur_balloon;
2215 2216
    }

2217
    info->nrVirtCpu = vm->def->vcpus;
2218 2219 2220
    ret = 0;

cleanup:
2221 2222
    if (vm)
        virDomainObjUnlock(vm);
2223
    return ret;
D
Daniel P. Berrange 已提交
2224 2225
}

2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249
static int
qemuDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

J
Jiri Denemark 已提交
2250
    *state = virDomainObjGetState(vm, reason);
2251 2252 2253 2254 2255 2256 2257 2258
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294
static int
qemuDomainGetControlInfo(virDomainPtr dom,
                          virDomainControlInfoPtr info,
                          unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

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

    priv = vm->privateData;

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

    if (priv->monError) {
        info->state = VIR_DOMAIN_CONTROL_ERROR;
2295
    } else if (priv->job.active) {
2296 2297
        if (!priv->monStart) {
            info->state = VIR_DOMAIN_CONTROL_JOB;
2298
            if (virTimeMillisNow(&info->stateTime) < 0)
2299
                goto cleanup;
2300
            info->stateTime -= priv->job.start;
2301 2302
        } else {
            info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
2303
            if (virTimeMillisNow(&info->stateTime) < 0)
2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318
                goto cleanup;
            info->stateTime -= priv->monStart;
        }
    } else {
        info->state = VIR_DOMAIN_CONTROL_OK;
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

D
Daniel P. Berrange 已提交
2319

E
Eric Blake 已提交
2320 2321
#define QEMUD_SAVE_MAGIC   "LibvirtQemudSave"
#define QEMUD_SAVE_PARTIAL "LibvirtQemudPart"
2322 2323
#define QEMUD_SAVE_VERSION 2

E
Eric Blake 已提交
2324 2325
verify(sizeof(QEMUD_SAVE_MAGIC) == sizeof(QEMUD_SAVE_PARTIAL));

2326
enum qemud_save_formats {
2327 2328 2329
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
2330 2331
    /*
     * Deprecated by xz and never used as part of a release
2332
     * QEMUD_SAVE_FORMAT_LZMA
2333 2334
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
2335
    QEMUD_SAVE_FORMAT_LZOP = 4,
2336 2337 2338
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2339 2340

    QEMUD_SAVE_FORMAT_LAST
2341
};
2342

2343 2344 2345 2346 2347
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
2348 2349
              "xz",
              "lzop")
2350

2351 2352
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
2353 2354 2355 2356 2357
    uint32_t version;
    uint32_t xml_len;
    uint32_t was_running;
    uint32_t compressed;
    uint32_t unused[15];
2358 2359
};

2360 2361 2362 2363 2364 2365 2366 2367 2368
static inline void
bswap_header(struct qemud_save_header *hdr) {
    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);
}


2369
/* return -errno on failure, or 0 on success */
E
Eric Blake 已提交
2370 2371 2372 2373
static int
qemuDomainSaveHeader(int fd, const char *path, char *xml,
                     struct qemud_save_header *header)
{
2374 2375
    int ret = 0;

E
Eric Blake 已提交
2376
    if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
2377
        ret = -errno;
2378
        qemuReportError(VIR_ERR_OPERATION_FAILED,
2379
                        _("failed to write header to domain save file '%s'"),
E
Eric Blake 已提交
2380
                        path);
2381 2382 2383
        goto endjob;
    }

E
Eric Blake 已提交
2384
    if (safewrite(fd, xml, header->xml_len) != header->xml_len) {
2385
        ret = -errno;
2386
        qemuReportError(VIR_ERR_OPERATION_FAILED,
E
Eric Blake 已提交
2387
                         _("failed to write xml to '%s'"), path);
2388 2389 2390 2391 2392 2393
        goto endjob;
    }
endjob:
    return ret;
}

2394 2395 2396 2397 2398 2399 2400 2401 2402
/* Given a enum qemud_save_formats compression level, return the name
 * of the program to run, or NULL if no program is needed.  */
static const char *
qemuCompressProgramName(int compress)
{
    return (compress == QEMUD_SAVE_FORMAT_RAW ? NULL :
            qemudSaveCompressionTypeToString(compress));
}

E
Eric Blake 已提交
2403 2404 2405 2406 2407 2408 2409 2410 2411 2412
/* Internal function to properly create or open existing files, with
 * ownership affected by qemu driver setup.  */
static int
qemuOpenFile(struct qemud_driver *driver, const char *path, int oflags,
             bool *needUnlink, bool *bypassSecurityDriver)
{
    struct stat sb;
    bool is_reg = true;
    bool need_unlink = false;
    bool bypass_security = false;
L
Laine Stump 已提交
2413
    unsigned int vfoflags = 0;
E
Eric Blake 已提交
2414 2415 2416 2417 2418 2419 2420 2421 2422
    int fd = -1;
    uid_t uid = getuid();
    gid_t gid = getgid();

    /* 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;
L
Laine Stump 已提交
2423
        vfoflags |= VIR_FILE_OPEN_FORCE_OWNER;
E
Eric Blake 已提交
2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443
        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 */
            if (is_reg && !driver->dynamicOwnership) {
                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 已提交
2444 2445
        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
E
Eric Blake 已提交
2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488
            /* 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
               qemu user (driver->user) is non-root, just set a flag to
               bypass security driver shenanigans, and retry the operation
               after doing setuid to qemu user */
            if ((fd != -EACCES && fd != -EPERM) ||
                driver->user == getuid()) {
                virReportSystemError(-fd,
                                     _("Failed to create file '%s'"),
                                     path);
                goto cleanup;
            }

            /* On Linux we can also verify the FS-type of the directory. */
            switch (virStorageFileIsSharedFS(path)) {
                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;
            }

            /* Retry creating the file as driver->user */

            if ((fd = virFileOpenAs(path, oflags,
                                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
                                    driver->user, driver->group,
L
Laine Stump 已提交
2489
                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
E
Eric Blake 已提交
2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511
                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;

    return fd;
}

2512
/* This internal function expects the driver lock to already be held on
2513 2514 2515 2516
 * entry and the vm must be active + locked. Vm will be unlocked and
 * 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).
2517
 */
2518 2519 2520
static int
qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
                       virDomainObjPtr vm, const char *path,
2521
                       int compressed, const char *xmlin, unsigned int flags)
2522
{
2523
    char *xml = NULL;
2524
    struct qemud_save_header header;
2525
    bool bypassSecurityDriver = false;
2526
    int ret = -1;
2527
    int rc;
2528
    virDomainEventPtr event = NULL;
2529
    qemuDomainObjPrivatePtr priv;
E
Eric Blake 已提交
2530
    bool needUnlink = false;
2531
    size_t len;
2532
    unsigned long long offset;
2533
    unsigned long long pad;
2534
    int fd = -1;
2535
    int directFlag = 0;
J
Jiri Denemark 已提交
2536
    virFileWrapperFdPtr wrapperFd = NULL;
2537
    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
2538

2539 2540 2541
    if (qemuProcessAutoDestroyActive(driver, vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is marked for auto destroy"));
2542
        goto cleanup;
2543 2544
    }

2545
    memset(&header, 0, sizeof(header));
E
Eric Blake 已提交
2546
    memcpy(header.magic, QEMUD_SAVE_PARTIAL, sizeof(header.magic));
2547 2548
    header.version = QEMUD_SAVE_VERSION;

2549
    header.compressed = compressed;
2550

2551
    priv = vm->privateData;
2552

2553 2554
    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_SAVE) < 0)
2555 2556
        goto cleanup;

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

2560
    /* Pause */
J
Jiri Denemark 已提交
2561
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
2562
        header.was_running = 1;
2563 2564
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_SAVE) < 0)
2565
            goto endjob;
2566 2567 2568 2569 2570 2571

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto endjob;
        }
2572
    }
2573 2574 2575 2576 2577
    /* libvirt.c already guaranteed these two flags are exclusive.  */
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        header.was_running = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        header.was_running = 0;
2578

2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594
    /* 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;

        if (!(def = virDomainDefParseString(driver->caps, xmlin,
                                            QEMU_EXPECTED_VIRT_TYPES,
                                            VIR_DOMAIN_XML_INACTIVE))) {
            goto endjob;
        }
        if (!virDomainDefCheckABIStability(vm->def, def)) {
            virDomainDefFree(def);
            goto endjob;
        }
2595
        xml = qemuDomainDefFormatLive(driver, def, true);
2596
    } else {
2597
        xml = qemuDomainDefFormatLive(driver, vm->def, true);
2598
    }
2599
    if (!xml) {
2600 2601
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
2602
        goto endjob;
2603
    }
2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623
    len = strlen(xml) + 1;
    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));
    if (VIR_EXPAND_N(xml, len, pad) < 0) {
        virReportOOMError();
        goto endjob;
    }
    offset += pad;
    header.xml_len = len;
2624

2625
    /* Obtain the file handle.  */
2626 2627
    if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
2628 2629 2630 2631
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("bypass cache unsupported by this system"));
E
Eric Blake 已提交
2632
            goto cleanup;
2633
        }
2634
    }
E
Eric Blake 已提交
2635 2636 2637 2638
    fd = qemuOpenFile(driver, path, O_WRONLY | O_TRUNC | O_CREAT | directFlag,
                      &needUnlink, &bypassSecurityDriver);
    if (fd < 0)
        goto endjob;
2639
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
2640 2641
        goto endjob;

2642
    /* Write header to file, followed by XML */
E
Eric Blake 已提交
2643
    if (qemuDomainSaveHeader(fd, path, xml, &header) < 0) {
2644 2645 2646 2647
        VIR_FORCE_CLOSE(fd);
        goto endjob;
    }

2648
    /* Perform the migration */
2649
    if (qemuMigrationToFile(driver, vm, fd, offset, path,
2650
                            qemuCompressProgramName(compressed),
E
Eric Blake 已提交
2651
                            bypassSecurityDriver,
2652
                            QEMU_ASYNC_JOB_SAVE) < 0)
2653
        goto endjob;
E
Eric Blake 已提交
2654

2655 2656 2657 2658 2659 2660 2661 2662 2663
    /* 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);
        goto endjob;
E
Eric Blake 已提交
2664
    }
2665 2666 2667 2668 2669 2670
    if (virFileWrapperFdClose(wrapperFd) < 0)
        goto endjob;
    fd = qemuOpenFile(driver, path, O_WRONLY, NULL, NULL);
    if (fd < 0)
        goto endjob;

E
Eric Blake 已提交
2671 2672 2673 2674 2675
    memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        virReportSystemError(errno, _("unable to write %s"), path);
        goto endjob;
    }
2676 2677
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
2678
        goto endjob;
2679 2680
    }

2681 2682
    ret = 0;

2683
    /* Shut it down */
J
Jiri Denemark 已提交
2684
    qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_SAVED);
2685
    virDomainAuditStop(vm, "saved");
2686 2687 2688
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
2689
    if (!vm->persistent) {
2690
        if (qemuDomainObjEndAsyncJob(driver, vm) > 0)
2691
            qemuDomainRemoveInactive(driver, vm);
2692 2693
        vm = NULL;
    }
2694

2695
endjob:
2696
    if (vm) {
2697
        if (ret != 0) {
2698
            if (header.was_running && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
2699
                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
2700 2701
                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED,
                                          QEMU_ASYNC_JOB_SAVE);
2702
                if (rc < 0)
2703
                    VIR_WARN("Unable to resume guest CPUs after save failure");
2704
            }
2705
        }
2706
        if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
2707
            vm = NULL;
2708
    }
2709

2710
cleanup:
2711
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
2712
    virFileWrapperFdFree(wrapperFd);
2713
    VIR_FREE(xml);
E
Eric Blake 已提交
2714
    if (ret != 0 && needUnlink)
2715
        unlink(path);
2716 2717
    if (event)
        qemuDomainEventQueue(driver, event);
2718 2719
    if (vm)
        virDomainObjUnlock(vm);
2720
    return ret;
D
Daniel P. Berrange 已提交
2721 2722
}

2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738
/* Returns true if a compression program is available in PATH */
static bool qemudCompressProgramAvailable(enum qemud_save_formats compress)
{
    const char *prog;
    char *c;

    if (compress == QEMUD_SAVE_FORMAT_RAW)
        return true;
    prog = qemudSaveCompressionTypeToString(compress);
    c = virFindFileInPath(prog);
    if (!c)
        return false;
    VIR_FREE(c);
    return true;
}

2739 2740 2741
static int
qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                    unsigned int flags)
2742 2743 2744
{
    struct qemud_driver *driver = dom->conn->privateData;
    int compressed;
2745 2746 2747
    int ret = -1;
    virDomainObjPtr vm = NULL;

2748 2749 2750
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
2751

2752
    qemuDriverLock(driver);
2753 2754 2755 2756 2757 2758 2759 2760 2761

    if (driver->saveImageFormat == NULL)
        compressed = QEMUD_SAVE_FORMAT_RAW;
    else {
        compressed = qemudSaveCompressionTypeFromString(driver->saveImageFormat);
        if (compressed < 0) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Invalid save image format specified "
                                    "in configuration file"));
2762
            goto cleanup;
2763
        }
2764 2765 2766 2767
        if (!qemudCompressProgramAvailable(compressed)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Compression program for image format "
                                    "in configuration file isn't available"));
2768
            goto cleanup;
2769
        }
2770 2771
    }

2772 2773 2774 2775 2776 2777 2778 2779 2780
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

2781 2782 2783 2784 2785 2786
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2787
    ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
2788
                                 dxml, flags);
2789
    vm = NULL;
2790 2791 2792 2793 2794 2795 2796

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    return ret;
2797 2798
}

2799 2800 2801 2802 2803 2804
static int
qemuDomainSave(virDomainPtr dom, const char *path)
{
    return qemuDomainSaveFlags(dom, path, NULL, 0);
}

2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825
static char *
qemuDomainManagedSavePath(struct qemud_driver *driver, virDomainObjPtr vm) {
    char *ret;

    if (virAsprintf(&ret, "%s/%s.save", driver->saveDir, vm->def->name) < 0) {
        virReportOOMError();
        return(NULL);
    }

    return(ret);
}

static int
qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *name = NULL;
    int ret = -1;
    int compressed;

2826 2827 2828
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
2829 2830 2831 2832 2833 2834 2835 2836

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
2837
        goto cleanup;
2838 2839
    }

2840 2841 2842 2843 2844
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }
2845 2846 2847 2848 2849
    if (!vm->persistent) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot do managed save for transient domain"));
        goto cleanup;
    }
2850

2851 2852
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
2853
        goto cleanup;
2854

2855
    VIR_INFO("Saving state to %s", name);
2856 2857

    compressed = QEMUD_SAVE_FORMAT_RAW;
2858
    ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
2859
                                 NULL, flags);
2860
    vm = NULL;
2861 2862 2863 2864 2865

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
2866 2867 2868
    VIR_FREE(name);

    return ret;
2869 2870 2871 2872 2873 2874 2875 2876 2877 2878
}

static int
qemuDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    char *name = NULL;

2879
    virCheckFlags(0, -1);
2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

    ret = virFileExists(name);

cleanup:
    VIR_FREE(name);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    char *name = NULL;

2913
    virCheckFlags(0, -1);
2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

    ret = unlink(name);

cleanup:
    VIR_FREE(name);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
D
Daniel P. Berrange 已提交
2938

2939 2940 2941 2942
static int
doCoreDump(struct qemud_driver *driver,
           virDomainObjPtr vm,
           const char *path,
2943 2944
           enum qemud_save_formats compress,
           bool bypass_cache)
H
Hu Tao 已提交
2945 2946 2947
{
    int fd = -1;
    int ret = -1;
J
Jiri Denemark 已提交
2948
    virFileWrapperFdPtr wrapperFd = NULL;
2949
    int directFlag = 0;
2950
    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
H
Hu Tao 已提交
2951 2952

    /* Create an empty file with appropriate ownership.  */
2953
    if (bypass_cache) {
2954
        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
2955 2956 2957 2958 2959 2960 2961
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("bypass cache unsupported by this system"));
            goto cleanup;
        }
    }
E
Eric Blake 已提交
2962 2963 2964 2965 2966 2967
    /* 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 已提交
2968 2969
        goto cleanup;

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

2973
    if (qemuMigrationToFile(driver, vm, fd, 0, path,
E
Eric Blake 已提交
2974
                            qemuCompressProgramName(compress), false,
2975
                            QEMU_ASYNC_JOB_DUMP) < 0)
2976 2977
        goto cleanup;

H
Hu Tao 已提交
2978 2979 2980 2981 2982 2983
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
                             _("unable to save file %s"),
                             path);
        goto cleanup;
    }
J
Jiri Denemark 已提交
2984
    if (virFileWrapperFdClose(wrapperFd) < 0)
2985
        goto cleanup;
H
Hu Tao 已提交
2986

2987
    ret = 0;
H
Hu Tao 已提交
2988 2989

cleanup:
2990
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
2991
    virFileWrapperFdFree(wrapperFd);
H
Hu Tao 已提交
2992 2993 2994 2995 2996
    if (ret != 0)
        unlink(path);
    return ret;
}

2997 2998 2999 3000 3001
static enum qemud_save_formats
getCompressionType(struct qemud_driver *driver)
{
    int compress = QEMUD_SAVE_FORMAT_RAW;

3002 3003 3004 3005 3006 3007
    /*
     * We reuse "save" flag for "dump" here. Then, we can support the same
     * format in "save" and "dump".
     */
    if (driver->dumpImageFormat) {
        compress = qemudSaveCompressionTypeFromString(driver->dumpImageFormat);
3008 3009 3010
        /* Use "raw" as the format if the specified format is not valid,
         * or the compress program is not available.
         */
3011
        if (compress < 0) {
3012 3013
            VIR_WARN("%s", _("Invalid dump image format specified in "
                             "configuration file, using raw"));
3014
            return QEMUD_SAVE_FORMAT_RAW;
3015
        }
3016
        if (!qemudCompressProgramAvailable(compress)) {
3017 3018 3019
            VIR_WARN("%s", _("Compression program for dump image format "
                             "in configuration file isn't available, "
                             "using raw"));
3020
            return QEMUD_SAVE_FORMAT_RAW;
3021
        }
3022
    }
3023 3024 3025 3026 3027
    return compress;
}

static int qemudDomainCoreDump(virDomainPtr dom,
                               const char *path,
3028
                               unsigned int flags)
3029
{
3030 3031
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
3032
    qemuDomainObjPrivatePtr priv;
3033
    int resume = 0, paused = 0;
H
Hu Tao 已提交
3034
    int ret = -1;
3035 3036
    virDomainEventPtr event = NULL;

M
Michal Privoznik 已提交
3037 3038
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH |
                  VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET, -1);
3039

P
Paolo Bonzini 已提交
3040 3041 3042 3043 3044 3045
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3046 3047
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
3048 3049 3050
        goto cleanup;
    }

3051 3052
    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_DUMP) < 0)
3053 3054
        goto cleanup;

D
Daniel P. Berrange 已提交
3055
    if (!virDomainObjIsActive(vm)) {
3056 3057
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
3058
        goto endjob;
P
Paolo Bonzini 已提交
3059 3060
    }

P
Paolo Bonzini 已提交
3061 3062
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
J
Jiri Denemark 已提交
3063
    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
3064 3065

    /* Pause domain for non-live dump */
J
Jiri Denemark 已提交
3066 3067
    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3068 3069
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP,
                                QEMU_ASYNC_JOB_DUMP) < 0)
3070
            goto endjob;
P
Paolo Bonzini 已提交
3071
        paused = 1;
3072 3073 3074 3075 3076 3077

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto endjob;
        }
P
Paolo Bonzini 已提交
3078 3079
    }

3080 3081
    ret = doCoreDump(driver, vm, path, getCompressionType(driver),
                     (flags & VIR_DUMP_BYPASS_CACHE) != 0);
3082 3083 3084 3085
    if (ret < 0)
        goto endjob;

    paused = 1;
3086 3087

endjob:
3088
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
J
Jiri Denemark 已提交
3089
        qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_CRASHED);
3090
        virDomainAuditStop(vm, "crashed");
3091 3092 3093 3094 3095
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
3096 3097 3098
    /* 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 已提交
3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110
    else if (((resume && paused) || (flags & VIR_DUMP_RESET)) &&
             virDomainObjIsActive(vm)) {
        if ((ret == 0) && (flags & VIR_DUMP_RESET)) {
            priv =  vm->privateData;
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            ret = qemuMonitorSystemReset(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
        }

        if (resume && qemuProcessStartCPUs(driver, vm, dom->conn,
                                           VIR_DOMAIN_RUNNING_UNPAUSED,
                                           QEMU_ASYNC_JOB_DUMP) < 0) {
3111
            if (virGetLastError() == NULL)
3112 3113
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3114 3115
        }
    }
3116

3117
    if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3118
        vm = NULL;
3119
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
3120
        qemuDomainRemoveInactive(driver, vm);
3121 3122
        vm = NULL;
    }
3123 3124

cleanup:
P
Paolo Bonzini 已提交
3125 3126
    if (vm)
        virDomainObjUnlock(vm);
3127 3128
    if (event)
        qemuDomainEventQueue(driver, event);
3129
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
3130 3131 3132
    return ret;
}

3133 3134 3135 3136
static char *
qemuDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
3137
                     unsigned int flags)
3138 3139 3140 3141 3142 3143 3144
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *tmp = NULL;
    int tmp_fd = -1;
    char *ret = NULL;
E
Eric Blake 已提交
3145
    bool unlink_tmp = false;
3146

E
Eric Blake 已提交
3147 3148
    virCheckFlags(0, NULL);

3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

    priv = vm->privateData;

3163
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189
        goto cleanup;

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

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

    if (virAsprintf(&tmp, "%s/qemu.screendump.XXXXXX", driver->cacheDir) < 0) {
        virReportOOMError();
        goto endjob;
    }

    if ((tmp_fd = mkstemp(tmp)) == -1) {
        virReportSystemError(errno, _("mkstemp(\"%s\") failed"), tmp);
        goto endjob;
    }
E
Eric Blake 已提交
3190
    unlink_tmp = true;
3191

3192
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
3193

3194
    qemuDomainObjEnterMonitor(driver, vm);
3195
    if (qemuMonitorScreendump(priv->mon, tmp) < 0) {
3196
        qemuDomainObjExitMonitor(driver, vm);
3197 3198
        goto endjob;
    }
3199
    qemuDomainObjExitMonitor(driver, vm);
3200 3201 3202 3203 3204 3205

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

E
Eric Blake 已提交
3206
    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
3207 3208 3209 3210 3211 3212 3213 3214 3215
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("unable to open stream"));
        goto endjob;
    }

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

endjob:
    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
3216 3217
    if (unlink_tmp)
        unlink(tmp);
E
Eric Blake 已提交
3218
    VIR_FREE(tmp);
3219

3220
    if (qemuDomainObjEndJob(driver, vm) == 0)
3221 3222 3223 3224 3225 3226 3227 3228
        vm = NULL;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

H
Hu Tao 已提交
3229 3230 3231
static void processWatchdogEvent(void *data, void *opaque)
{
    int ret;
3232
    struct qemuDomainWatchdogEvent *wdEvent = data;
H
Hu Tao 已提交
3233 3234
    struct qemud_driver *driver = opaque;

W
Wen Congyang 已提交
3235 3236 3237
    qemuDriverLock(driver);
    virDomainObjLock(wdEvent->vm);

H
Hu Tao 已提交
3238 3239 3240 3241 3242
    switch (wdEvent->action) {
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;

E
Eric Blake 已提交
3243
            if (virAsprintf(&dumpfile, "%s/%s-%u",
H
Hu Tao 已提交
3244 3245
                            driver->autoDumpPath,
                            wdEvent->vm->def->name,
E
Eric Blake 已提交
3246 3247
                            (unsigned int)time(NULL)) < 0) {
                virReportOOMError();
W
Wen Congyang 已提交
3248
                goto unlock;
E
Eric Blake 已提交
3249
            }
H
Hu Tao 已提交
3250

3251 3252
            if (qemuDomainObjBeginAsyncJobWithDriver(driver, wdEvent->vm,
                                                     QEMU_ASYNC_JOB_DUMP) < 0) {
W
Wen Congyang 已提交
3253 3254 3255
                VIR_FREE(dumpfile);
                goto unlock;
            }
H
Hu Tao 已提交
3256 3257 3258 3259

            if (!virDomainObjIsActive(wdEvent->vm)) {
                qemuReportError(VIR_ERR_OPERATION_INVALID,
                                "%s", _("domain is not running"));
W
Wen Congyang 已提交
3260 3261
                VIR_FREE(dumpfile);
                goto endjob;
H
Hu Tao 已提交
3262 3263
            }

3264
            ret = doCoreDump(driver, wdEvent->vm, dumpfile,
3265 3266
                             getCompressionType(driver),
                             driver->autoDumpBypassCache);
H
Hu Tao 已提交
3267 3268 3269 3270
            if (ret < 0)
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("Dump failed"));

J
Jiri Denemark 已提交
3271
            ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL,
3272 3273
                                       VIR_DOMAIN_RUNNING_UNPAUSED,
                                       QEMU_ASYNC_JOB_DUMP);
H
Hu Tao 已提交
3274 3275 3276 3277 3278 3279 3280 3281

            if (ret < 0)
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("Resuming after dump failed"));

            VIR_FREE(dumpfile);
        }
        break;
W
Wen Congyang 已提交
3282 3283
    default:
        goto unlock;
H
Hu Tao 已提交
3284 3285
    }

W
Wen Congyang 已提交
3286 3287 3288 3289
endjob:
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleWatchdog().
     */
3290
    ignore_value(qemuDomainObjEndAsyncJob(driver, wdEvent->vm));
W
Wen Congyang 已提交
3291 3292 3293 3294 3295

unlock:
    if (virDomainObjUnref(wdEvent->vm) > 0)
        virDomainObjUnlock(wdEvent->vm);
    qemuDriverUnlock(driver);
H
Hu Tao 已提交
3296 3297
    VIR_FREE(wdEvent);
}
P
Paolo Bonzini 已提交
3298

3299 3300 3301
static int qemudDomainHotplugVcpus(struct qemud_driver *driver,
                                   virDomainObjPtr vm,
                                   unsigned int nvcpus)
3302 3303
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3304
    int i, rc = 1;
3305
    int ret = -1;
3306
    int oldvcpus = vm->def->vcpus;
E
Eric Blake 已提交
3307
    int vcpus = oldvcpus;
3308

3309
    qemuDomainObjEnterMonitor(driver, vm);
3310

3311 3312 3313
    /* 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 已提交
3314 3315
    if (nvcpus > vcpus) {
        for (i = vcpus ; i < nvcpus ; i++) {
3316 3317 3318 3319 3320 3321 3322
            /* Online new CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3323
            vcpus++;
3324 3325
        }
    } else {
E
Eric Blake 已提交
3326
        for (i = vcpus - 1 ; i >= nvcpus ; i--) {
3327 3328 3329 3330 3331 3332 3333
            /* Offline old CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3334
            vcpus--;
3335 3336 3337 3338 3339 3340
        }
    }

    ret = 0;

cleanup:
3341
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
3342
    vm->def->vcpus = vcpus;
3343
    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
3344 3345 3346 3347 3348 3349 3350 3351 3352
    return ret;

unsupported:
    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("cannot change vcpu count of this domain"));
    goto cleanup;
}


3353
static int
3354 3355
qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3356
{
3357 3358
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3359
    virDomainDefPtr persistentDef;
3360 3361
    const char * type;
    int max;
3362
    int ret = -1;
3363
    bool maximum;
3364

3365 3366
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
3367 3368 3369 3370 3371
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("argument out of range: %d"), nvcpus);
3372 3373 3374
        return -1;
    }

3375
    qemuDriverLock(driver);
3376
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3377 3378
    qemuDriverUnlock(driver);

3379
    if (!vm) {
3380 3381
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3382 3383
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
3384
        goto cleanup;
3385 3386
    }

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

3390 3391 3392
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

3393 3394 3395
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto endjob;
3396 3397 3398 3399 3400 3401 3402 3403

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

3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
        goto endjob;
    }

    if ((max = qemudGetMaxVCPUs(NULL, type)) < 0) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("could not determine max vcpus for the domain"));
        goto endjob;
    }

3417
    if (!maximum && vm->def->maxvcpus < max) {
3418 3419 3420
        max = vm->def->maxvcpus;
    }

3421 3422 3423 3424 3425 3426 3427
    if (nvcpus > max) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("requested vcpus is greater than max allowable"
                          " vcpus for the domain: %d > %d"), nvcpus, max);
        goto endjob;
    }

3428
    switch (flags) {
3429
    case VIR_DOMAIN_AFFECT_CONFIG:
3430 3431 3432 3433 3434 3435 3436
        if (maximum) {
            persistentDef->maxvcpus = nvcpus;
            if (nvcpus < persistentDef->vcpus)
                persistentDef->vcpus = nvcpus;
        } else {
            persistentDef->vcpus = nvcpus;
        }
3437 3438 3439
        ret = 0;
        break;

3440
    case VIR_DOMAIN_AFFECT_LIVE:
3441
        ret = qemudDomainHotplugVcpus(driver, vm, nvcpus);
3442 3443
        break;

3444
    case VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG:
3445
        ret = qemudDomainHotplugVcpus(driver, vm, nvcpus);
3446 3447 3448
        if (ret == 0) {
            persistentDef->vcpus = nvcpus;
        }
3449 3450
        break;
    }
3451

3452
    /* Save the persistent config to disk */
3453
    if (flags & VIR_DOMAIN_AFFECT_CONFIG)
3454 3455
        ret = virDomainSaveConfig(driver->configDir, persistentDef);

3456
endjob:
3457
    if (qemuDomainObjEndJob(driver, vm) == 0)
3458
        vm = NULL;
3459

3460
cleanup:
3461 3462
    if (vm)
        virDomainObjUnlock(vm);
3463
    return ret;
3464 3465
}

3466
static int
3467
qemuDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3468
{
3469
    return qemuDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
3470 3471
}

3472 3473

static int
3474 3475 3476 3477 3478 3479
qemudDomainPinVcpuFlags(virDomainPtr dom,
                        unsigned int vcpu,
                        unsigned char *cpumap,
                        int maplen,
                        unsigned int flags) {

3480 3481
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3482
    virDomainDefPtr persistentDef = NULL;
3483
    int maxcpu, hostcpus;
3484
    virNodeInfo nodeinfo;
3485
    int ret = -1;
3486
    qemuDomainObjPrivatePtr priv;
3487
    bool canResetting = true;
E
Eric Blake 已提交
3488
    int pcpu;
3489

3490 3491 3492
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

3493
    qemuDriverLock(driver);
3494
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3495 3496
    qemuDriverUnlock(driver);

3497 3498 3499
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3500 3501
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
3502 3503 3504
        goto cleanup;
    }

3505 3506
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
3507
        goto cleanup;
3508

3509 3510 3511
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
3512 3513 3514
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("vcpu number out of range %d > %d"),
                        vcpu, priv->nvcpupids);
3515
        goto cleanup;
3516 3517
    }

3518 3519 3520 3521 3522 3523 3524 3525 3526
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
        goto cleanup;
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
E
Eric Blake 已提交
3527
    for (pcpu = 0; pcpu < hostcpus; pcpu++) {
3528 3529 3530 3531 3532
        if ((cpumap[pcpu/8] & (1 << (pcpu % 8))) == 0) {
            canResetting = false;
            break;
        }
    }
3533

3534
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3535 3536 3537 3538 3539 3540

        if (priv->vcpupids != NULL) {
            if (virProcessInfoSetAffinity(priv->vcpupids[vcpu],
                                          cpumap, maplen, maxcpu) < 0)
                goto cleanup;
        } else {
3541
            qemuReportError(VIR_ERR_OPERATION_INVALID,
3542 3543 3544 3545
                            "%s", _("cpu affinity is not supported"));
            goto cleanup;
        }

3546
        if (canResetting) {
E
Eric Blake 已提交
3547
            if (virDomainVcpuPinDel(vm->def, vcpu) < 0) {
3548 3549 3550 3551 3552 3553
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("failed to delete vcpupin xml of "
                                  "a running domain"));
                goto cleanup;
            }
        } else {
E
Eric Blake 已提交
3554
            if (virDomainVcpuPinAdd(vm->def, cpumap, maplen, vcpu) < 0) {
3555 3556 3557 3558 3559
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("failed to update or add vcpupin xml of "
                                  "a running domain"));
                goto cleanup;
            }
3560 3561
        }

3562 3563
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            goto cleanup;
3564
    }
3565

3566 3567
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

3568
        if (canResetting) {
E
Eric Blake 已提交
3569
            if (virDomainVcpuPinDel(persistentDef, vcpu) < 0) {
3570 3571 3572 3573 3574 3575
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("failed to delete vcpupin xml of "
                                  "a persistent domain"));
                goto cleanup;
            }
        } else {
E
Eric Blake 已提交
3576
            if (virDomainVcpuPinAdd(persistentDef, cpumap, maplen, vcpu) < 0) {
3577 3578 3579 3580 3581
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("failed to update or add vcpupin xml of "
                                  "a persistent domain"));
                goto cleanup;
            }
3582
        }
3583

3584
        ret = virDomainSaveConfig(driver->configDir, persistentDef);
3585 3586 3587
        goto cleanup;
    }

3588
    ret = 0;
3589

3590
cleanup:
3591 3592
    if (vm)
        virDomainObjUnlock(vm);
3593
    return ret;
3594 3595
}

3596 3597 3598 3599 3600 3601 3602 3603 3604
static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
    return qemudDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                   VIR_DOMAIN_AFFECT_LIVE);
}

3605
static int
E
Eric Blake 已提交
3606
qemudDomainGetVcpuPinInfo(virDomainPtr dom,
3607 3608 3609 3610 3611 3612
                          int ncpumaps,
                          unsigned char *cpumaps,
                          int maplen,
                          unsigned int flags) {

    struct qemud_driver *driver = dom->conn->privateData;
E
Eric Blake 已提交
3613
    virDomainObjPtr vm = NULL;
3614 3615 3616 3617 3618
    virNodeInfo nodeinfo;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, vcpu, pcpu;
    int n;
E
Eric Blake 已提交
3619
    virDomainVcpuPinDefPtr *vcpupin_list;
3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637
    char *cpumask = NULL;
    unsigned char *cpumap;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

3638 3639 3640
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &targetDef) < 0)
        goto cleanup;
3641 3642 3643 3644 3645

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

3646 3647 3648
    /* Coverity didn't realize that targetDef must be set if we got here.  */
    sa_assert(targetDef);

3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
        goto cleanup;
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    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++) {
            if (cpumask[pcpu] == 0)
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

3692 3693 3694 3695 3696 3697
static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
3698 3699
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3700
    virNodeInfo nodeinfo;
3701
    int i, v, maxcpu, hostcpus;
3702
    int ret = -1;
3703
    qemuDomainObjPrivatePtr priv;
3704

3705
    qemuDriverLock(driver);
3706
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3707 3708
    qemuDriverUnlock(driver);

3709 3710 3711
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3712 3713
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
3714 3715 3716
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
3717
    if (!virDomainObjIsActive(vm)) {
3718 3719 3720
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",
                        _("cannot list vcpu pinning for an inactive domain"));
3721
        goto cleanup;
3722 3723
    }

3724 3725
    priv = vm->privateData;

3726
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
3727
        goto cleanup;
3728

3729
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
3730
    maxcpu = maplen * 8;
3731 3732
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
3733 3734

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

3738 3739 3740 3741 3742 3743
    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;
3744

3745
                if (priv->vcpupids != NULL &&
3746 3747
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
3748
                                        NULL,
3749
                                        vm->pid,
3750
                                        priv->vcpupids[i]) < 0) {
3751
                    virReportSystemError(errno, "%s",
3752 3753 3754
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
3755
            }
3756 3757
        }

3758 3759
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
3760
            if (priv->vcpupids != NULL) {
3761 3762 3763
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);

3764
                    if (virProcessInfoGetAffinity(priv->vcpupids[v],
3765
                                                  cpumap, maplen, maxcpu) < 0)
3766
                        goto cleanup;
3767
                }
3768
            } else {
3769
                qemuReportError(VIR_ERR_OPERATION_INVALID,
3770
                                "%s", _("cpu affinity is not available"));
3771
                goto cleanup;
3772 3773 3774
            }
        }
    }
3775
    ret = maxinfo;
3776

3777
cleanup:
3778 3779
    if (vm)
        virDomainObjUnlock(vm);
3780
    return ret;
3781 3782 3783
}


3784 3785 3786
static int
qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
3787 3788
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3789
    virDomainDefPtr def;
3790
    int ret = -1;
3791

3792 3793
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
3794 3795
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

3796
    qemuDriverLock(driver);
3797
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3798 3799
    qemuDriverUnlock(driver);

3800
    if (!vm) {
3801 3802
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3803 3804
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
3805
        goto cleanup;
3806 3807
    }

3808 3809
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &def) < 0)
        goto cleanup;
3810

3811
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3812
        def = vm->def;
3813 3814
    }

3815
    ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
3816

3817
cleanup:
3818 3819
    if (vm)
        virDomainObjUnlock(vm);
3820 3821 3822
    return ret;
}

3823 3824 3825
static int
qemudDomainGetMaxVcpus(virDomainPtr dom)
{
3826
    return qemudDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
3827 3828 3829
                                          VIR_DOMAIN_VCPU_MAXIMUM));
}

3830 3831 3832 3833 3834 3835 3836 3837 3838
static int qemudDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

3839 3840
    memset(seclabel, 0, sizeof(*seclabel));

3841 3842 3843
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3844 3845
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
3846 3847 3848
        goto cleanup;
    }

3849
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
3850 3851 3852
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869
        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 已提交
3870
    if (virDomainObjIsActive(vm)) {
3871
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
3872
                                              vm->def, vm->pid, seclabel) < 0) {
3873 3874 3875
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Failed to get security label"));
            goto cleanup;
3876 3877 3878 3879 3880 3881 3882 3883
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
3884
    qemuDriverUnlock(driver);
3885 3886 3887
    return ret;
}

3888 3889
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
3890 3891 3892
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
3893
    int ret = 0;
3894

3895
    qemuDriverLock(driver);
3896 3897 3898 3899 3900
    memset(secmodel, 0, sizeof(*secmodel));

    /* NULL indicates no driver, which we treat as
     * success, but simply return no data in *secmodel */
    if (driver->caps->host.secModel.model == NULL)
3901
        goto cleanup;
3902

3903 3904
    p = driver->caps->host.secModel.model;
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
3905 3906 3907
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security model string exceeds max %d bytes"),
                        VIR_SECURITY_MODEL_BUFLEN-1);
3908 3909
        ret = -1;
        goto cleanup;
3910 3911 3912 3913 3914
    }
    strcpy(secmodel->model, p);

    p = driver->caps->host.secModel.doi;
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
3915 3916 3917
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security DOI string exceeds max %d bytes"),
                        VIR_SECURITY_DOI_BUFLEN-1);
3918 3919
        ret = -1;
        goto cleanup;
3920 3921
    }
    strcpy(secmodel->doi, p);
3922 3923 3924 3925

cleanup:
    qemuDriverUnlock(driver);
    return ret;
3926 3927
}

E
Eric Blake 已提交
3928
/* Return -1 on most failures after raising error, -2 if edit was specified
3929 3930 3931
 * 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.  */
3932
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
3933 3934 3935
qemuDomainSaveImageOpen(struct qemud_driver *driver,
                        const char *path,
                        virDomainDefPtr *ret_def,
3936
                        struct qemud_save_header *ret_header,
J
Jiri Denemark 已提交
3937 3938
                        bool bypass_cache,
                        virFileWrapperFdPtr *wrapperFd,
3939 3940
                        const char *xmlin, int state, bool edit,
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
3941 3942
{
    int fd;
3943
    struct qemud_save_header header;
J
Jiri Denemark 已提交
3944 3945
    char *xml = NULL;
    virDomainDefPtr def = NULL;
3946
    int oflags = edit ? O_RDWR : O_RDONLY;
3947

3948
    if (bypass_cache) {
3949
        int directFlag = virFileDirectFdFlag();
3950 3951 3952 3953 3954
        if (directFlag < 0) {
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("bypass cache unsupported by this system"));
            goto error;
        }
3955
        oflags |= directFlag;
3956
    }
3957

E
Eric Blake 已提交
3958 3959
    if ((fd = qemuOpenFile(driver, path, oflags, NULL, NULL)) < 0)
        goto error;
J
Jiri Denemark 已提交
3960 3961 3962
    if (bypass_cache &&
        !(*wrapperFd = virFileWrapperFdNew(&fd, path,
                                           VIR_FILE_WRAPPER_BYPASS_CACHE)))
3963
        goto error;
3964 3965

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
3966 3967 3968 3969 3970 3971 3972 3973 3974
        if (unlink_corrupt) {
            if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove corrupt file: %s"),
                                     path);
                goto error;
            }
            return -3;
        }
3975 3976
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
3977
        goto error;
3978 3979 3980
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
E
Eric Blake 已提交
3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996
        const char *msg = _("image magic is incorrect");

        if (memcmp(header.magic, QEMUD_SAVE_PARTIAL,
                   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;
            }
        }
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", msg);
J
Jiri Denemark 已提交
3997
        goto error;
3998 3999 4000
    }

    if (header.version > QEMUD_SAVE_VERSION) {
4001 4002 4003 4004 4005
        /* convert endianess and try again */
        bswap_header(&header);
    }

    if (header.version > QEMUD_SAVE_VERSION) {
4006 4007 4008
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("image version is not supported (%d > %d)"),
                        header.version, QEMUD_SAVE_VERSION);
J
Jiri Denemark 已提交
4009
        goto error;
4010 4011
    }

4012 4013 4014
    if (header.xml_len <= 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
4015
        goto error;
4016 4017
    }

4018 4019
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
J
Jiri Denemark 已提交
4020
        goto error;
4021 4022 4023
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
4024 4025
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
4026
        goto error;
4027 4028
    }

4029 4030
    if (edit && STREQ(xml, xmlin) &&
        (state < 0 || state == header.was_running)) {
4031 4032 4033 4034 4035 4036 4037
        VIR_FREE(xml);
        if (VIR_CLOSE(fd) < 0) {
            virReportSystemError(errno, _("cannot close file: %s"), path);
            goto error;
        }
        return -2;
    }
4038 4039
    if (state >= 0)
        header.was_running = state;
4040

4041
    /* Create a domain from this XML */
4042
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
4043
                                        QEMU_EXPECTED_VIRT_TYPES,
4044
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
4045
        goto error;
4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059
    if (xmlin) {
        virDomainDefPtr def2 = NULL;

        if (!(def2 = virDomainDefParseString(driver->caps, xmlin,
                                             QEMU_EXPECTED_VIRT_TYPES,
                                             VIR_DOMAIN_XML_INACTIVE)))
            goto error;
        if (!virDomainDefCheckABIStability(def, def2)) {
            virDomainDefFree(def2);
            goto error;
        }
        virDomainDefFree(def);
        def = def2;
    }
4060

J
Jiri Denemark 已提交
4061
    VIR_FREE(xml);
4062

J
Jiri Denemark 已提交
4063 4064
    *ret_def = def;
    *ret_header = header;
4065

J
Jiri Denemark 已提交
4066
    return fd;
4067

J
Jiri Denemark 已提交
4068 4069 4070
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
4071
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
4072 4073 4074 4075

    return -1;
}

4076 4077 4078 4079 4080 4081
static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6)
qemuDomainSaveImageStartVM(virConnectPtr conn,
                           struct qemud_driver *driver,
                           virDomainObjPtr vm,
                           int *fd,
                           const struct qemud_save_header *header,
4082 4083
                           const char *path,
                           bool start_paused)
J
Jiri Denemark 已提交
4084 4085 4086 4087
{
    int ret = -1;
    virDomainEventPtr event;
    int intermediatefd = -1;
4088
    virCommandPtr cmd = NULL;
J
Jiri Denemark 已提交
4089 4090 4091

    if (header->version == 2) {
        const char *prog = qemudSaveCompressionTypeToString(header->compressed);
4092
        if (prog == NULL) {
4093 4094
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("Invalid compressed save format %d"),
J
Jiri Denemark 已提交
4095 4096
                            header->compressed);
            goto out;
4097
        }
4098

J
Jiri Denemark 已提交
4099
        if (header->compressed != QEMUD_SAVE_FORMAT_RAW) {
4100
            cmd = virCommandNewArgList(prog, "-dc", NULL);
4101 4102
            intermediatefd = *fd;
            *fd = -1;
4103 4104 4105 4106 4107

            virCommandSetInputFD(cmd, intermediatefd);
            virCommandSetOutputFD(cmd, fd);

            if (virCommandRunAsync(cmd, NULL) < 0) {
4108 4109
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Failed to start decompression binary %s"),
4110
                                prog);
4111
                *fd = intermediatefd;
J
Jiri Denemark 已提交
4112
                goto out;
4113 4114 4115
            }
        }
    }
J
Jiri Denemark 已提交
4116

4117
    /* Set the migration source and start it up. */
4118 4119 4120
    ret = qemuProcessStart(conn, driver, vm, "stdio", false, true,
                           false, *fd, path, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_RESTORE);
J
Jiri Denemark 已提交
4121

4122
    if (intermediatefd != -1) {
4123
        if (ret < 0) {
4124 4125 4126
            /* if there was an error setting up qemu, the intermediate
             * process will wait forever to write to stdout, so we
             * must manually kill it.
4127 4128
             */
            VIR_FORCE_CLOSE(intermediatefd);
4129
            VIR_FORCE_CLOSE(*fd);
4130 4131
        }

4132 4133
        if (virCommandWait(cmd, NULL) < 0)
            ret = -1;
4134
    }
4135
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
4136

4137 4138 4139
    if (VIR_CLOSE(*fd) < 0) {
        virReportSystemError(errno, _("cannot close file: %s"), path);
        ret = -1;
4140
    }
J
Jiri Denemark 已提交
4141

4142
    if (ret < 0) {
4143
        virDomainAuditStart(vm, "restored", false);
J
Jiri Denemark 已提交
4144
        goto out;
4145
    }
4146

4147 4148 4149
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
4150
    virDomainAuditStart(vm, "restored", true);
J
Jiri Denemark 已提交
4151 4152 4153
    if (event)
        qemuDomainEventQueue(driver, event);

4154

4155 4156
    /* If it was running before, resume it now unless caller requested pause. */
    if (header->was_running && !start_paused) {
J
Jiri Denemark 已提交
4157
        if (qemuProcessStartCPUs(driver, vm, conn,
4158 4159
                                 VIR_DOMAIN_RUNNING_RESTORED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
4160
            if (virGetLastError() == NULL)
4161 4162
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("failed to resume domain"));
J
Jiri Denemark 已提交
4163
            goto out;
4164
        }
4165 4166
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
J
Jiri Denemark 已提交
4167
            goto out;
4168
        }
4169 4170 4171 4172 4173 4174 4175 4176
    } 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);
4177
    }
J
Jiri Denemark 已提交
4178

4179
    ret = 0;
4180

J
Jiri Denemark 已提交
4181
out:
4182
    virCommandFree(cmd);
4183
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
4184
                                                 vm->def, path) < 0)
4185 4186
        VIR_WARN("failed to restore save state label on %s", path);

J
Jiri Denemark 已提交
4187 4188 4189
    return ret;
}

4190
static int
4191 4192 4193 4194
qemuDomainRestoreFlags(virConnectPtr conn,
                       const char *path,
                       const char *dxml,
                       unsigned int flags)
4195
{
J
Jiri Denemark 已提交
4196 4197 4198 4199 4200 4201
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    int ret = -1;
    struct qemud_save_header header;
J
Jiri Denemark 已提交
4202
    virFileWrapperFdPtr wrapperFd = NULL;
4203
    int state = -1;
J
Jiri Denemark 已提交
4204

4205 4206 4207
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
4208

J
Jiri Denemark 已提交
4209 4210
    qemuDriverLock(driver);

4211 4212 4213 4214 4215
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

4216 4217
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
J
Jiri Denemark 已提交
4218
                                 &wrapperFd, dxml, state, false, false);
J
Jiri Denemark 已提交
4219 4220 4221 4222 4223 4224 4225 4226 4227
    if (fd < 0)
        goto cleanup;

    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, true))) {
4228
        /* virDomainAssignDef already set the error */
J
Jiri Denemark 已提交
4229 4230 4231 4232
        goto cleanup;
    }
    def = NULL;

4233
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
4234 4235
        goto cleanup;

4236 4237
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     false);
J
Jiri Denemark 已提交
4238
    if (virFileWrapperFdClose(wrapperFd) < 0)
4239
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
4240

4241
    if (qemuDomainObjEndJob(driver, vm) == 0)
4242
        vm = NULL;
J
Jiri Denemark 已提交
4243
    else if (ret < 0 && !vm->persistent) {
4244
        qemuDomainRemoveInactive(driver, vm);
J
Jiri Denemark 已提交
4245 4246
        vm = NULL;
    }
4247

4248 4249
cleanup:
    virDomainDefFree(def);
4250
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
4251
    virFileWrapperFdFree(wrapperFd);
4252 4253 4254
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
4255
    return ret;
D
Daniel P. Berrange 已提交
4256 4257
}

4258 4259 4260 4261 4262 4263 4264
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280
static char *
qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
                              unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
    char *ret = NULL;
    virDomainDefPtr def = NULL;
    int fd = -1;
    struct qemud_save_header header;

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

    qemuDriverLock(driver);

    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
4281
                                 NULL, -1, false, false);
4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305

    if (fd < 0)
        goto cleanup;

    ret = qemuDomainDefFormatXML(driver, def, flags);

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

static int
qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
                             const char *dxml, unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;
    virDomainDefPtr def = NULL;
    int fd = -1;
    struct qemud_save_header header;
    char *xml = NULL;
    size_t len;
4306
    int state = -1;
4307

4308 4309
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
4310 4311 4312

    qemuDriverLock(driver);

4313 4314 4315 4316 4317
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

4318
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
4319
                                 dxml, state, true, false);
4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343

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

    xml = qemuDomainDefFormatXML(driver, def, (VIR_DOMAIN_XML_INACTIVE |
                                               VIR_DOMAIN_XML_SECURE));
    if (!xml)
        goto cleanup;
    len = strlen(xml) + 1;

    if (len > header.xml_len) {
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("new xml too large to fit in file"));
        goto cleanup;
    }
    if (VIR_EXPAND_N(xml, len, header.xml_len - len) < 0) {
        virReportOOMError();
        goto cleanup;
    }

4344
    if (lseek(fd, 0, SEEK_SET) != 0) {
4345 4346 4347
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
4348 4349
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364
        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);
    qemuDriverUnlock(driver);
    return ret;
}

E
Eric Blake 已提交
4365 4366
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
4367 4368 4369 4370
static int
qemuDomainObjRestore(virConnectPtr conn,
                     struct qemud_driver *driver,
                     virDomainObjPtr vm,
4371
                     const char *path,
4372
                     bool start_paused,
4373
                     bool bypass_cache)
J
Jiri Denemark 已提交
4374 4375 4376 4377 4378
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    int ret = -1;
    struct qemud_save_header header;
J
Jiri Denemark 已提交
4379
    virFileWrapperFdPtr wrapperFd = NULL;
J
Jiri Denemark 已提交
4380

4381
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
J
Jiri Denemark 已提交
4382
                                 bypass_cache, &wrapperFd, NULL, -1, false,
4383
                                 true);
E
Eric Blake 已提交
4384 4385 4386
    if (fd < 0) {
        if (fd == -3)
            ret = 1;
J
Jiri Denemark 已提交
4387
        goto cleanup;
E
Eric Blake 已提交
4388
    }
J
Jiri Denemark 已提交
4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406

    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);
        qemuReportError(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);
        goto cleanup;
    }

    virDomainObjAssignDef(vm, def, true);
    def = NULL;

4407 4408
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     start_paused);
J
Jiri Denemark 已提交
4409
    if (virFileWrapperFdClose(wrapperFd) < 0)
4410
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
4411 4412 4413

cleanup:
    virDomainDefFree(def);
4414
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
4415
    virFileWrapperFdFree(wrapperFd);
J
Jiri Denemark 已提交
4416 4417 4418
    return ret;
}

D
Daniel P. Berrange 已提交
4419

4420
static char *qemuDomainGetXMLDesc(virDomainPtr dom,
4421 4422
                                  unsigned int flags)
{
4423 4424 4425
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
4426
    unsigned long long balloon;
4427
    int err = 0;
4428

4429
    /* Flags checked by virDomainDefFormat */
4430

4431
    qemuDriverLock(driver);
4432
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4433

D
Daniel P. Berrange 已提交
4434
    if (!vm) {
4435 4436
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4437 4438
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4439
        goto cleanup;
D
Daniel P. Berrange 已提交
4440 4441
    }

4442 4443 4444 4445
    /* Refresh current memory based on balloon info if supported */
    if ((vm->def->memballoon != NULL) &&
        (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
        (virDomainObjIsActive(vm))) {
4446
        qemuDomainObjPrivatePtr priv = vm->privateData;
4447 4448
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
4449
        if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
4450
            if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_QUERY) < 0)
4451 4452
                goto cleanup;

4453 4454 4455 4456 4457 4458
            if (!virDomainObjIsActive(vm)) {
                qemuReportError(VIR_ERR_OPERATION_INVALID,
                                "%s", _("domain is not running"));
                goto endjob;
            }

4459
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
4460
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
4461
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4462 4463

endjob:
4464
            if (qemuDomainObjEndJob(driver, vm) == 0) {
4465 4466 4467
                vm = NULL;
                goto cleanup;
            }
4468 4469 4470
            if (err < 0)
                goto cleanup;
            if (err > 0)
4471
                vm->def->mem.cur_balloon = balloon;
4472 4473
            /* err == 0 indicates no balloon support, so ignore it */
        }
4474
    }
4475

4476
    ret = qemuDomainFormatXML(driver, vm, flags);
4477 4478

cleanup:
4479 4480
    if (vm)
        virDomainObjUnlock(vm);
4481
    qemuDriverUnlock(driver);
4482
    return ret;
D
Daniel P. Berrange 已提交
4483 4484 4485
}


4486 4487 4488
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
E
Eric Blake 已提交
4489 4490
                                     unsigned int flags)
{
4491
    struct qemud_driver *driver = conn->privateData;
4492 4493 4494
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
4495 4496
    virCheckFlags(0, NULL);

4497
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
4498 4499
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
4500 4501 4502
        goto cleanup;
    }

4503
    qemuDriverLock(driver);
4504 4505
    def = qemuParseCommandLineString(driver->caps, config,
                                     NULL, NULL, NULL);
4506
    qemuDriverUnlock(driver);
4507 4508 4509
    if (!def)
        goto cleanup;

4510 4511 4512 4513 4514 4515
    if (!def->name &&
        !(def->name = strdup("unnamed"))) {
        virReportOOMError();
        goto cleanup;
    }

4516
    xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
4517 4518 4519 4520 4521 4522

cleanup:
    virDomainDefFree(def);
    return xml;
}

4523 4524 4525
static char *qemuDomainXMLToNative(virConnectPtr conn,
                                   const char *format,
                                   const char *xmlData,
E
Eric Blake 已提交
4526 4527
                                   unsigned int flags)
{
4528 4529
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
4530
    virDomainChrSourceDef monConfig;
4531
    virBitmapPtr qemuCaps = NULL;
T
tangchen 已提交
4532
    bool monitor_json = false;
E
Eric Blake 已提交
4533
    virCommandPtr cmd = NULL;
4534 4535 4536
    char *ret = NULL;
    int i;

E
Eric Blake 已提交
4537 4538
    virCheckFlags(0, NULL);

4539 4540
    qemuDriverLock(driver);

4541
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
4542 4543
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
4544 4545 4546
        goto cleanup;
    }

M
Matthias Bolte 已提交
4547 4548
    def = virDomainDefParseString(driver->caps, xmlData,
                                  QEMU_EXPECTED_VIRT_TYPES, 0);
4549 4550 4551
    if (!def)
        goto cleanup;

4552 4553
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
4554 4555 4556 4557 4558
     * 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];
4559
        int bootIndex = net->info.bootIndex;
4560 4561 4562 4563
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

4564
            VIR_FREE(net->data.network.name);
4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579
            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);

                memset(net, 0, sizeof *net);

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
4580
                net->script = NULL;
4581 4582 4583 4584 4585 4586 4587 4588 4589 4590
                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);
                memset(net, 0, sizeof *net);

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
4591
                net->script = NULL;
4592 4593 4594 4595 4596 4597
                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);
            VIR_FREE(net->data.direct.virtPortProfile);
4598 4599 4600 4601

            memset(net, 0, sizeof *net);

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
4602
            net->script = NULL;
4603 4604 4605
            net->data.ethernet.dev = NULL;
            net->data.ethernet.ipaddr = NULL;
        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
4606
            char *script = net->script;
4607 4608 4609 4610 4611 4612
            char *brname = net->data.bridge.brname;
            char *ipaddr = net->data.bridge.ipaddr;

            memset(net, 0, sizeof *net);

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
4613
            net->script = script;
4614 4615 4616
            net->data.ethernet.dev = brname;
            net->data.ethernet.ipaddr = ipaddr;
        }
4617
        net->info.bootIndex = bootIndex;
4618 4619 4620 4621
    }
    for (i = 0 ; i < def->ngraphics ; i++) {
        if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
            def->graphics[i]->data.vnc.autoport)
4622
            def->graphics[i]->data.vnc.port = QEMU_VNC_PORT_MIN;
4623 4624
    }

4625
    if (qemuCapsExtractVersionInfo(def->emulator, def->os.arch,
4626
                                   NULL,
4627
                                   &qemuCaps) < 0)
4628 4629
        goto cleanup;

T
tangchen 已提交
4630 4631
    monitor_json = qemuCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON);

4632
    if (qemuProcessPrepareMonitorChr(driver, &monConfig, def->name) < 0)
4633
        goto cleanup;
4634

4635 4636 4637
    if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
        goto cleanup;

4638
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
T
tangchen 已提交
4639
                                     &monConfig, monitor_json, qemuCaps,
4640
                                     NULL, -1, NULL, VIR_NETDEV_VPORT_PROFILE_OP_NO_OP)))
4641 4642
        goto cleanup;

E
Eric Blake 已提交
4643
    ret = virCommandToString(cmd);
4644 4645

cleanup:
4646
    qemuDriverUnlock(driver);
4647

4648
    qemuCapsFree(qemuCaps);
E
Eric Blake 已提交
4649
    virCommandFree(cmd);
4650 4651 4652 4653 4654
    virDomainDefFree(def);
    return ret;
}


4655
static int qemudListDefinedDomains(virConnectPtr conn,
4656
                            char **const names, int nnames) {
4657
    struct qemud_driver *driver = conn->privateData;
4658
    int n;
4659

4660
    qemuDriverLock(driver);
4661
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
4662
    qemuDriverUnlock(driver);
4663
    return n;
D
Daniel P. Berrange 已提交
4664 4665
}

4666
static int qemudNumDefinedDomains(virConnectPtr conn) {
4667
    struct qemud_driver *driver = conn->privateData;
4668
    int n;
4669

4670
    qemuDriverLock(driver);
4671
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
4672
    qemuDriverUnlock(driver);
4673

4674
    return n;
D
Daniel P. Berrange 已提交
4675 4676 4677
}


4678 4679 4680 4681
static int
qemuDomainObjStart(virConnectPtr conn,
                   struct qemud_driver *driver,
                   virDomainObjPtr vm,
4682
                   unsigned int flags)
J
Jiri Denemark 已提交
4683 4684 4685
{
    int ret = -1;
    char *managed_save;
4686 4687 4688 4689
    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;
J
Jiri Denemark 已提交
4690 4691 4692

    /*
     * If there is a managed saved state restore it instead of starting
4693
     * from scratch. The old state is removed once the restoring succeeded.
J
Jiri Denemark 已提交
4694 4695
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
4696 4697 4698 4699

    if (!managed_save)
        goto cleanup;

E
Eric Blake 已提交
4700
    if (virFileExists(managed_save)) {
4701 4702 4703 4704 4705 4706 4707 4708 4709
        if (force_boot) {
            if (unlink(managed_save) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove managed save file %s"),
                                     managed_save);
                goto cleanup;
            }
        } else {
            ret = qemuDomainObjRestore(conn, driver, vm, managed_save,
4710
                                       start_paused, bypass_cache);
J
Jiri Denemark 已提交
4711

E
Eric Blake 已提交
4712
            if (ret == 0 && unlink(managed_save) < 0)
4713
                VIR_WARN("Failed to remove the managed state %s", managed_save);
E
Eric Blake 已提交
4714 4715 4716 4717
            if (ret > 0)
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
            else
                goto cleanup;
4718
        }
J
Jiri Denemark 已提交
4719 4720
    }

4721 4722 4723
    ret = qemuProcessStart(conn, driver, vm, NULL, true, start_paused,
                           autodestroy, -1, NULL, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_CREATE);
4724
    virDomainAuditStart(vm, "booted", ret >= 0);
4725
    if (ret >= 0) {
J
Jiri Denemark 已提交
4726 4727 4728 4729
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
4730
        if (event) {
J
Jiri Denemark 已提交
4731
            qemuDomainEventQueue(driver, event);
4732 4733 4734 4735 4736 4737 4738 4739
            if (start_paused) {
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
                if (event)
                    qemuDomainEventQueue(driver, event);
            }
        }
J
Jiri Denemark 已提交
4740 4741 4742 4743 4744 4745 4746
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

4747
static int
4748
qemuDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
4749
{
4750 4751 4752
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4753

4754
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
4755
                  VIR_DOMAIN_START_AUTODESTROY |
4756 4757
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
4758

4759
    qemuDriverLock(driver);
4760
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4761

4762
    if (!vm) {
4763 4764
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4765 4766
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4767
        goto cleanup;
4768 4769
    }

4770
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
4771 4772 4773
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
4774 4775
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is already running"));
4776 4777 4778
        goto endjob;
    }

4779
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
4780 4781 4782
        goto endjob;

    ret = 0;
4783

4784
endjob:
4785
    if (qemuDomainObjEndJob(driver, vm) == 0)
4786
        vm = NULL;
4787

4788
cleanup:
4789 4790
    if (vm)
        virDomainObjUnlock(vm);
4791
    qemuDriverUnlock(driver);
4792
    return ret;
D
Daniel P. Berrange 已提交
4793 4794
}

4795
static int
4796
qemuDomainStart(virDomainPtr dom)
4797
{
4798
    return qemuDomainStartWithFlags(dom, 0);
4799 4800
}

4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815
static int
qemudCanonicalizeMachineFromInfo(virDomainDefPtr def,
                                 virCapsGuestDomainInfoPtr info,
                                 char **canonical)
{
    int i;

    *canonical = NULL;

    for (i = 0; i < info->nmachines; i++) {
        virCapsGuestMachinePtr machine = info->machines[i];

        if (!machine->canonical)
            continue;

4816
        if (def->os.machine && STRNEQ(def->os.machine, machine->name))
4817 4818 4819
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
4820
            virReportOOMError();
4821 4822 4823 4824 4825 4826 4827 4828 4829
            return -1;
        }

        break;
    }

    return 0;
}

4830 4831 4832 4833 4834 4835
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
    int i, nmachines = 0;

4836
    if (qemuCapsProbeMachineTypes(def->emulator, &machines, &nmachines) < 0)
4837 4838 4839 4840 4841 4842
        return -1;

    for (i = 0; i < nmachines; i++) {
        if (!machines[i]->canonical)
            continue;

4843
        if (def->os.machine && STRNEQ(def->os.machine, machines[i]->name))
4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855
            continue;

        *canonical = machines[i]->canonical;
        machines[i]->canonical = NULL;
        break;
    }

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

4856 4857
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
4858 4859 4860 4861 4862 4863
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
4864
        virCapsGuestDomainInfoPtr info;
4865 4866 4867
        int j;

        for (j = 0; j < guest->arch.ndomains; j++) {
4868
            info = &guest->arch.domains[j]->info;
4869

4870 4871 4872 4873 4874 4875 4876 4877 4878
            if (!info->emulator || !STREQ(info->emulator, def->emulator))
                continue;

            if (!info->nmachines)
                info = &guest->arch.defaultInfo;

            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
                return -1;
            goto out;
4879 4880
        }

4881 4882 4883 4884
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
4885 4886 4887 4888
                return -1;
            goto out;
        }
    }
4889 4890 4891 4892

    if (qemudCanonicalizeMachineDirect(def, &canonical) < 0)
        return -1;

4893 4894 4895 4896 4897 4898 4899
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
4900

4901
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
4902
    struct qemud_driver *driver = conn->privateData;
4903
    virDomainDefPtr def;
4904
    virDomainObjPtr vm = NULL;
4905
    virDomainPtr dom = NULL;
4906
    virDomainEventPtr event = NULL;
4907
    int dupVM;
4908

4909
    qemuDriverLock(driver);
4910
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
4911
                                        QEMU_EXPECTED_VIRT_TYPES,
4912
                                        VIR_DOMAIN_XML_INACTIVE)))
4913
        goto cleanup;
4914

4915
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
4916 4917
        goto cleanup;

4918 4919
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
4920

4921
    if (qemudCanonicalizeMachine(driver, def) < 0)
4922 4923
        goto cleanup;

4924
    if (qemuDomainAssignAddresses(def) < 0)
4925 4926
        goto cleanup;

4927
    if (!(vm = virDomainAssignDef(driver->caps,
4928
                                  &driver->domains,
4929
                                  def, false))) {
4930
        goto cleanup;
4931
    }
4932
    def = NULL;
4933
    vm->persistent = 1;
4934

4935
    if (virDomainSaveConfig(driver->configDir,
4936
                            vm->newDef ? vm->newDef : vm->def) < 0) {
4937
        VIR_INFO("Defining domain '%s'", vm->def->name);
4938
        qemuDomainRemoveInactive(driver, vm);
4939
        vm = NULL;
4940
        goto cleanup;
4941 4942
    }

4943 4944
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
4945
                                     !dupVM ?
4946 4947
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
4948

4949
    VIR_INFO("Creating domain '%s'", vm->def->name);
4950
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4951
    if (dom) dom->id = vm->def->id;
4952 4953

cleanup:
4954
    virDomainDefFree(def);
4955 4956
    if (vm)
        virDomainObjUnlock(vm);
4957 4958
    if (event)
        qemuDomainEventQueue(driver, event);
4959
    qemuDriverUnlock(driver);
4960
    return dom;
D
Daniel P. Berrange 已提交
4961 4962
}

4963 4964
static int
qemuDomainUndefineFlags(virDomainPtr dom,
4965
                        unsigned int flags)
4966
{
4967 4968
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4969
    virDomainEventPtr event = NULL;
4970
    char *name = NULL;
4971
    int ret = -1;
4972
    int nsnapshots;
D
Daniel P. Berrange 已提交
4973

4974 4975
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
4976

4977
    qemuDriverLock(driver);
4978
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4979

D
Daniel P. Berrange 已提交
4980
    if (!vm) {
4981 4982
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4983 4984
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4985
        goto cleanup;
D
Daniel P. Berrange 已提交
4986 4987
    }

4988 4989 4990 4991 4992 4993
    if (!vm->persistent) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot undefine transient domain"));
        goto cleanup;
    }

4994 4995
    if (!virDomainObjIsActive(vm) &&
        (nsnapshots = virDomainSnapshotObjListNum(&vm->snapshots, 0))) {
4996
        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
4997 4998 4999 5000 5001 5002
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            _("cannot delete inactive domain with %d "
                              "snapshots"),
                            nsnapshots);
            goto cleanup;
        }
5003
        if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0)
5004
            goto cleanup;
5005 5006
    }

5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("Failed to remove domain managed "
                                  "save image"));
                goto cleanup;
            }
        } else {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("Refusing to undefine while domain managed "
                              "save image exists"));
            goto cleanup;
        }
    }

5027
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
5028
        goto cleanup;
D
Daniel P. Berrange 已提交
5029

5030 5031 5032
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
5033

5034
    VIR_INFO("Undefining domain '%s'", vm->def->name);
5035 5036 5037 5038 5039 5040 5041 5042

    /* 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 {
5043
        qemuDomainRemoveInactive(driver, vm);
5044 5045 5046
        vm = NULL;
    }

5047
    ret = 0;
D
Daniel P. Berrange 已提交
5048

5049
cleanup:
5050
    VIR_FREE(name);
5051 5052
    if (vm)
        virDomainObjUnlock(vm);
5053 5054
    if (event)
        qemuDomainEventQueue(driver, event);
5055
    qemuDriverUnlock(driver);
5056
    return ret;
D
Daniel P. Berrange 已提交
5057 5058
}

5059 5060 5061 5062 5063 5064
static int
qemudDomainUndefine(virDomainPtr dom)
{
    return qemuDomainUndefineFlags(dom, 0);
}

5065
static int
5066 5067
qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
                               struct qemud_driver *driver,
5068
                               virDomainObjPtr vm,
5069
                               virDomainDeviceDefPtr dev)
5070 5071 5072 5073
{
    virDomainDiskDefPtr disk = dev->data.disk;
    virCgroupPtr cgroup = NULL;
    int ret = -1;
5074

5075
    if (disk->driverName != NULL && !STREQ(disk->driverName, "qemu")) {
5076
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094
                        _("unsupported driver name '%s' for disk '%s'"),
                        disk->driverName, disk->src);
        goto end;
    }

    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Unable to find cgroup for %s"),
                            vm->def->name);
            goto end;
        }
        if (qemuSetupDiskCgroup(driver, vm, cgroup, disk) < 0)
            goto end;
    }
    switch (disk->device)  {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5095
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, false);
5096 5097
        break;
    case VIR_DOMAIN_DISK_DEVICE_DISK:
5098
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5099 5100 5101 5102 5103 5104
        if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                                _("disk device='lun' is not supported for usb bus"));
                break;
            }
5105
            ret = qemuDomainAttachUsbMassstorageDevice(conn, driver, vm,
5106
                                                       disk);
5107
        } else if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
5108
            ret = qemuDomainAttachPciDiskDevice(conn, driver, vm, disk);
5109
        } else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
5110
            ret = qemuDomainAttachSCSIDisk(conn, driver, vm, disk);
5111
        } else {
5112 5113 5114
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                            _("disk bus '%s' cannot be hotplugged."),
                            virDomainDiskBusTypeToString(disk->bus));
5115
        }
5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("disk device type '%s' cannot be hotplugged"),
                        virDomainDiskDeviceTypeToString(disk->device));
        break;
    }

    if (ret != 0 && cgroup) {
        if (qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0)
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(disk->src));
    }
end:
    if (cgroup)
        virCgroupFree(&cgroup);
    return ret;
}

static int
qemuDomainAttachDeviceControllerLive(struct qemud_driver *driver,
                                     virDomainObjPtr vm,
5138
                                     virDomainDeviceDefPtr dev)
5139 5140 5141 5142 5143 5144
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5145
        ret = qemuDomainAttachPciControllerDevice(driver, vm, cont);
5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("disk controller bus '%s' cannot be hotplugged."),
                        virDomainControllerTypeToString(cont->type));
        break;
    }
    return ret;
}

static int
qemuDomainAttachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5159
                           virDomainPtr dom)
5160 5161 5162 5163 5164 5165
{
    struct qemud_driver *driver = dom->conn->privateData;
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5166
        qemuDomainObjCheckDiskTaint(driver, vm, dev->data.disk, -1);
5167
        ret = qemuDomainAttachDeviceDiskLive(dom->conn, driver, vm, dev);
5168 5169 5170 5171 5172
        if (!ret)
            dev->data.disk = NULL;
        break;

    case VIR_DOMAIN_DEVICE_CONTROLLER:
5173
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
5174 5175 5176 5177
        if (!ret)
            dev->data.controller = NULL;
        break;

5178 5179 5180 5181 5182 5183 5184
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

5185
    case VIR_DOMAIN_DEVICE_NET:
5186
        qemuDomainObjCheckNetTaint(driver, vm, dev->data.net, -1);
5187
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
5188
                                        dev->data.net);
5189 5190 5191 5192 5193 5194
        if (!ret)
            dev->data.net = NULL;
        break;

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = qemuDomainAttachHostDevice(driver, vm,
5195
                                         dev->data.hostdev);
5196 5197 5198 5199
        if (!ret)
            dev->data.hostdev = NULL;
        break;

5200 5201 5202 5203 5204 5205 5206
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("device type '%s' cannot be attached"),
                        virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}

static int
qemuDomainDetachDeviceDiskLive(struct qemud_driver *driver,
                               virDomainObjPtr vm,
5220
                               virDomainDeviceDefPtr dev)
5221 5222 5223 5224 5225 5226
{
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_DISK:
5227
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5228
        if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
5229
            ret = qemuDomainDetachPciDiskDevice(driver, vm, dev);
5230
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI)
5231
            ret =  qemuDomainDetachDiskDevice(driver, vm, dev);
5232
        else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB)
5233
            ret = qemuDomainDetachDiskDevice(driver, vm, dev);
5234 5235 5236 5237 5238 5239
        else
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                            _("This type of disk cannot be hot unplugged"));
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5240 5241
                        _("disk device type '%s' cannot be detached"),
                        virDomainDiskDeviceTypeToString(disk->type));
5242 5243 5244 5245 5246 5247 5248 5249
        break;
    }
    return ret;
}

static int
qemuDomainDetachDeviceControllerLive(struct qemud_driver *driver,
                                     virDomainObjPtr vm,
5250
                                     virDomainDeviceDefPtr dev)
5251 5252 5253 5254 5255 5256
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5257
        ret = qemuDomainDetachPciControllerDevice(driver, vm, dev);
5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269
        break;
    default :
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("disk controller bus '%s' cannot be hotunplugged."),
                        virDomainControllerTypeToString(cont->type));
    }
    return ret;
}

static int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5270
                           virDomainPtr dom)
5271 5272 5273 5274 5275 5276
{
    struct qemud_driver *driver = dom->conn->privateData;
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5277
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
5278 5279
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5280
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
5281
        break;
5282 5283 5284
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
5285
    case VIR_DOMAIN_DEVICE_NET:
5286
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
5287 5288
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
5289
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
5290 5291 5292 5293 5294 5295 5296 5297 5298 5299
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        "%s", _("This type of device cannot be hot unplugged"));
        break;
    }

    return ret;
}

5300 5301 5302 5303 5304 5305 5306 5307
static int
qemuDomainChangeDiskMediaLive(virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev,
                              struct qemud_driver *driver,
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
    virCgroupPtr cgroup = NULL;
5308
    int ret = -1;
5309 5310 5311

    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup,
5312
                               vm->def->name, &cgroup, 0) != 0) {
5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Unable to find cgroup for %s"),
                            vm->def->name);
            goto end;
        }
        if (qemuSetupDiskCgroup(driver, vm, cgroup, disk) < 0)
            goto end;
    }

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5325
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, force);
5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357
        if (ret == 0)
            dev->data.disk = NULL;
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("disk bus '%s' cannot be updated."),
                        virDomainDiskBusTypeToString(disk->bus));
        break;
    }

    if (ret != 0 && cgroup) {
        if (qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0)
             VIR_WARN("Failed to teardown cgroup for disk path %s",
                      NULLSTR(disk->src));
    }
end:
    if (cgroup)
        virCgroupFree(&cgroup);
    return ret;
}

static int
qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
                           virDomainPtr dom,
                           bool force)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5358
        ret = qemuDomainChangeDiskMediaLive(vm, dev, driver, force);
5359 5360 5361 5362
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;
5363 5364 5365
    case VIR_DOMAIN_DEVICE_NET:
        ret = qemuDomainChangeNet(driver, vm, dom, dev->data.net);
        break;
5366 5367 5368 5369 5370 5371 5372 5373 5374 5375
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("device type '%s' cannot be updated"),
                        virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}

5376
static int
5377
qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
5378 5379
                             virDomainDeviceDefPtr dev)
{
5380
    virDomainDiskDefPtr disk;
5381
    virDomainNetDefPtr net;
5382
    virDomainHostdevDefPtr hostdev;
5383
    virDomainLeaseDefPtr lease;
5384

5385
    switch (dev->type) {
5386 5387
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
5388
        if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("target %s already exists."), disk->dst);
            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;
5402
        if (qemuDomainAssignAddresses(vmdef) < 0)
5403 5404 5405
            return -1;
        break;

5406 5407 5408 5409
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
        if (virDomainNetIndexByMac(vmdef, net->mac) >= 0) {
            char macbuf[VIR_MAC_STRING_BUFLEN];
5410
            virMacAddrFormat(net->mac, macbuf);
5411 5412 5413 5414 5415 5416 5417 5418 5419
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("mac %s already exists"), macbuf);
            return -1;
        }
        if (virDomainNetInsert(vmdef, net)) {
            virReportOOMError();
            return -1;
        }
        dev->data.net = NULL;
5420
        if (qemuDomainAssignAddresses(vmdef) < 0)
5421 5422
            return -1;
        break;
5423

5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        hostdev = dev->data.hostdev;
        if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
            qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                            _("device is already in the domain configuration"));
            return -1;
        }
        if (virDomainHostdevInsert(vmdef, hostdev)) {
            virReportOOMError();
            return -1;
        }
        dev->data.hostdev = NULL;
        if (qemuDomainAssignAddresses(vmdef) < 0)
            return -1;
        break;

5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
        if (virDomainLeaseIndex(vmdef, lease) >= 0) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Lease %s in lockspace %s already exists"),
                            lease->key, NULLSTR(lease->lockspace));
            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;

5455 5456 5457 5458 5459 5460 5461 5462 5463 5464
    default:
         qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                         _("persistent attach of device is not supported"));
         return -1;
    }
    return 0;
}


static int
5465
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
5466 5467
                             virDomainDeviceDefPtr dev)
{
5468 5469
    virDomainDiskDefPtr disk, det_disk;
    virDomainNetDefPtr net, det_net;
5470
    virDomainHostdevDefPtr hostdev, det_hostdev;
5471
    virDomainLeaseDefPtr lease, det_lease;
5472

5473
    switch (dev->type) {
5474 5475
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
5476
        if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
5477 5478 5479 5480
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("no target device %s"), disk->dst);
            return -1;
        }
5481
        virDomainDiskDefFree(det_disk);
5482
        break;
5483

5484 5485
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
5486
        if (!(det_net = virDomainNetRemoveByMac(vmdef, net->mac))) {
5487 5488
            char macbuf[VIR_MAC_STRING_BUFLEN];

5489
            virMacAddrFormat(net->mac, macbuf);
5490 5491 5492 5493
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("no nic of mac %s"), macbuf);
            return -1;
        }
5494
        virDomainNetDefFree(det_net);
5495
        break;
5496

5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        int idx;

        hostdev = dev->data.hostdev;
        if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
            qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                            _("device not present in domain configuration"));
            return -1;
        }
        virDomainHostdevRemove(vmdef, idx);
        virDomainHostdevDefFree(det_hostdev);
        break;
    }

5511 5512
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
5513
        if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) {
5514 5515 5516 5517 5518
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Lease %s in lockspace %s does not exist"),
                            lease->key, NULLSTR(lease->lockspace));
            return -1;
        }
5519
        virDomainLeaseDefFree(det_lease);
5520 5521
        break;

5522 5523 5524 5525 5526 5527 5528 5529 5530
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent detach of device is not supported"));
        return -1;
    }
    return 0;
}

static int
5531
qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
5532 5533
                             virDomainDeviceDefPtr dev)
{
5534
    virDomainDiskDefPtr orig, disk;
5535
    virDomainNetDefPtr net;
5536 5537
    int pos;

5538
    switch (dev->type) {
5539 5540
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
5541
        pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
5542 5543
        if (pos < 0) {
            qemuReportError(VIR_ERR_INVALID_ARG,
5544
                            _("target %s doesn't exist."), disk->dst);
5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573
            return -1;
        }
        orig = vmdef->disks[pos];
        if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
            !(orig->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("this disk doesn't support update"));
            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;
        }
        if (disk->driverType) {
            VIR_FREE(orig->driverType);
            orig->driverType = disk->driverType;
            disk->driverType = NULL;
        }
        disk->src = NULL;
        break;
5574 5575 5576 5577 5578

    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
        if ((pos = virDomainNetIndexByMac(vmdef, net->mac)) < 0) {
            char macbuf[VIR_MAC_STRING_BUFLEN];
5579
            virMacAddrFormat(net->mac, macbuf);
5580 5581 5582 5583 5584
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("mac %s doesn't exist"), macbuf);
            return -1;
        }

5585
        virDomainNetDefFree(vmdef->nets[pos]);
5586 5587 5588 5589

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

5590
        if (qemuDomainAssignAddresses(vmdef) < 0)
5591 5592 5593
            return -1;
        break;

5594 5595 5596 5597 5598 5599 5600 5601
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                         _("persistent update of device is not supported"));
        return -1;
    }
    return 0;
}

5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612
/* 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)
5613
{
5614
    struct qemud_driver *driver = dom->conn->privateData;
5615
    virDomainObjPtr vm = NULL;
5616
    virDomainDefPtr vmdef = NULL;
5617
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
5618
    bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
5619
    int ret = -1;
5620
    unsigned int affect;
5621

5622 5623
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
5624 5625 5626
                  (action == QEMU_DEVICE_UPDATE ?
                   VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);

5627 5628
    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

5629 5630 5631 5632 5633 5634 5635
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5636 5637 5638
        goto cleanup;
    }

5639
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
5640
        goto cleanup;
5641

5642
    if (virDomainObjIsActive(vm)) {
5643
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
5644
            flags |= VIR_DOMAIN_AFFECT_LIVE;
5645
    } else {
5646
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
5647
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
5648
        /* check consistency between flags and the vm state */
5649
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
5650 5651 5652 5653 5654 5655
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s",
                            _("cannot do live update a device on "
                              "inactive domain"));
            goto endjob;
        }
5656
    }
5657

5658
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
5659 5660 5661 5662
         qemuReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("cannot modify device on transient domain"));
         goto endjob;
    }
5663

5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676
    dev = dev_copy = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                             VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto endjob;

    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        flags & VIR_DOMAIN_AFFECT_LIVE) {
        /* If we are affecting both CONFIG and LIVE
         * create a deep copy of device as adding
         * to CONFIG takes one instance.
         */
        dev_copy = virDomainDeviceDefCopy(driver->caps, vm->def, dev);
        if (!dev_copy)
5677
            goto endjob;
5678
    }
5679

5680
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto endjob;
        switch (action) {
        case QEMU_DEVICE_ATTACH:
            ret = qemuDomainAttachDeviceConfig(vmdef, dev);
            break;
        case QEMU_DEVICE_DETACH:
            ret = qemuDomainDetachDeviceConfig(vmdef, dev);
            break;
        case QEMU_DEVICE_UPDATE:
            ret = qemuDomainUpdateDeviceConfig(vmdef, dev);
            break;
        default:
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("unknown domain modify action %d"), action);
            break;
        }
5700

5701 5702 5703 5704 5705
        if (ret == -1)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
5706 5707
        switch (action) {
        case QEMU_DEVICE_ATTACH:
5708
            ret = qemuDomainAttachDeviceLive(vm, dev_copy, dom);
5709 5710
            break;
        case QEMU_DEVICE_DETACH:
5711
            ret = qemuDomainDetachDeviceLive(vm, dev_copy, dom);
5712 5713
            break;
        case QEMU_DEVICE_UPDATE:
5714
            ret = qemuDomainUpdateDeviceLive(vm, dev_copy, dom, force);
5715 5716 5717 5718
            break;
        default:
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("unknown domain modify action %d"), action);
5719
            ret = -1;
5720 5721
            break;
        }
5722 5723 5724

        if (ret == -1)
            goto endjob;
5725 5726
        /*
         * update domain status forcibly because the domain status may be
5727 5728
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
5729
         */
5730
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
5731
            ret = -1;
5732 5733
            goto endjob;
        }
5734
    }
5735

5736
    /* Finally, if no error until here, we can save config. */
5737
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5738 5739 5740 5741 5742 5743
        ret = virDomainSaveConfig(driver->configDir, vmdef);
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false);
            vmdef = NULL;
        }
    }
5744 5745

endjob:
5746
    if (qemuDomainObjEndJob(driver, vm) == 0)
5747 5748 5749
        vm = NULL;

cleanup:
5750
    virDomainDefFree(vmdef);
5751 5752
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
5753 5754 5755 5756
    virDomainDeviceDefFree(dev);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
5757 5758 5759
    return ret;
}

5760 5761 5762 5763 5764 5765
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_ATTACH);
}

5766 5767 5768
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
5769
                                       VIR_DOMAIN_AFFECT_LIVE);
5770
}
5771

5772

5773 5774 5775 5776
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
5777
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_UPDATE);
5778 5779
}

5780 5781 5782
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
5783
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_DETACH);
5784 5785
}

5786 5787 5788
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
5789
                                       VIR_DOMAIN_AFFECT_LIVE);
5790 5791
}

5792
static int qemudDomainGetAutostart(virDomainPtr dom,
5793
                                   int *autostart) {
5794 5795 5796
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5797

5798
    qemuDriverLock(driver);
5799
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5800 5801
    qemuDriverUnlock(driver);

5802
    if (!vm) {
5803 5804
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5805 5806
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5807
        goto cleanup;
5808 5809 5810
    }

    *autostart = vm->autostart;
5811
    ret = 0;
5812

5813
cleanup:
5814 5815
    if (vm)
        virDomainObjUnlock(vm);
5816
    return ret;
5817 5818
}

5819
static int qemudDomainSetAutostart(virDomainPtr dom,
5820
                                   int autostart) {
5821 5822
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5823 5824
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
5825

5826
    qemuDriverLock(driver);
5827
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5828

5829
    if (!vm) {
5830 5831
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5832 5833
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5834
        goto cleanup;
5835 5836
    }

5837
    if (!vm->persistent) {
5838
        qemuReportError(VIR_ERR_OPERATION_INVALID,
5839
                        "%s", _("cannot set autostart for transient domain"));
5840
        goto cleanup;
5841 5842
    }

5843 5844
    autostart = (autostart != 0);

5845
    if (vm->autostart != autostart) {
5846
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
5847
            goto cleanup;
5848
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
5849
            goto cleanup;
5850

5851
        if (autostart) {
5852 5853
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
5854 5855
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
5856 5857
                goto cleanup;
            }
5858

5859
            if (symlink(configFile, autostartLink) < 0) {
5860
                virReportSystemError(errno,
5861 5862
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
5863 5864 5865 5866
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
5867
                virReportSystemError(errno,
5868 5869
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
5870 5871
                goto cleanup;
            }
5872 5873
        }

5874
        vm->autostart = autostart;
5875
    }
5876
    ret = 0;
5877

5878 5879 5880
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
5881 5882
    if (vm)
        virDomainObjUnlock(vm);
5883
    qemuDriverUnlock(driver);
5884
    return ret;
5885 5886
}

5887

5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920
/*
 * 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;
}


5921 5922 5923 5924
static char *qemuGetSchedulerType(virDomainPtr dom,
                                  int *nparams)
{
    struct qemud_driver *driver = dom->conn->privateData;
5925
    char *ret = NULL;
5926
    int rc;
5927

5928
    qemuDriverLock(driver);
5929
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5930 5931
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup CPU controller is not mounted"));
5932
        goto cleanup;
5933 5934
    }

5935 5936 5937 5938 5939 5940 5941 5942 5943
    if (nparams) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        else if (rc == 0)
            *nparams = 1;
        else
            *nparams = 3;
    }
5944 5945 5946

    ret = strdup("posix");
    if (!ret)
5947
        virReportOOMError();
5948 5949 5950

cleanup:
    qemuDriverUnlock(driver);
5951 5952 5953
    return ret;
}

5954 5955 5956 5957
/* 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
5958 5959
qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
                               virBlkioDeviceWeightPtr *dw, size_t *size)
5960 5961 5962 5963 5964 5965 5966
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
    int i;
    virBlkioDeviceWeightPtr result = NULL;

5967 5968 5969 5970 5971 5972
    *dw = NULL;
    *size = 0;

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

5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034
    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:
    qemuReportError(VIR_ERR_INVALID_ARG,
6035
                    _("unable to parse device weight '%s'"), deviceWeightStr);
6036 6037 6038 6039 6040 6041
cleanup:
    virBlkioDeviceWeightArrayClear(result, ndevices);
    VIR_FREE(result);
    return -1;
}

6042 6043
/* Modify dest_array to reflect all device weight changes described in
 * src_array.  */
6044
static int
6045 6046 6047 6048
qemuDomainMergeDeviceWeights(virBlkioDeviceWeightPtr *dest_array,
                             size_t *dest_size,
                             virBlkioDeviceWeightPtr src_array,
                             size_t src_size)
6049 6050
{
    int i, j;
6051
    virBlkioDeviceWeightPtr dest, src;
6052

6053
    for (i = 0; i < src_size; i++) {
6054 6055
        bool found = false;

6056 6057 6058 6059
        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
6060
                found = true;
6061
                dest->weight = src->weight;
6062 6063 6064 6065
                break;
            }
        }
        if (!found) {
6066
            if (!src->weight)
6067
                continue;
6068
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0) {
6069 6070 6071
                virReportOOMError();
                return -1;
            }
6072 6073 6074 6075
            dest = &(*dest_array)[*dest_size - 1];
            dest->path = src->path;
            dest->weight = src->weight;
            src->path = NULL;
6076 6077 6078 6079 6080 6081
        }
    }

    return 0;
}

6082 6083 6084 6085 6086
static int
qemuDomainSetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
6087 6088 6089 6090 6091
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6092
    virDomainDefPtr persistentDef = NULL;
6093 6094
    int ret = -1;

6095 6096
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6097 6098 6099 6100 6101 6102 6103
    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;
6104

6105
    qemuDriverLock(driver);
6106 6107 6108 6109 6110 6111 6112 6113
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

6114 6115 6116
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
6117

6118 6119
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
6120 6121
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            _("blkio cgroup isn't mounted"));
6122 6123 6124 6125 6126
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
6127 6128
                            _("cannot find cgroup for domain %s"),
                            vm->def->name);
6129 6130 6131 6132
            goto cleanup;
        }
    }

6133
    ret = 0;
6134 6135
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        for (i = 0; i < nparams; i++) {
6136
            int rc;
6137 6138 6139 6140 6141 6142 6143 6144 6145
            virTypedParameterPtr param = &params[i];

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

6147 6148 6149 6150 6151 6152
                rc = virCgroupSetBlkioWeight(group, params[i].value.ui);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set blkio weight tunable"));
                    ret = -1;
                }
6153
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
6154
                size_t ndevices;
6155
                virBlkioDeviceWeightPtr devices = NULL;
6156 6157
                int j;

6158 6159 6160
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
6161 6162 6163
                    ret = -1;
                    continue;
                }
6164
                for (j = 0; j < ndevices; j++) {
6165
                    rc = virCgroupSetBlkioDeviceWeight(group,
6166 6167
                                                       devices[j].path,
                                                       devices[j].weight);
6168 6169 6170 6171
                    if (rc < 0) {
                        virReportSystemError(-rc,
                                             _("Unable to set io device weight "
                                               "for path %s"),
6172
                                             devices[j].path);
6173 6174 6175
                        break;
                    }
                }
6176 6177
                if (j != ndevices ||
                    qemuDomainMergeDeviceWeights(&vm->def->blkio.devices,
6178 6179 6180 6181 6182
                                                 &vm->def->blkio.ndevices,
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
6183
            }
6184
        }
E
Eric Blake 已提交
6185 6186 6187 6188
    }
    if (ret < 0)
        goto cleanup;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
6189 6190 6191
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203
        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) {
                    qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                    _("out of blkio weight range."));
                    ret = -1;
                    continue;
                }

                persistentDef->blkio.weight = params[i].value.ui;
6204 6205
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
                virBlkioDeviceWeightPtr devices = NULL;
6206
                size_t ndevices;
6207

6208 6209 6210
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
6211 6212 6213
                    ret = -1;
                    continue;
                }
6214 6215
                if (qemuDomainMergeDeviceWeights(&persistentDef->blkio.devices,
                                                 &persistentDef->blkio.ndevices,
6216 6217 6218 6219
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
6220 6221
            }
        }
A
Alex Jia 已提交
6222 6223 6224

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
6225 6226 6227 6228 6229 6230 6231 6232 6233 6234
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

6235 6236 6237 6238 6239
static int
qemuDomainGetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
6240 6241
{
    struct qemud_driver *driver = dom->conn->privateData;
6242
    int i, j;
6243 6244
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6245
    virDomainDefPtr persistentDef = NULL;
6246 6247 6248 6249
    unsigned int val;
    int ret = -1;
    int rc;

6250
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
6251 6252
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
6253 6254
    qemuDriverLock(driver);

6255 6256 6257
    /* 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.  */
6258 6259
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

6275 6276 6277
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
6278

6279 6280
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
6281
            qemuReportError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted"));
6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find cgroup for domain %s"), vm->def->name);
            goto cleanup;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6293
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304
            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;
                }
6305 6306
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
6307 6308
                    goto cleanup;
                break;
6309 6310 6311 6312
            case 1: /* blkiotune.device_weight */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;
6313

6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330
                    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);
                }
6331 6332 6333 6334
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
6335 6336
                    goto cleanup;
                break;
6337 6338 6339 6340

            default:
                break;
                /* should not hit here */
6341
            }
6342 6343
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6344
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
6345 6346 6347 6348 6349 6350 6351 6352 6353
            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) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
6354 6355
                                    _("Field name '%s' too long"),
                                    VIR_DOMAIN_BLKIO_WEIGHT);
6356 6357 6358 6359
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
6360

6361 6362 6363
            case 1: /* blkiotune.device_weight */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
6364 6365
                    bool comma = false;

6366
                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
6367 6368 6369
                        if (!persistentDef->blkio.devices[j].weight)
                            continue;
                        if (comma)
6370
                            virBufferAddChar(&buf, ',');
6371 6372
                        else
                            comma = true;
6373 6374 6375 6376 6377 6378 6379 6380 6381
                        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);
6382 6383
                }
                if (!param->value.s) {
6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399
                    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) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    _("Field name '%s' too long"),
                                    VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
                    goto cleanup;
                }
                break;

6400 6401 6402 6403
            default:
                break;
                /* should not hit here */
            }
6404 6405 6406
        }
    }

6407 6408
    if (QEMU_NB_BLKIO_PARAM < *nparams)
        *nparams = QEMU_NB_BLKIO_PARAM;
6409 6410 6411 6412 6413 6414 6415 6416 6417 6418
    ret = 0;

cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
6419

6420 6421 6422 6423 6424
static int
qemuDomainSetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              unsigned int flags)
6425 6426 6427
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
6428
    virDomainDefPtr persistentDef = NULL;
6429 6430 6431
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
6432
    int rc;
6433

6434 6435
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6436 6437 6438 6439 6440 6441 6442 6443 6444
    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;
6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455

    qemuDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

6456 6457 6458
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
6459

6460
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("cgroup memory controller is not mounted"));
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find cgroup for domain %s"), vm->def->name);
            goto cleanup;
        }
    }

6474 6475
    ret = 0;
    for (i = 0; i < nparams; i++) {
6476
        virTypedParameterPtr param = &params[i];
6477 6478

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
6479
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6480 6481 6482 6483 6484 6485 6486 6487
                rc = virCgroupSetMemoryHardLimit(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set memory hard_limit tunable"));
                    ret = -1;
                }
            }

6488
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6489
                persistentDef->mem.hard_limit = params[i].value.ul;
6490 6491
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
6492
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6493 6494 6495 6496 6497 6498 6499 6500
                rc = virCgroupSetMemorySoftLimit(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set memory soft_limit tunable"));
                    ret = -1;
                }
            }

6501
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6502
                persistentDef->mem.soft_limit = params[i].value.ul;
6503
            }
6504
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
6505
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6506 6507 6508 6509 6510 6511 6512
                rc = virCgroupSetMemSwapHardLimit(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set swap_hard_limit tunable"));
                    ret = -1;
                }
            }
6513
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6514
                persistentDef->mem.swap_hard_limit = params[i].value.ul;
6515 6516 6517 6518
            }
        }
    }

6519
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6520 6521
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
6522 6523
    }

6524 6525 6526 6527 6528 6529 6530 6531
cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

6532 6533 6534 6535 6536
static int
qemuDomainGetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int *nparams,
                              unsigned int flags)
6537 6538 6539 6540 6541
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6542
    virDomainDefPtr persistentDef = NULL;
6543 6544 6545
    int ret = -1;
    int rc;

6546
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
6547 6548
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
6549

6550
    qemuDriverLock(driver);
6551

6552 6553 6554
    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

6555 6556 6557 6558 6559 6560 6561 6562
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

6563 6564 6565
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
6566

6567
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("cgroup memory controller is not mounted"));
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find cgroup for domain %s"), vm->def->name);
            goto cleanup;
        }
    }

6581 6582 6583 6584 6585 6586 6587
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

6588
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6589
        for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
6590 6591 6592 6593
            virMemoryParameterPtr param = &params[i];

            switch (i) {
            case 0: /* fill memory hard limit here */
6594 6595 6596 6597
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.hard_limit) < 0)
6598 6599 6600 6601
                    goto cleanup;
                break;

            case 1: /* fill memory soft limit here */
6602 6603 6604 6605
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.soft_limit) < 0)
6606 6607 6608 6609
                    goto cleanup;
                break;

            case 2: /* fill swap hard limit here */
6610 6611 6612 6613
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.swap_hard_limit) < 0)
6614 6615 6616 6617 6618 6619 6620 6621 6622
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
6623 6624
    }

6625
    for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
6626
        virTypedParameterPtr param = &params[i];
6627
        unsigned long long val = 0;
6628

6629 6630 6631
        /* Coverity does not realize that if we get here, group is set.  */
        sa_assert(group);

6632
        switch (i) {
6633 6634 6635 6636 6637
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
6638
                goto cleanup;
6639
            }
6640 6641 6642
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
6643
                goto cleanup;
6644 6645 6646 6647 6648 6649 6650
            break;

        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
6651
                goto cleanup;
6652
            }
6653 6654 6655
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
6656
                goto cleanup;
6657 6658 6659
            break;

        case 2: /* fill swap hard limit here */
6660
            rc = virCgroupGetMemSwapHardLimit(group, &val);
6661 6662 6663
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
6664
                goto cleanup;
6665
            }
6666 6667 6668
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
6669
                goto cleanup;
6670 6671 6672 6673 6674 6675 6676 6677
            break;

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

6678
out:
6679 6680
    if (QEMU_NB_MEM_PARAM < *nparams)
        *nparams = QEMU_NB_MEM_PARAM;
6681 6682
    ret = 0;

6683 6684 6685 6686 6687 6688 6689 6690 6691
cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706
static int
qemuDomainSetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virDomainDefPtr persistentDef = NULL;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6707 6708 6709 6710 6711 6712 6713
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_NUMA_MODE,
                                       VIR_TYPED_PARAM_INT,
                                       VIR_DOMAIN_NUMA_NODESET,
                                       VIR_TYPED_PARAM_STRING,
                                       NULL) < 0)
        return -1;
6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761

    qemuDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("cgroup cpuset controller is not mounted"));
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find cgroup for domain %s"),
                            vm->def->name);
            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) {
                qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                _("can't change numa mode for running domain"));
                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;
H
Hu Tao 已提交
6762
            bool savedmask;
6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783
            char oldnodemask[VIR_DOMAIN_CPUMASK_LEN];

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                if (vm->def->numatune.memory.mode !=
                    VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
                    qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                    _("change of nodeset for running domain "
                                      "requires strict numa mode"));
                    ret = -1;
                    continue;
                }
                rc = virCgroupSetCpusetMems(group, params[i].value.s);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set numa tunable"));
                    ret = -1;
                    continue;
                }

                /* update vm->def here so that dumpxml can read the new
                 * values from vm->def. */
H
Hu Tao 已提交
6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796
                savedmask = false;
                if (!vm->def->numatune.memory.nodemask) {
                    if (VIR_ALLOC_N(vm->def->numatune.memory.nodemask,
                                    VIR_DOMAIN_CPUMASK_LEN) < 0) {
                        virReportOOMError();
                        ret = -1;
                        goto cleanup;
                    }
                } else {
                    memcpy(oldnodemask, vm->def->numatune.memory.nodemask,
                           VIR_DOMAIN_CPUMASK_LEN);
                    savedmask = true;
                }
6797 6798 6799 6800
                if (virDomainCpuSetParse(params[i].value.s,
                                         0,
                                         vm->def->numatune.memory.nodemask,
                                         VIR_DOMAIN_CPUMASK_LEN) < 0) {
H
Hu Tao 已提交
6801 6802 6803 6804 6805
                    if (savedmask)
                        memcpy(vm->def->numatune.memory.nodemask,
                               oldnodemask, VIR_DOMAIN_CPUMASK_LEN);
                    else
                        VIR_FREE(vm->def->numatune.memory.nodemask);
6806 6807 6808 6809 6810 6811
                    ret = -1;
                    continue;
                }
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
H
Hu Tao 已提交
6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824
                savedmask = false;
                if (!persistentDef->numatune.memory.nodemask) {
                    if (VIR_ALLOC_N(persistentDef->numatune.memory.nodemask,
                                    VIR_DOMAIN_CPUMASK_LEN) < 0) {
                        virReportOOMError();
                        ret = -1;
                        goto cleanup;
                    }
                } else {
                    memcpy(oldnodemask, persistentDef->numatune.memory.nodemask,
                           VIR_DOMAIN_CPUMASK_LEN);
                    savedmask = true;
                }
6825 6826 6827 6828
                if (virDomainCpuSetParse(params[i].value.s,
                                         0,
                                         persistentDef->numatune.memory.nodemask,
                                         VIR_DOMAIN_CPUMASK_LEN) < 0) {
H
Hu Tao 已提交
6829 6830 6831 6832 6833
                    if (savedmask)
                        memcpy(persistentDef->numatune.memory.nodemask,
                               oldnodemask, VIR_DOMAIN_CPUMASK_LEN);
                    else
                        VIR_FREE(persistentDef->numatune.memory.nodemask);
6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917
                    ret = -1;
                    continue;
                }
            }
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    char *nodeset = NULL;
    int ret = -1;
    int rc;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    qemuDriverLock(driver);

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

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &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)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("cgroup memory controller is not mounted"));
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find cgroup for domain %s"),
                            vm->def->name);
            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 */
6918 6919
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942
                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) {
                char *mask = persistentDef->numatune.memory.nodemask;
                if (mask)
                    nodeset = virDomainCpuSetFormat(mask,
                                                    VIR_DOMAIN_CPUMASK_LEN);
                else
                    nodeset = strdup("");
            } else {
                rc = virCgroupGetCpusetMems(group, &nodeset);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get numa nodeset"));
                    goto cleanup;
                }
            }
6943 6944
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965
                goto cleanup;
            break;

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

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

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

6966 6967 6968 6969 6970 6971 6972 6973
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;
W
Wen Congyang 已提交
6974 6975 6976
    long long vm_quota = 0;
    long long old_quota = 0;
    unsigned long long old_period = 0;
6977 6978 6979 6980

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

W
Wen Congyang 已提交
6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999
    /* Ensure that we can multiply by vcpus without overflowing. */
    if (quota > LLONG_MAX / vm->def->vcpus) {
        virReportSystemError(EINVAL,
                             _("%s"),
                             "Unable to set cpu bandwidth quota");
        goto cleanup;
    }

    if (quota > 0)
        vm_quota = quota * vm->def->vcpus;
    else
        vm_quota = quota;

    rc = virCgroupGetCpuCfsQuota(cgroup, &old_quota);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth tunable"));
        goto cleanup;
    }
7000

W
Wen Congyang 已提交
7001 7002 7003 7004 7005
    rc = virCgroupGetCpuCfsPeriod(cgroup, &old_period);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth period tunable"));
        goto cleanup;
7006 7007
    }

W
Wen Congyang 已提交
7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028
    /*
     * If quota will be changed to a small value, we should modify vcpu's quota
     * first. Otherwise, we should modify vm's quota first.
     *
     * If period will be changed to a small value, we should modify vm's period
     * first. Otherwise, we should modify vcpu's period first.
     *
     * If both quota and period will be changed to a big/small value, we cannot
     * modify period and quota together.
     */
    if ((quota != 0) && (period != 0)) {
        if (((quota > old_quota) && (period > old_period)) ||
            ((quota < old_quota) && (period < old_period))) {
            /* modify period */
            if (qemuSetVcpusBWLive(vm, cgroup, period, 0) < 0)
                goto cleanup;

            /* modify quota */
            if (qemuSetVcpusBWLive(vm, cgroup, 0, quota) < 0)
                goto cleanup;
            return 0;
7029
        }
W
Wen Congyang 已提交
7030
    }
7031

W
Wen Congyang 已提交
7032 7033 7034 7035
    if (((vm_quota != 0) && (vm_quota > old_quota)) ||
        ((period != 0) && (period < old_period)))
        /* Set cpu bandwidth for the vm */
        if (qemuSetupCgroupVcpuBW(cgroup, period, vm_quota) < 0)
7036 7037
            goto cleanup;

W
Wen Congyang 已提交
7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057
    /* 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);
        }
7058 7059
    }

W
Wen Congyang 已提交
7060 7061 7062 7063 7064 7065
    if (((vm_quota != 0) && (vm_quota <= old_quota)) ||
        ((period != 0) && (period >= old_period)))
        /* Set cpu bandwidth for the vm */
        if (qemuSetupCgroupVcpuBW(cgroup, period, vm_quota) < 0)
            goto cleanup;

7066 7067 7068 7069 7070 7071 7072
    return 0;

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

7073 7074 7075 7076 7077
static int
qemuSetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int nparams,
                                unsigned int flags)
7078 7079 7080 7081 7082
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7083
    virDomainDefPtr vmdef = NULL;
7084
    int ret = -1;
7085
    int rc;
7086

7087 7088
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7089 7090 7091 7092 7093 7094 7095 7096 7097
    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,
                                       NULL) < 0)
        return -1;
7098

7099
    qemuDriverLock(driver);
7100 7101 7102 7103

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7104 7105
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
7106 7107 7108
        goto cleanup;
    }

7109 7110 7111
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &vmdef) < 0)
        goto cleanup;
7112

7113 7114 7115 7116 7117
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto cleanup;
7118 7119
    }

7120
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("cgroup CPU controller is not mounted"));
            goto cleanup;
        }
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find cgroup for domain %s"),
                            vm->def->name);
            goto cleanup;
        }
    }

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

7137
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
7138
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7139 7140 7141 7142 7143 7144 7145 7146
                rc = virCgroupSetCpuShares(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set cpu shares tunable"));
                    goto cleanup;
                }

                vm->def->cputune.shares = params[i].value.ul;
7147
            }
7148

7149
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7150 7151
                vmdef->cputune.shares = params[i].value.ul;
            }
7152
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
7153 7154 7155
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = qemuSetVcpusBWLive(vm, group, params[i].value.ul, 0);
                if (rc != 0)
7156
                    goto cleanup;
7157 7158 7159 7160 7161 7162 7163 7164

                if (params[i].value.ul)
                    vm->def->cputune.period = params[i].value.ul;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.period = params[i].value.ul;
            }
7165
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
7166 7167 7168
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = qemuSetVcpusBWLive(vm, group, 0, params[i].value.l);
                if (rc != 0)
7169
                    goto cleanup;
7170 7171 7172 7173 7174 7175 7176

                if (params[i].value.l)
                    vm->def->cputune.quota = params[i].value.l;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.quota = params[i].value.l;
7177
            }
7178 7179
        }
    }
7180

7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto cleanup;


    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        rc = virDomainSaveConfig(driver->configDir, vmdef);
        if (rc < 0)
            goto cleanup;

        virDomainObjAssignDef(vm, vmdef, false);
        vmdef = NULL;
    }

7194 7195 7196
    ret = 0;

cleanup:
7197
    virDomainDefFree(vmdef);
7198 7199 7200
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
7201
    qemuDriverUnlock(driver);
7202 7203 7204
    return ret;
}

7205 7206 7207 7208
static int
qemuSetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int nparams)
7209 7210 7211 7212
{
    return qemuSetSchedulerParametersFlags(dom,
                                           params,
                                           nparams,
7213
                                           VIR_DOMAIN_AFFECT_LIVE);
7214 7215
}

7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280
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;
}

7281 7282 7283 7284 7285
static int
qemuGetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int *nparams,
                                unsigned int flags)
7286 7287 7288 7289
{
    struct qemud_driver *driver = dom->conn->privateData;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7290 7291 7292
    unsigned long long shares;
    unsigned long long period;
    long long quota;
7293 7294
    int ret = -1;
    int rc;
7295
    bool cpu_bw_status = false;
7296
    int saved_nparams = 0;
7297
    virDomainDefPtr persistentDef;
7298

7299
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7300 7301
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7302

7303 7304
    qemuDriverLock(driver);

7305 7306 7307
    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7308 7309 7310 7311 7312 7313 7314
    if (*nparams > 1) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        cpu_bw_status = !!rc;
    }

7315 7316 7317
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7318 7319
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
7320 7321 7322
        goto cleanup;
    }

7323 7324 7325
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
7326

7327
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7328 7329 7330 7331
        shares = persistentDef->cputune.shares;
        if (*nparams > 1 && cpu_bw_status) {
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
7332
        }
7333
        goto out;
7334 7335
    }

7336 7337 7338 7339 7340 7341
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup CPU controller is not mounted"));
        goto cleanup;
    }

7342
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7343 7344
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
7345 7346 7347
        goto cleanup;
    }

7348
    rc = virCgroupGetCpuShares(group, &shares);
7349
    if (rc != 0) {
7350
        virReportSystemError(-rc, "%s",
7351 7352 7353
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
7354 7355 7356 7357 7358 7359

    if (*nparams > 1 && cpu_bw_status) {
        rc = qemuGetVcpusBWLive(vm, group, &period, &quota);
        if (rc != 0)
            goto cleanup;
    }
7360
out:
7361 7362
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
7363
        goto cleanup;
7364 7365 7366 7367
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
7368 7369 7370
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
7371 7372 7373 7374 7375
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
7376 7377 7378
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
7379 7380 7381 7382 7383 7384 7385
                goto cleanup;
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

7386 7387 7388 7389 7390 7391
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
7392
    qemuDriverUnlock(driver);
7393 7394 7395
    return ret;
}

7396 7397 7398 7399 7400 7401
static int
qemuGetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int *nparams)
{
    return qemuGetSchedulerParametersFlags(dom, params, nparams,
7402
                                           VIR_DOMAIN_AFFECT_CURRENT);
7403
}
7404

7405 7406 7407 7408 7409 7410 7411
/**
 * 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 已提交
7412 7413 7414 7415
qemuDomainBlockResize(virDomainPtr dom,
                      const char *path,
                      unsigned long long size,
                      unsigned int flags)
7416 7417 7418 7419 7420 7421 7422 7423
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1, i;
    char *device = NULL;
    virDomainDiskDefPtr disk = NULL;

E
Eric Blake 已提交
7424
    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
7425 7426 7427 7428 7429 7430 7431

    if (path[0] == '\0') {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("empty path"));
        return -1;
    }

E
Eric Blake 已提交
7432 7433 7434
    /* We prefer operating on bytes.  */
    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
        if (size > ULLONG_MAX / 1024) {
E
Eric Blake 已提交
7435
            qemuReportError(VIR_ERR_OVERFLOW,
E
Eric Blake 已提交
7436 7437 7438 7439 7440
                            _("size must be less than %llu"),
                            ULLONG_MAX / 1024);
            return -1;
        }
        size *= 1024;
7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

    priv = vm->privateData;

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

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

    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path: %s"), path);
7469
        goto endjob;
7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498
    }
    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)
        virDomainObjUnlock(vm);
    return ret;
}

7499 7500 7501 7502 7503
/* 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
7504 7505 7506
qemuDomainBlockStats(virDomainPtr dom,
                     const char *path,
                     struct _virDomainBlockStats *stats)
7507
{
7508
    struct qemud_driver *driver = dom->conn->privateData;
7509
    int i, ret = -1;
7510
    virDomainObjPtr vm;
7511
    virDomainDiskDefPtr disk = NULL;
7512
    qemuDomainObjPrivatePtr priv;
7513

7514
    qemuDriverLock(driver);
7515
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
7516
    qemuDriverUnlock(driver);
7517
    if (!vm) {
7518 7519
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7520 7521
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7522
        goto cleanup;
7523
    }
7524

7525 7526 7527 7528 7529 7530
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

7531
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
7532 7533
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path: %s"), path);
7534
        goto cleanup;
7535
    }
7536
    disk = vm->def->disks[i];
7537

7538
    if (!disk->info.alias) {
7539 7540
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), disk->dst);
7541
        goto cleanup;
7542
    }
7543

7544
    priv = vm->privateData;
7545 7546
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;
7547

7548 7549 7550 7551 7552
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }
7553

7554
    qemuDomainObjEnterMonitor(driver, vm);
7555 7556 7557 7558
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
7559
                                       NULL,
7560 7561
                                       &stats->wr_req,
                                       &stats->wr_bytes,
7562 7563 7564
                                       NULL,
                                       NULL,
                                       NULL,
7565 7566
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
7567

7568
endjob:
7569 7570
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
7571

7572
cleanup:
7573 7574
    if (vm)
        virDomainObjUnlock(vm);
7575
    return ret;
7576 7577
}

7578
static int
7579 7580 7581 7582 7583
qemuDomainBlockStatsFlags(virDomainPtr dom,
                          const char *path,
                          virTypedParameterPtr params,
                          int *nparams,
                          unsigned int flags)
7584 7585 7586 7587 7588 7589 7590 7591
{
    struct qemud_driver *driver = dom->conn->privateData;
    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;
7592
    virTypedParameterPtr param;
7593

7594 7595 7596 7597
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

    if (*nparams != 0) {
7617
        if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
7618 7619 7620 7621
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("invalid path: %s"), path);
            goto cleanup;
        }
7622
        disk = vm->def->disks[i];
7623 7624 7625

        if (!disk->info.alias) {
             qemuReportError(VIR_ERR_INTERNAL_ERROR,
7626 7627
                             _("missing disk device alias name for %s"),
                             disk->dst);
7628 7629 7630 7631 7632 7633 7634 7635 7636 7637
             goto cleanup;
        }
    }

    priv = vm->privateData;
    VIR_DEBUG("priv=%p, params=%p, flags=%x", priv, params, flags);

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

7638 7639 7640 7641 7642 7643
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }

7644 7645 7646 7647
    qemuDomainObjEnterMonitor(driver, vm);
    tmp = *nparams;
    ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);

7648
    if (tmp == 0 || ret < 0) {
7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669
        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;

7670 7671
    tmp = 0;
    ret = -1;
7672

7673 7674
    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
7675 7676
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
7677 7678 7679
            goto endjob;
        tmp++;
    }
7680

7681
    if (tmp < *nparams && wr_req != -1) {
7682
        param = &params[tmp];
7683 7684
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
7685 7686 7687
            goto endjob;
        tmp++;
    }
7688

7689
    if (tmp < *nparams && rd_bytes != -1) {
7690
        param = &params[tmp];
7691 7692
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
7693 7694 7695
            goto endjob;
        tmp++;
    }
7696

7697
    if (tmp < *nparams && rd_req != -1) {
7698
        param = &params[tmp];
7699 7700
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
7701 7702 7703
            goto endjob;
        tmp++;
    }
7704

7705
    if (tmp < *nparams && flush_req != -1) {
7706
        param = &params[tmp];
7707 7708
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ,
                                    VIR_TYPED_PARAM_LLONG, flush_req) < 0)
7709 7710 7711
            goto endjob;
        tmp++;
    }
7712

7713
    if (tmp < *nparams && wr_total_times != -1) {
7714
        param = &params[tmp];
7715 7716 7717
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, wr_total_times) < 0)
7718 7719 7720
            goto endjob;
        tmp++;
    }
7721

7722
    if (tmp < *nparams && rd_total_times != -1) {
7723
        param = &params[tmp];
7724 7725 7726
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, rd_total_times) < 0)
7727 7728 7729
            goto endjob;
        tmp++;
    }
7730

7731
    if (tmp < *nparams && flush_total_times != -1) {
7732
        param = &params[tmp];
7733 7734 7735 7736
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG,
                                    flush_total_times) < 0)
7737 7738
            goto endjob;
        tmp++;
7739 7740
    }

7741 7742 7743 7744 7745
    /* Field 'errs' is meaningless for QEMU, won't set it. */

    ret = 0;
    *nparams = tmp;

7746 7747 7748 7749 7750 7751 7752 7753 7754 7755
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

7756
#ifdef __linux__
7757 7758 7759 7760 7761
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
7762 7763
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
7764
    int i;
7765
    int ret = -1;
7766

7767
    qemuDriverLock(driver);
7768
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
7769 7770
    qemuDriverUnlock(driver);

7771
    if (!vm) {
7772 7773
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7774 7775
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7776
        goto cleanup;
7777 7778
    }

D
Daniel P. Berrange 已提交
7779
    if (!virDomainObjIsActive(vm)) {
7780 7781
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
7782
        goto cleanup;
7783 7784 7785
    }

    /* Check the path is one of the domain's network interfaces. */
7786 7787
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
7788 7789 7790 7791
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
7792 7793
    }

7794
    if (ret == 0)
7795
        ret = linuxDomainInterfaceStats(path, stats);
7796
    else
7797 7798
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path, '%s' is not a known interface"), path);
7799

7800
cleanup:
7801 7802
    if (vm)
        virDomainObjUnlock(vm);
7803 7804
    return ret;
}
7805
#else
7806 7807 7808 7809
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
7810
{
7811 7812
    qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                    _("interface stats not implemented on this platform"));
7813 7814
    return -1;
}
7815
#endif
7816

7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830
static int
qemuDomainSetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    virDomainNetDefPtr net = NULL, persistentNet = NULL;
7831
    virNetDevBandwidthPtr bandwidth = NULL, newBandwidth = NULL;
7832 7833 7834

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849
    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;
7850

7851
    qemuDriverLock(driver);
7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        net = virDomainNetFind(vm->def, device);
        if (!net) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Can't find device %s"), device);
            goto cleanup;
        }
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        persistentNet = virDomainNetFind(persistentDef, device);
        if (!persistentNet) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Can't find device %s"), device);
            goto cleanup;
        }
    }

7881 7882 7883
    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
        (VIR_ALLOC(bandwidth->out) < 0)) {
7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905
        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;
        }
    }

7906
    /* average is mandatory, peak and burst are optional. So if no
7907
     * average is given, we free inbound/outbound here which causes
7908
     * inbound/outbound to not be set. */
7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923
    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
7924
         * here to prevent them from being lost. */
7925 7926
        if (bandwidth->in ||
            (net->bandwidth && net->bandwidth->in)) {
7927 7928 7929 7930
            if (VIR_ALLOC(newBandwidth->in) < 0) {
                virReportOOMError();
                goto cleanup;
            }
7931 7932 7933 7934 7935 7936 7937

            memcpy(newBandwidth->in,
                   bandwidth->in ? bandwidth->in : net->bandwidth->in,
                   sizeof(*newBandwidth->in));
        }
        if (bandwidth->out ||
            (net->bandwidth && net->bandwidth->out)) {
7938 7939 7940 7941
            if (VIR_ALLOC(newBandwidth->out) < 0) {
                virReportOOMError();
                goto cleanup;
            }
7942 7943 7944 7945

            memcpy(newBandwidth->out,
                   bandwidth->out ? bandwidth->out : net->bandwidth->out,
                   sizeof(*newBandwidth->out));
7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956
        }

        if (virNetDevBandwidthSet(net->ifname, newBandwidth) < 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot set bandwidth limits on %s"),
                            device);
            goto cleanup;
        }

        virNetDevBandwidthFree(net->bandwidth);
        net->bandwidth = newBandwidth;
E
Eric Blake 已提交
7957
        newBandwidth = NULL;
7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982
    }
    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;
            }
        }

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;
cleanup:
    virNetDevBandwidthFree(bandwidth);
7983
    virNetDevBandwidthFree(newBandwidth);
7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int *nparams,
                                 unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainDefPtr persistentDef = NULL;
    virDomainNetDefPtr net = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    qemuDriverLock(driver);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &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) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("Can't find device %s"), device);
        goto cleanup;
    }

    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
        switch(i) {
        case 0: /* inbound.average */
8047 8048 8049
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8050 8051 8052 8053 8054
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->average;
            break;
        case 1: /* inbound.peak */
8055 8056 8057
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8058 8059 8060 8061 8062
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->peak;
            break;
        case 2: /* inbound.burst */
8063 8064 8065
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8066 8067 8068 8069 8070
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->burst;
            break;
        case 3: /* outbound.average */
8071 8072 8073
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8074 8075 8076 8077 8078
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->average;
            break;
        case 4: /* outbound.peak */
8079 8080 8081
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8082 8083 8084 8085 8086
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->peak;
            break;
        case 5: /* outbound.burst */
8087 8088 8089
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112
                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)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

8113 8114 8115
static int
qemudDomainMemoryStats (virDomainPtr dom,
                        struct _virDomainMemoryStat *stats,
8116 8117
                        unsigned int nr_stats,
                        unsigned int flags)
8118 8119 8120
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
M
Martin Kletzander 已提交
8121
    int ret = -1;
8122

8123 8124
    virCheckFlags(0, -1);

8125 8126 8127 8128 8129 8130 8131
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

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

M
Martin Kletzander 已提交
8140 8141 8142 8143
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
    } else {
8144
        qemuDomainObjPrivatePtr priv = vm->privateData;
8145
        qemuDomainObjEnterMonitor(driver, vm);
8146
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
8147
        qemuDomainObjExitMonitor(driver, vm);
M
Martin Kletzander 已提交
8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160

        if (ret >= 0 && ret < nr_stats) {
            long rss;
            if (qemudGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) {
                qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("cannot get RSS for domain"));
            } else {
                stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
                stats[ret].val = rss;
                ret++;
            }

        }
8161 8162
    }

8163
    if (qemuDomainObjEndJob(driver, vm) == 0)
8164 8165
        vm = NULL;

8166 8167 8168 8169 8170 8171
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

8172 8173 8174 8175 8176
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
E
Eric Blake 已提交
8177
                      unsigned int flags)
8178
{
8179 8180
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8181 8182
    int fd = -1, ret = -1;
    const char *actual;
8183

E
Eric Blake 已提交
8184 8185
    virCheckFlags(0, -1);

8186
    qemuDriverLock(driver);
8187
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8188 8189
    qemuDriverUnlock(driver);

8190
    if (!vm) {
8191 8192
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8193 8194
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8195
        goto cleanup;
8196 8197 8198
    }

    if (!path || path[0] == '\0') {
8199 8200
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("NULL or empty path"));
8201
        goto cleanup;
8202 8203
    }

8204 8205 8206 8207 8208
    /* Check the path belongs to this domain.  */
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path '%s'"), path);
        goto cleanup;
8209
    }
8210
    path = actual;
8211

8212 8213 8214 8215 8216 8217 8218
    /* 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;
    }
8219

8220 8221 8222 8223 8224 8225 8226 8227 8228
    /* 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;
8229 8230
    }

8231 8232
    ret = 0;

8233
cleanup:
8234
    VIR_FORCE_CLOSE(fd);
8235 8236
    if (vm)
        virDomainObjUnlock(vm);
8237 8238 8239
    return ret;
}

R
Richard W.M. Jones 已提交
8240 8241 8242 8243 8244 8245
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
8246 8247
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8248
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
8249
    int fd = -1, ret = -1;
8250
    qemuDomainObjPrivatePtr priv;
R
Richard W.M. Jones 已提交
8251

8252 8253
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

8254
    qemuDriverLock(driver);
8255
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8256
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
8257 8258

    if (!vm) {
8259 8260
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8261 8262
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8263 8264 8265
        goto cleanup;
    }

8266
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
8267 8268
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
8269
        goto cleanup;
R
Richard W.M. Jones 已提交
8270 8271
    }

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

D
Daniel P. Berrange 已提交
8275
    if (!virDomainObjIsActive(vm)) {
8276 8277
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8278
        goto endjob;
R
Richard W.M. Jones 已提交
8279 8280
    }

8281
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", driver->cacheDir) < 0) {
8282
        virReportOOMError();
8283
        goto endjob;
8284 8285
    }

R
Richard W.M. Jones 已提交
8286 8287
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
8288 8289
        virReportSystemError(errno,
                             _("mkstemp(\"%s\") failed"), tmp);
8290
        goto endjob;
R
Richard W.M. Jones 已提交
8291 8292
    }

8293
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
8294

8295
    priv = vm->privateData;
8296
    qemuDomainObjEnterMonitor(driver, vm);
8297
    if (flags == VIR_MEMORY_VIRTUAL) {
8298
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
8299
            qemuDomainObjExitMonitor(driver, vm);
8300
            goto endjob;
8301
        }
8302
    } else {
8303
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
8304
            qemuDomainObjExitMonitor(driver, vm);
8305
            goto endjob;
8306
        }
R
Richard W.M. Jones 已提交
8307
    }
8308
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
8309 8310

    /* Read the memory file into buffer. */
8311
    if (saferead(fd, buffer, size) == (ssize_t) -1) {
8312 8313 8314
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
8315
        goto endjob;
R
Richard W.M. Jones 已提交
8316 8317 8318
    }

    ret = 0;
8319

8320
endjob:
8321
    if (qemuDomainObjEndJob(driver, vm) == 0)
8322
        vm = NULL;
8323

8324
cleanup:
8325
    VIR_FORCE_CLOSE(fd);
8326 8327
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
8328
    VIR_FREE(tmp);
8329 8330
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
8331 8332 8333
    return ret;
}

8334

8335 8336 8337 8338 8339 8340 8341 8342 8343
static int qemuDomainGetBlockInfo(virDomainPtr dom,
                                  const char *path,
                                  virDomainBlockInfoPtr info,
                                  unsigned int flags) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
8344
    virStorageFileMetadata *meta = NULL;
8345
    virDomainDiskDefPtr disk = NULL;
8346
    struct stat sb;
8347
    int i;
8348
    int format;
8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!path || path[0] == '\0') {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("NULL or empty path"));
        goto cleanup;
    }

    /* Check the path belongs to this domain. */
8370
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8371 8372 8373 8374
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path %s not assigned to domain"), path);
        goto cleanup;
    }
8375 8376 8377 8378 8379 8380 8381 8382
    disk = vm->def->disks[i];
    if (!disk->src) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("disk %s does not currently have a source assigned"),
                        path);
        goto cleanup;
    }
    path = disk->src;
8383 8384

    /* The path is correct, now try to open it and get its size. */
8385
    fd = open(path, O_RDONLY);
8386 8387 8388 8389 8390 8391 8392
    if (fd == -1) {
        virReportSystemError(errno,
                             _("failed to open path '%s'"), path);
        goto cleanup;
    }

    /* Probe for magic formats */
8393 8394 8395 8396 8397 8398 8399 8400
    if (disk->driverType) {
        if ((format = virStorageFileFormatTypeFromString(disk->driverType)) < 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("unknown disk format %s for %s"),
                            disk->driverType, disk->src);
            goto cleanup;
        }
    } else {
8401 8402 8403 8404 8405 8406 8407
        if (driver->allowDiskFormatProbing) {
            if ((format = virStorageFileProbeFormat(disk->src)) < 0)
                goto cleanup;
        } else {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no disk format for %s and probing is disabled"),
                            disk->src);
8408
            goto cleanup;
8409
        }
8410 8411
    }

8412 8413 8414 8415 8416
    if (VIR_ALLOC(meta) < 0) {
        virReportOOMError();
        goto cleanup;
    }

8417 8418
    if (virStorageFileGetMetadataFromFD(path, fd,
                                        format,
8419
                                        meta) < 0)
8420 8421 8422 8423 8424 8425 8426 8427 8428 8429
        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)) {
8430
#ifndef WIN32
8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443
        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.
         */
8444
        end = lseek(fd, 0, SEEK_END);
8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455
        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 */
8456 8457
    if (meta->capacity)
        info->capacity = meta->capacity;
8458

8459
    /* Set default value .. */
8460 8461
    info->allocation = info->physical;

8462 8463 8464
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
8465
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
8466
        format != VIR_STORAGE_FILE_RAW &&
8467 8468
        S_ISBLK(sb.st_mode) &&
        virDomainObjIsActive(vm)) {
8469
        qemuDomainObjPrivatePtr priv = vm->privateData;
8470

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

8474
        if (virDomainObjIsActive(vm)) {
8475
            qemuDomainObjEnterMonitor(driver, vm);
8476 8477 8478 8479
            ret = qemuMonitorGetBlockExtent(priv->mon,
                                            disk->info.alias,
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
8480
        } else {
8481
            ret = 0;
8482
        }
8483 8484 8485

        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
8486 8487 8488
    } else {
        ret = 0;
    }
8489 8490

cleanup:
8491
    virStorageFileFreeMetadata(meta);
8492
    VIR_FORCE_CLOSE(fd);
8493 8494 8495 8496 8497 8498
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


8499
static int
8500 8501 8502 8503
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
8504
{
8505 8506 8507
    struct qemud_driver *driver = conn->privateData;
    int ret;

8508
    qemuDriverLock(driver);
8509 8510 8511
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
8512
    qemuDriverUnlock(driver);
8513

8514
    return ret;
8515 8516
}

8517

8518
static int
8519 8520
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
8521
{
8522 8523 8524
    struct qemud_driver *driver = conn->privateData;
    int ret;

8525
    qemuDriverLock(driver);
8526 8527 8528
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
8529
    qemuDriverUnlock(driver);
8530

8531
    return ret;
8532 8533
}

8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546

static int
qemuDomainEventRegisterAny(virConnectPtr conn,
                           virDomainPtr dom,
                           int eventID,
                           virConnectDomainEventGenericCallback callback,
                           void *opaque,
                           virFreeCallback freecb)
{
    struct qemud_driver *driver = conn->privateData;
    int ret;

    qemuDriverLock(driver);
8547 8548 8549 8550
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
8551
        ret = -1;
8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565
    qemuDriverUnlock(driver);

    return ret;
}


static int
qemuDomainEventDeregisterAny(virConnectPtr conn,
                             int callbackID)
{
    struct qemud_driver *driver = conn->privateData;
    int ret;

    qemuDriverLock(driver);
8566 8567 8568
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
8569 8570 8571 8572 8573 8574
    qemuDriverUnlock(driver);

    return ret;
}


8575 8576 8577
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
8578

C
Chris Lalancette 已提交
8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593
/* 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
qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
                                virStreamPtr st,
                                unsigned long flags,
                                const char *dname,
                                unsigned long resource ATTRIBUTE_UNUSED,
                                const char *dom_xml)
{
    struct qemud_driver *driver = dconn->privateData;
    int ret = -1;
8594

8595
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
8596

8597 8598
    qemuDriverLock(driver);

C
Chris Lalancette 已提交
8599
    if (!dom_xml) {
8600 8601
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
8602 8603 8604
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
8605
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
8606 8607 8608 8609
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
8610 8611
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
8612 8613 8614
        goto cleanup;
    }

8615 8616 8617 8618 8619 8620 8621
    if (virLockManagerPluginUsesState(driver->lockManager)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot use migrate v2 protocol with lock manager %s"),
                        virLockManagerPluginGetName(driver->lockManager));
        goto cleanup;
    }

8622 8623 8624
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
                                     st, dname, dom_xml);
8625

C
Chris Lalancette 已提交
8626
cleanup:
8627
    qemuDriverUnlock(driver);
C
Chris Lalancette 已提交
8628 8629 8630
    return ret;
}

D
Daniel Veillard 已提交
8631 8632 8633 8634
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
8635
static int ATTRIBUTE_NONNULL (5)
D
Daniel Veillard 已提交
8636
qemudDomainMigratePrepare2 (virConnectPtr dconn,
8637 8638
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
D
Daniel Veillard 已提交
8639 8640
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
8641
                            unsigned long flags,
D
Daniel Veillard 已提交
8642 8643 8644 8645
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
8646
    struct qemud_driver *driver = dconn->privateData;
8647
    int ret = -1;
8648

8649
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
8650

8651
    *uri_out = NULL;
D
Daniel Veillard 已提交
8652

8653
    qemuDriverLock(driver);
8654 8655 8656 8657 8658 8659 8660 8661

    if (virLockManagerPluginUsesState(driver->lockManager)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot use migrate v2 protocol with lock manager %s"),
                        virLockManagerPluginGetName(driver->lockManager));
        goto cleanup;
    }

C
Chris Lalancette 已提交
8662 8663 8664 8665
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
8666 8667
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
8668 8669 8670
        goto cleanup;
    }

D
Daniel Veillard 已提交
8671
    if (!dom_xml) {
8672 8673
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
8674
        goto cleanup;
D
Daniel Veillard 已提交
8675 8676
    }

8677 8678 8679 8680
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
8681
    ret = qemuMigrationPrepareDirect(driver, dconn,
8682
                                     NULL, 0, NULL, NULL, /* No cookies */
8683 8684
                                     uri_in, uri_out,
                                     dname, dom_xml);
D
Daniel Veillard 已提交
8685

8686 8687 8688 8689
cleanup:
    qemuDriverUnlock(driver);
    return ret;
}
C
Chris Lalancette 已提交
8690

D
Daniel Veillard 已提交
8691

8692 8693 8694
/* Perform is the second step, and it runs on the source host. */
static int
qemudDomainMigratePerform (virDomainPtr dom,
8695 8696
                           const char *cookie,
                           int cookielen,
8697 8698 8699 8700 8701 8702 8703 8704
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
8705
    const char *dconnuri = NULL;
8706

8707
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
8708

8709
    qemuDriverLock(driver);
8710 8711 8712 8713 8714 8715 8716
    if (virLockManagerPluginUsesState(driver->lockManager)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot use migrate v2 protocol with lock manager %s"),
                        virLockManagerPluginGetName(driver->lockManager));
        goto cleanup;
    }

8717
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
8718
    if (!vm) {
8719 8720
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8721 8722
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8723
        goto cleanup;
D
Daniel Veillard 已提交
8724 8725
    }

8726 8727 8728 8729 8730
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

8731 8732 8733 8734 8735 8736
    /* 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
     */
8737
    ret = qemuMigrationPerform(driver, dom->conn, vm,
8738
                               NULL, dconnuri, uri, cookie, cookielen,
8739
                               NULL, NULL, /* No output cookies in v2 */
8740
                               flags, dname, resource, false);
8741

8742
cleanup:
8743
    qemuDriverUnlock(driver);
8744
    return ret;
D
Daniel Veillard 已提交
8745 8746
}

8747

D
Daniel Veillard 已提交
8748 8749 8750 8751 8752 8753 8754
/* Finish is the third and final step, and it runs on the destination host. */
static virDomainPtr
qemudDomainMigrateFinish2 (virConnectPtr dconn,
                           const char *dname,
                           const char *cookie ATTRIBUTE_UNUSED,
                           int cookielen ATTRIBUTE_UNUSED,
                           const char *uri ATTRIBUTE_UNUSED,
C
Chris Lalancette 已提交
8755
                           unsigned long flags,
D
Daniel Veillard 已提交
8756 8757
                           int retcode)
{
8758 8759 8760
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
8761

8762
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
8763

8764
    qemuDriverLock(driver);
8765
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
8766
    if (!vm) {
8767 8768
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
8769
        goto cleanup;
D
Daniel Veillard 已提交
8770 8771
    }

8772 8773 8774 8775
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
8776
    dom = qemuMigrationFinish(driver, dconn, vm,
8777
                              NULL, 0, NULL, NULL, /* No cookies */
8778
                              flags, retcode, false);
8779

8780
cleanup:
8781
    qemuDriverUnlock(driver);
8782
    return dom;
D
Daniel Veillard 已提交
8783 8784
}

8785

8786 8787 8788 8789 8790 8791
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
8792
                        const char *xmlin,
8793 8794 8795
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
8796
                        const char *dname,
8797 8798 8799 8800 8801 8802
                        unsigned long resource ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    char *xml = NULL;

8803
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cleanup;
    } else {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
            goto cleanup;
    }

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

8829 8830 8831 8832 8833 8834 8835
    /* Check if there is any ejected media.
     * We don't want to require them on the destination.
     */

    if (qemuDomainCheckEjectableMedia(driver, vm) < 0)
        goto endjob;

8836
    if (!(xml = qemuMigrationBegin(driver, vm, xmlin, dname,
8837 8838
                                   cookieout, cookieoutlen,
                                   flags)))
8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856
        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.
         */
        if (qemuMigrationJobContinue(vm) == 0) {
            vm = NULL;
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("domain disappeared"));
            VIR_FREE(xml);
            if (cookieout)
                VIR_FREE(*cookieout);
        }
    } else {
        goto endjob;
    }
8857 8858

cleanup:
8859 8860
    if (vm)
        virDomainObjUnlock(vm);
8861 8862
    qemuDriverUnlock(driver);
    return xml;
8863 8864 8865 8866 8867 8868 8869 8870 8871 8872

endjob:
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobFinish(driver, vm) == 0)
            vm = NULL;
    } else {
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    }
    goto cleanup;
8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890
}

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)
{
    struct qemud_driver *driver = dconn->privateData;
    int ret = -1;

8891
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937

    *uri_out = NULL;

    qemuDriverLock(driver);
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Tunnelled migration requested but invalid RPC method called"));
        goto cleanup;
    }

    if (!dom_xml) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
        goto cleanup;
    }

    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
                                     dname, dom_xml);

cleanup:
    qemuDriverUnlock(driver);
    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)
{
    struct qemud_driver *driver = dconn->privateData;
    int ret = -1;

8938
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969

    if (!dom_xml) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("tunnelled migration requested but NULL stream passed"));
        goto cleanup;
    }

    qemuDriverLock(driver);
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     st, dname, dom_xml);
    qemuDriverUnlock(driver);

cleanup:
    return ret;
}


static int
qemuDomainMigratePerform3(virDomainPtr dom,
8970
                          const char *xmlin,
8971 8972 8973 8974
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
8975
                          const char *dconnuri,
8976 8977 8978 8979 8980 8981 8982 8983 8984
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

8985
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

8997
    ret = qemuMigrationPerform(driver, dom->conn, vm, xmlin,
8998
                               dconnuri, uri, cookiein, cookieinlen,
8999
                               cookieout, cookieoutlen,
9000
                               flags, dname, resource, true);
9001 9002 9003 9004 9005 9006 9007

cleanup:
    qemuDriverUnlock(driver);
    return ret;
}


9008
static virDomainPtr
9009 9010 9011 9012 9013 9014
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
9015
                         const char *dconnuri ATTRIBUTE_UNUSED,
9016 9017
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
9018
                         int cancelled)
9019 9020 9021
{
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
9022
    virDomainPtr dom = NULL;
9023

9024
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9025 9026 9027 9028 9029 9030 9031 9032 9033

    qemuDriverLock(driver);
    vm = virDomainFindByName(&driver->domains, dname);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
        goto cleanup;
    }

9034 9035 9036 9037
    dom = qemuMigrationFinish(driver, dconn, vm,
                              cookiein, cookieinlen,
                              cookieout, cookieoutlen,
                              flags, cancelled, true);
9038 9039 9040

cleanup:
    qemuDriverUnlock(driver);
9041
    return dom;
9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053
}

static int
qemuDomainMigrateConfirm3(virDomainPtr domain,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned long flags,
                          int cancelled)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
9054
    enum qemuMigrationJobPhase phase;
9055

9056
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

9068
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
9069 9070
        goto cleanup;

9071 9072 9073 9074 9075 9076 9077
    if (cancelled)
        phase = QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED;
    else
        phase = QEMU_MIGRATION_PHASE_CONFIRM3;

    qemuMigrationJobStartPhase(driver, vm, phase);

9078 9079
    ret = qemuMigrationConfirm(driver, domain->conn, vm,
                               cookiein, cookieinlen,
9080 9081
                               flags, cancelled);

9082
    if (qemuMigrationJobFinish(driver, vm) == 0) {
9083 9084 9085 9086 9087
        vm = NULL;
    } else if (!virDomainObjIsActive(vm) &&
               (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE))) {
        if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
            virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm);
9088
        qemuDomainRemoveInactive(driver, vm);
9089 9090 9091
        vm = NULL;
    }

9092
cleanup:
9093 9094
    if (vm)
        virDomainObjUnlock(vm);
9095 9096 9097 9098 9099
    qemuDriverUnlock(driver);
    return ret;
}


9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115
static int
qemudNodeDeviceGetPciInfo (virNodeDevicePtr dev,
                           unsigned *domain,
                           unsigned *bus,
                           unsigned *slot,
                           unsigned *function)
{
    virNodeDeviceDefPtr def = NULL;
    virNodeDevCapsDefPtr cap;
    char *xml = NULL;
    int ret = -1;

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto out;

9116
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133
    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) {
9134 9135
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("device %s is not a PCI device"), dev->name);
9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
qemudNodeDeviceDettach (virNodeDevicePtr dev)
{
9149
    struct qemud_driver *driver = dev->conn->privateData;
9150 9151 9152
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;
9153
    bool in_inactive_list = false;
9154 9155 9156 9157

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

9158
    pci = pciGetDevice(domain, bus, slot, function);
9159 9160 9161
    if (!pci)
        return -1;

9162
    qemuDriverLock(driver);
9163 9164 9165 9166
    in_inactive_list = pciDeviceListFind(driver->inactivePciHostdevs, pci);

    if (pciDettachDevice(pci, driver->activePciHostdevs,
                         driver->inactivePciHostdevs) < 0)
9167 9168 9169 9170
        goto out;

    ret = 0;
out:
9171
    qemuDriverUnlock(driver);
9172 9173
    if (in_inactive_list)
        pciFreeDevice(pci);
9174 9175 9176 9177 9178 9179
    return ret;
}

static int
qemudNodeDeviceReAttach (virNodeDevicePtr dev)
{
9180
    struct qemud_driver *driver = dev->conn->privateData;
9181
    pciDevice *pci;
9182
    pciDevice *other;
9183 9184 9185 9186 9187 9188
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

9189
    pci = pciGetDevice(domain, bus, slot, function);
9190 9191 9192
    if (!pci)
        return -1;

9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206
    other = pciDeviceListFind(driver->activePciHostdevs, pci);
    if (other) {
        const char *other_name = pciDeviceGetUsedBy(other);

        if (other_name)
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            _("PCI device %s is still in use by domain %s"),
                            pciDeviceGetName(pci), other_name);
        else
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            _("PCI device %s is still in use"),
                            pciDeviceGetName(pci));
    }

9207 9208
    pciDeviceReAttachInit(pci);

9209
    qemuDriverLock(driver);
9210 9211
    if (pciReAttachDevice(pci, driver->activePciHostdevs,
                          driver->inactivePciHostdevs) < 0)
9212 9213 9214 9215
        goto out;

    ret = 0;
out:
9216
    qemuDriverUnlock(driver);
9217
    pciFreeDevice(pci);
9218 9219 9220 9221 9222 9223
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
9224
    struct qemud_driver *driver = dev->conn->privateData;
9225 9226 9227 9228 9229 9230 9231
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

9232
    pci = pciGetDevice(domain, bus, slot, function);
9233 9234 9235
    if (!pci)
        return -1;

9236 9237
    qemuDriverLock(driver);

9238 9239
    if (pciResetDevice(pci, driver->activePciHostdevs,
                       driver->inactivePciHostdevs) < 0)
9240 9241 9242 9243
        goto out;

    ret = 0;
out:
9244
    qemuDriverUnlock(driver);
9245
    pciFreeDevice(pci);
9246 9247 9248
    return ret;
}

9249 9250 9251
static int
qemuCPUCompare(virConnectPtr conn,
               const char *xmlDesc,
E
Eric Blake 已提交
9252
               unsigned int flags)
9253 9254 9255 9256
{
    struct qemud_driver *driver = conn->privateData;
    int ret = VIR_CPU_COMPARE_ERROR;

E
Eric Blake 已提交
9257 9258
    virCheckFlags(0, VIR_CPU_COMPARE_ERROR);

9259 9260 9261
    qemuDriverLock(driver);

    if (!driver->caps || !driver->caps->host.cpu) {
9262
        qemuReportError(VIR_ERR_OPERATION_INVALID,
9263
                        "%s", _("cannot get host CPU capabilities"));
E
Eric Blake 已提交
9264
    } else {
9265
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
E
Eric Blake 已提交
9266
    }
9267 9268 9269 9270 9271 9272

    qemuDriverUnlock(driver);

    return ret;
}

9273

9274 9275 9276 9277
static char *
qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED,
                const char **xmlCPUs,
                unsigned int ncpus,
E
Eric Blake 已提交
9278
                unsigned int flags)
9279 9280 9281
{
    char *cpu;

E
Eric Blake 已提交
9282 9283
    virCheckFlags(0, NULL);

9284 9285 9286 9287 9288
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0);

    return cpu;
}

9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310

static int qemuDomainGetJobInfo(virDomainPtr dom,
                                virDomainJobInfoPtr info) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    priv = vm->privateData;

    if (virDomainObjIsActive(vm)) {
9311
        if (priv->job.asyncJob) {
9312
            memcpy(info, &priv->job.info, sizeof(*info));
9313 9314 9315 9316 9317 9318

            /* 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
             */
9319
            if (virTimeMillisNow(&info->timeElapsed) < 0)
9320
                goto cleanup;
9321
            info->timeElapsed -= priv->job.start;
9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357
static int qemuDomainAbortJob(virDomainPtr dom) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

9358 9359
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
9360

9361
    if (!virDomainObjIsActive(vm)) {
9362 9363
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
9364
        goto endjob;
9365 9366
    }

9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380
    priv = vm->privateData;

    if (!priv->job.asyncJob) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("no job is active on the domain"));
        goto endjob;
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot abort incoming migration;"
                          " use virDomainDestroy instead"));
        goto endjob;
    }

    VIR_DEBUG("Cancelling job at client request");
9381
    qemuDomainObjEnterMonitor(driver, vm);
9382 9383 9384 9385 9386 9387
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
9388 9389 9390 9391 9392 9393 9394 9395

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


9396 9397 9398 9399 9400 9401 9402 9403 9404 9405
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

9406
    virCheckFlags(0, -1);
9407 9408 9409

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
9410
    qemuDriverUnlock(driver);
9411 9412 9413 9414 9415 9416

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9417
        return -1;
9418 9419
    }

9420 9421 9422
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

9423 9424 9425
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
9426
        goto endjob;
9427 9428 9429 9430
    }

    priv = vm->privateData;

9431
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
9432 9433
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not being migrated"));
9434
        goto endjob;
9435 9436
    }

9437
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
9438
    qemuDomainObjEnterMonitor(driver, vm);
9439 9440 9441 9442 9443 9444
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
9445 9446 9447 9448 9449 9450 9451

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465
static int
qemuDomainMigrateSetMaxSpeed(virDomainPtr dom,
                             unsigned long bandwidth,
                             unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
9466
    qemuDriverUnlock(driver);
9467 9468 9469 9470 9471 9472

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9473
        return -1;
9474 9475 9476
    }

    priv = vm->privateData;
9477 9478 9479
    if (virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
            goto cleanup;
9480

9481 9482 9483 9484 9485 9486
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
            goto endjob;
        }

9487 9488 9489 9490
        VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
        qemuDomainObjExitMonitor(driver, vm);
9491

9492 9493
        if (ret == 0)
            priv->migMaxBandwidth = bandwidth;
9494

9495
endjob:
9496 9497 9498 9499 9500 9501
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    } else {
        priv->migMaxBandwidth = bandwidth;
        ret = 0;
    }
9502 9503 9504 9505 9506 9507 9508

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

9509 9510 9511 9512 9513 9514 9515
static int
qemuDomainMigrateGetMaxSpeed(virDomainPtr dom,
                             unsigned long *bandwidth,
                             unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
9516
    qemuDomainObjPrivatePtr priv;
9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532
    int ret = -1;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

J
Jim Fehlig 已提交
9533 9534
    priv = vm->privateData;
    *bandwidth = priv->migMaxBandwidth;
9535 9536 9537 9538 9539 9540 9541 9542
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

C
Chris Lalancette 已提交
9543 9544 9545 9546 9547 9548 9549 9550 9551
static int qemuDomainSnapshotIsAllowed(virDomainObjPtr vm)
{
    int i;

    /* FIXME: we need to figure out what else here might succeed; in
     * particular, if it's a raw device but on LVM, we could probably make
     * that succeed as well
     */
    for (i = 0; i < vm->def->ndisks; i++) {
9552 9553 9554
        if ((vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_LUN) ||
            (vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
             STRNEQ_NULLABLE(vm->def->disks[i]->driverType, "qcow2"))) {
C
Chris Lalancette 已提交
9555
            qemuReportError(VIR_ERR_OPERATION_INVALID,
9556 9557
                            _("Disk '%s' does not support snapshotting"),
                            vm->def->disks[i]->src);
C
Chris Lalancette 已提交
9558 9559 9560 9561 9562 9563 9564
            return 0;
        }
    }

    return 1;
}

9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591
static int
qemuDomainSnapshotFSFreeze(struct qemud_driver *driver,
                           virDomainObjPtr vm) {
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int freezed;

    if (priv->agentError) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("QEMU guest agent is not "
                          "available due to an error"));
        return -1;
    }
    if (!priv->agent) {
        qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                        _("QEMU guest agent is not configured"));
        return -1;
    }

    qemuDomainObjEnterAgent(driver, vm);
    freezed = qemuAgentFSFreeze(priv->agent);
    qemuDomainObjExitAgent(driver, vm);

    return freezed;
}

static int
qemuDomainSnapshotFSThaw(struct qemud_driver *driver,
E
Eric Blake 已提交
9592 9593
                         virDomainObjPtr vm, bool report)
{
9594 9595
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int thawed;
E
Eric Blake 已提交
9596
    virErrorPtr err = NULL;
9597 9598

    if (priv->agentError) {
E
Eric Blake 已提交
9599 9600 9601 9602
        if (report)
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("QEMU guest agent is not "
                              "available due to an error"));
9603 9604 9605
        return -1;
    }
    if (!priv->agent) {
E
Eric Blake 已提交
9606 9607 9608
        if (report)
            qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                            _("QEMU guest agent is not configured"));
9609 9610 9611 9612
        return -1;
    }

    qemuDomainObjEnterAgent(driver, vm);
E
Eric Blake 已提交
9613 9614
    if (!report)
        err = virGetLastError();
9615
    thawed = qemuAgentFSThaw(priv->agent);
E
Eric Blake 已提交
9616 9617 9618 9619 9620 9621
    if (!report) {
        if (err)
            virResetError(err);
        else
            virResetLastError();
    }
9622 9623 9624 9625 9626
    qemuDomainObjExitAgent(driver, vm);

    return thawed;
}

9627 9628
/* The domain is expected to be locked and inactive. */
static int
E
Eric Blake 已提交
9629 9630
qemuDomainSnapshotCreateInactive(struct qemud_driver *driver,
                                 virDomainObjPtr vm,
9631 9632
                                 virDomainSnapshotObjPtr snap)
{
E
Eric Blake 已提交
9633
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
9634 9635
}

9636 9637
/* The domain is expected to be locked and active. */
static int
9638 9639
qemuDomainSnapshotCreateActive(virConnectPtr conn,
                               struct qemud_driver *driver,
9640
                               virDomainObjPtr *vmptr,
9641 9642
                               virDomainSnapshotObjPtr snap,
                               unsigned int flags)
9643 9644 9645
{
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
9646 9647
    bool resume = false;
    int ret = -1;
9648

9649
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
9650 9651
        return -1;

9652 9653 9654 9655 9656 9657
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }

J
Jiri Denemark 已提交
9658
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
9659 9660 9661 9662
        /* 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.
         */
9663 9664
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
9665 9666 9667 9668 9669 9670 9671 9672 9673 9674
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto cleanup;
        }
    }

9675
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9676 9677
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        virDomainEventPtr event;

        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
        qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
        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;
        if (event)
            qemuDomainEventQueue(driver, event);
    }
9696

9697 9698
cleanup:
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
9699
        qemuProcessStartCPUs(driver, vm, conn,
9700 9701
                             VIR_DOMAIN_RUNNING_UNPAUSED,
                             QEMU_ASYNC_JOB_NONE) < 0 &&
9702 9703 9704 9705 9706
        virGetLastError() == NULL) {
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("resuming after snapshot failed"));
    }

9707
endjob:
9708
    if (vm && qemuDomainObjEndJob(driver, vm) == 0) {
9709 9710
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
9711
        *vmptr = NULL;
9712 9713
        ret = -1;
    }
9714 9715 9716 9717

    return ret;
}

9718
static int
9719 9720
qemuDomainSnapshotDiskPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
                              bool allow_reuse)
9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772
{
    int ret = -1;
    int i;
    bool found = false;
    bool active = virDomainObjIsActive(vm);
    struct stat st;

    for (i = 0; i < def->ndisks; i++) {
        virDomainSnapshotDiskDefPtr disk = &def->disks[i];

        switch (disk->snapshot) {
        case VIR_DOMAIN_DISK_SNAPSHOT_INTERNAL:
            if (active) {
                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                _("active qemu domains require external disk "
                                  "snapshots; disk %s requested internal"),
                                disk->name);
                goto cleanup;
            }
            if (!vm->def->disks[i]->driverType ||
                STRNEQ(vm->def->disks[i]->driverType, "qcow2")) {
                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                _("internal snapshot for disk %s unsupported "
                                  "for storage type %s"),
                                disk->name,
                                NULLSTR(vm->def->disks[i]->driverType));
                goto cleanup;
            }
            found = true;
            break;

        case VIR_DOMAIN_DISK_SNAPSHOT_EXTERNAL:
            if (!disk->driverType) {
                if (!(disk->driverType = strdup("qcow2"))) {
                    virReportOOMError();
                    goto cleanup;
                }
            } else if (STRNEQ(disk->driverType, "qcow2")) {
                /* XXX We should also support QED */
                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                _("external snapshot format for disk %s "
                                  "is unsupported: %s"),
                                disk->name, disk->driverType);
                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;
                }
9773
            } else if (!(S_ISBLK(st.st_mode) || allow_reuse)) {
9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808
                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                _("external snapshot file for disk %s already "
                                  "exists and is not a block device: %s"),
                                disk->name, disk->file);
                goto cleanup;
            }
            found = true;
            break;

        case VIR_DOMAIN_DISK_SNAPSHOT_NO:
            break;

        case VIR_DOMAIN_DISK_SNAPSHOT_DEFAULT:
        default:
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("unexpected code path"));
            goto cleanup;
        }
    }

    if (!found) {
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("disk snapshots require at least one disk to be "
                          "selected for snapshot"));
        goto cleanup;
    }

    ret = 0;

cleanup:
    return ret;
}

/* The domain is expected to hold monitor lock.  */
static int
9809 9810
qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver,
                                         virDomainObjPtr vm,
9811
                                         virDomainSnapshotDiskDefPtr snap,
9812 9813
                                         virDomainDiskDefPtr disk,
                                         virDomainDiskDefPtr persistDisk)
9814 9815 9816 9817 9818
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *device = NULL;
    char *source = NULL;
    char *driverType = NULL;
9819 9820
    char *persistSource = NULL;
    char *persistDriverType = NULL;
9821
    int ret = -1;
9822 9823 9824 9825
    int fd = -1;
    char *origsrc = NULL;
    char *origdriver = NULL;
    bool need_unlink = false;
9826 9827 9828 9829 9830 9831 9832 9833 9834 9835

    if (snap->snapshot != VIR_DOMAIN_DISK_SNAPSHOT_EXTERNAL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("unexpected code path"));
        return -1;
    }

    if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
        !(source = strdup(snap->file)) ||
        (STRNEQ_NULLABLE(disk->driverType, "qcow2") &&
9836 9837 9838 9839 9840
         !(driverType = strdup("qcow2"))) ||
        (persistDisk &&
         (!(persistSource = strdup(source)) ||
          (STRNEQ_NULLABLE(persistDisk->driverType, "qcow2") &&
           !(persistDriverType = strdup("qcow2")))))) {
9841 9842 9843 9844
        virReportOOMError();
        goto cleanup;
    }

9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855
    /* create the stub file and set selinux labels; manipulate disk in
     * place, in a way that can be reverted on failure. */
    fd = qemuOpenFile(driver, source, O_WRONLY | O_TRUNC | O_CREAT,
                      &need_unlink, NULL);
    if (fd < 0)
        goto cleanup;
    VIR_FORCE_CLOSE(fd);

    origsrc = disk->src;
    disk->src = source;
    origdriver = disk->driverType;
9856
    disk->driverType = (char *) "raw"; /* Don't want to probe backing files */
9857 9858 9859

    if (virDomainLockDiskAttach(driver->lockManager, vm, disk) < 0)
        goto cleanup;
9860
    if (virSecurityManagerSetImageLabel(driver->securityManager, vm->def,
9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872
                                        disk) < 0) {
        if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
            VIR_WARN("Unable to release lock on %s", source);
        goto cleanup;
    }

    disk->src = origsrc;
    origsrc = NULL;
    disk->driverType = origdriver;
    origdriver = NULL;

    /* create the actual snapshot */
9873 9874 9875 9876 9877 9878
    ret = qemuMonitorDiskSnapshot(priv->mon, device, source);
    virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
    if (ret < 0)
        goto cleanup;

    /* Update vm in place to match changes.  */
9879
    need_unlink = false;
9880 9881 9882 9883 9884 9885 9886 9887
    VIR_FREE(disk->src);
    disk->src = source;
    source = NULL;
    if (driverType) {
        VIR_FREE(disk->driverType);
        disk->driverType = driverType;
        driverType = NULL;
    }
9888 9889 9890 9891 9892 9893 9894 9895 9896 9897
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
        if (persistDriverType) {
            VIR_FREE(persistDisk->driverType);
            persistDisk->driverType = persistDriverType;
            persistDriverType = NULL;
        }
    }
9898 9899

cleanup:
9900 9901 9902 9903 9904 9905
    if (origsrc) {
        disk->src = origsrc;
        disk->driverType = origdriver;
    }
    if (need_unlink && unlink(source))
        VIR_WARN("unable to unlink just-created %s", source);
9906 9907 9908
    VIR_FREE(device);
    VIR_FREE(source);
    VIR_FREE(driverType);
9909 9910
    VIR_FREE(persistSource);
    VIR_FREE(persistDriverType);
9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925
    return ret;
}

/* The domain is expected to be locked and active. */
static int
qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
                                   struct qemud_driver *driver,
                                   virDomainObjPtr *vmptr,
                                   virDomainSnapshotObjPtr snap,
                                   unsigned int flags)
{
    virDomainObjPtr vm = *vmptr;
    bool resume = false;
    int ret = -1;
    int i;
9926
    bool persist = false;
E
Eric Blake 已提交
9927
    int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
9928 9929 9930 9931

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        return -1;

9932 9933 9934 9935 9936 9937
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }

E
Eric Blake 已提交
9938 9939 9940 9941 9942 9943
    /* 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) {
        if (qemuDomainSnapshotFSFreeze(driver, vm) < 0) {
9944
            /* helper reported the error */
E
Eric Blake 已提交
9945
            thaw = -1;
9946
            goto endjob;
E
Eric Blake 已提交
9947 9948
        } else {
            thaw = 1;
9949
        }
E
Eric Blake 已提交
9950
    }
9951

E
Eric Blake 已提交
9952
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977
        /* In qemu, snapshot_blkdev on a single disk will pause cpus,
         * but this confuses libvirt since notifications are not given
         * when qemu resumes.  And for multiple disks, libvirt must
         * pause externally to get all snapshots to be at the same
         * point in time.  For simplicitly, we always pause ourselves
         * rather than relying on qemu doing pause.
         */
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto cleanup;
        }
    }

    /* No way to roll back if first disk succeeds but later disks
     * fail.  Based on earlier qemuDomainSnapshotDiskPrepare, all
     * disks in this list are now either SNAPSHOT_NO, or
     * SNAPSHOT_EXTERNAL with a valid file name and qcow2 format.  */
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    for (i = 0; i < snap->def->ndisks; i++) {
9978 9979
        virDomainDiskDefPtr persistDisk = NULL;

9980 9981
        if (snap->def->disks[i].snapshot == VIR_DOMAIN_DISK_SNAPSHOT_NO)
            continue;
9982 9983 9984 9985 9986 9987 9988 9989 9990
        if (vm->newDef) {
            int indx = virDomainDiskIndexByName(vm->newDef,
                                                vm->def->disks[i]->dst,
                                                false);
            if (indx >= 0) {
                persistDisk = vm->newDef->disks[indx];
                persist = true;
            }
        }
9991

9992
        ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm,
9993
                                                       &snap->def->disks[i],
9994 9995
                                                       vm->def->disks[i],
                                                       persistDisk);
9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013
        if (ret < 0)
            break;
    }
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        virDomainEventPtr event;

        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
        qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
        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;
E
Eric Blake 已提交
10014
        thaw = 0;
10015 10016 10017 10018 10019 10020
        vm = NULL;
        if (event)
            qemuDomainEventQueue(driver, event);
    }

cleanup:
10021 10022 10023 10024 10025 10026 10027 10028 10029
    if (resume && virDomainObjIsActive(vm)) {
        if (qemuProcessStartCPUs(driver, vm, conn,
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0 &&
            virGetLastError() == NULL) {
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("resuming after snapshot failed"));
            goto endjob;
        }
10030 10031 10032
    }

    if (vm) {
10033 10034 10035
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0 ||
            (persist &&
             virDomainSaveConfig(driver->configDir, vm->newDef) < 0))
10036
            ret = -1;
10037 10038 10039
    }

endjob:
E
Eric Blake 已提交
10040 10041 10042 10043 10044 10045
    if (vm && thaw != 0 &&
        qemuDomainSnapshotFSThaw(driver, vm, thaw > 0) < 0) {
        /* helper reported the error, if it was needed */
        if (thaw > 0)
            ret = -1;
    }
10046
    if (vm && (qemuDomainObjEndJob(driver, vm) == 0)) {
10047 10048 10049 10050 10051 10052 10053 10054 10055
            /* Only possible if a transient vm quit while our locks were down,
             * in which case we don't want to save snapshot metadata.  */
            *vmptr = NULL;
            ret = -1;
    }

    return ret;
}

10056 10057 10058 10059
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
                            const char *xmlDesc,
                            unsigned int flags)
C
Chris Lalancette 已提交
10060 10061 10062
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
10063
    char *xml = NULL;
C
Chris Lalancette 已提交
10064 10065 10066
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
10067
    virDomainSnapshotDefPtr def = NULL;
10068 10069
    bool update_current = true;
    unsigned int parse_flags = 0;
10070
    virDomainSnapshotObjPtr other = NULL;
C
Chris Lalancette 已提交
10071

10072 10073
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
10074
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
10075
                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
10076
                  VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
10077 10078 10079 10080 10081 10082 10083 10084 10085
                  VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE, NULL);

    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
        !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("quiesce requires disk-only"));
        return NULL;
    }
10086 10087 10088 10089 10090 10091 10092

    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;
10093 10094
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
10095

C
Chris Lalancette 已提交
10096 10097 10098 10099 10100 10101 10102 10103 10104
    qemuDriverLock(driver);
    virUUIDFormat(domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

10105 10106 10107 10108 10109
    if (qemuProcessAutoDestroyActive(driver, vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is marked for auto destroy"));
        goto cleanup;
    }
10110 10111 10112 10113 10114
    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot halt after transient domain snapshot"));
        goto cleanup;
    }
10115

10116 10117 10118
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
10119 10120
        goto cleanup;

10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* Prevent circular chains */
        if (def->parent) {
            if (STREQ(def->name, def->parent)) {
                qemuReportError(VIR_ERR_INVALID_ARG,
                                _("cannot set snapshot %s as its own parent"),
                                def->name);
                goto cleanup;
            }
            other = virDomainSnapshotFindByName(&vm->snapshots, def->parent);
            if (!other) {
                qemuReportError(VIR_ERR_INVALID_ARG,
                                _("parent %s for snapshot %s not found"),
                                def->parent, def->name);
                goto cleanup;
            }
            while (other->def->parent) {
                if (STREQ(other->def->parent, def->name)) {
                    qemuReportError(VIR_ERR_INVALID_ARG,
                                    _("parent %s would create cycle to %s"),
                                    other->def->name, def->name);
                    goto cleanup;
                }
                other = virDomainSnapshotFindByName(&vm->snapshots,
                                                    other->def->parent);
                if (!other) {
                    VIR_WARN("snapshots are inconsistent for %s",
                             vm->def->name);
                    break;
                }
            }
        }

        /* Check that any replacement is compatible */
10155 10156 10157 10158 10159 10160 10161
        if (def->dom &&
            memcmp(def->dom->uuid, domain->uuid, VIR_UUID_BUFLEN)) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("definition for snapshot %s must use uuid %s"),
                            def->name, uuidstr);
            goto cleanup;
        }
10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173
        other = virDomainSnapshotFindByName(&vm->snapshots, def->name);
        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)) {
                qemuReportError(VIR_ERR_INVALID_ARG,
                                _("cannot change between online and offline "
                                  "snapshot state in snapshot %s"),
                                def->name);
                goto cleanup;
            }
10174 10175 10176 10177 10178 10179 10180 10181
            if ((other->def->state == VIR_DOMAIN_DISK_SNAPSHOT) !=
                (def->state == VIR_DOMAIN_DISK_SNAPSHOT)) {
                qemuReportError(VIR_ERR_INVALID_ARG,
                                _("cannot change between disk snapshot and "
                                  "system checkpoint in snapshot %s"),
                                def->name);
                goto cleanup;
            }
10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192
            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;
                }
            }
10193 10194 10195 10196
            if (other == vm->current_snapshot) {
                update_current = true;
                vm->current_snapshot = NULL;
            }
10197 10198 10199 10200 10201 10202
            /* Drop and rebuild the parent relationship, but keep all
             * child relations by reusing snap.  */
            virDomainSnapshotDropParent(&vm->snapshots, other);
            virDomainSnapshotDefFree(other->def);
            other->def = NULL;
            snap = other;
10203
        }
10204 10205 10206 10207 10208 10209
        if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && def->dom) {
            if (virDomainSnapshotAlignDisks(def,
                                            VIR_DOMAIN_DISK_SNAPSHOT_EXTERNAL,
                                            false) < 0)
                goto cleanup;
        }
10210 10211 10212
    } else {
        /* Easiest way to clone inactive portion of vm->def is via
         * conversion in and back out of xml.  */
10213
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true)) ||
10214 10215 10216 10217 10218
            !(def->dom = virDomainDefParseString(driver->caps, xml,
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE)))
            goto cleanup;

10219
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
10220 10221 10222
            bool allow_reuse;

            allow_reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
10223 10224 10225 10226
            if (virDomainSnapshotAlignDisks(def,
                                            VIR_DOMAIN_DISK_SNAPSHOT_EXTERNAL,
                                            false) < 0)
                goto cleanup;
10227
            if (qemuDomainSnapshotDiskPrepare(vm, def, allow_reuse) < 0)
10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243
                goto cleanup;
            def->state = VIR_DOMAIN_DISK_SNAPSHOT;
        } else {
            /* In a perfect world, we would allow qemu to tell us this.
             * The problem is that qemu only does this check
             * device-by-device; so if you had a domain that booted from a
             * large qcow2 device, but had a secondary raw device
             * attached, you wouldn't find out that you can't snapshot
             * your guest until *after* it had spent the time to snapshot
             * the boot device.  This is probably a bug in qemu, but we'll
             * work around it here for now.
             */
            if (!qemuDomainSnapshotIsAllowed(vm))
                goto cleanup;
            def->state = virDomainObjGetState(vm, NULL);
        }
10244 10245
    }

10246 10247 10248
    if (snap)
        snap->def = def;
    else if (!(snap = virDomainSnapshotAssignDef(&vm->snapshots, def)))
C
Chris Lalancette 已提交
10249
        goto cleanup;
10250
    def = NULL;
C
Chris Lalancette 已提交
10251

10252 10253
    if (update_current)
        snap->def->current = true;
10254
    if (vm->current_snapshot) {
10255 10256 10257 10258 10259 10260
        if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
            snap->def->parent = strdup(vm->current_snapshot->def->name);
            if (snap->def->parent == NULL) {
                virReportOOMError();
                goto cleanup;
            }
10261
        }
10262
        if (update_current) {
10263 10264 10265 10266 10267 10268
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                                driver->snapshotDir) < 0)
                goto cleanup;
            vm->current_snapshot = NULL;
        }
10269
    }
10270

C
Chris Lalancette 已提交
10271
    /* actually do the snapshot */
10272 10273
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* XXX Should we validate that the redefined snapshot even
10274 10275
         * makes sense, such as checking that qemu-img recognizes the
         * snapshot name in at least one of the domain's disks?  */
10276 10277 10278 10279 10280 10281 10282 10283 10284 10285
    } else if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                            _("disk snapshots of inactive domains not "
                              "implemented yet"));
            goto cleanup;
        }
        if (qemuDomainSnapshotCreateDiskActive(domain->conn, driver,
                                               &vm, snap, flags) < 0)
            goto cleanup;
10286
    } else if (!virDomainObjIsActive(vm)) {
E
Eric Blake 已提交
10287
        if (qemuDomainSnapshotCreateInactive(driver, vm, snap) < 0)
C
Chris Lalancette 已提交
10288
            goto cleanup;
E
Eric Blake 已提交
10289
    } else {
10290
        if (qemuDomainSnapshotCreateActive(domain->conn, driver,
10291
                                           &vm, snap, flags) < 0)
10292
            goto cleanup;
C
Chris Lalancette 已提交
10293 10294
    }

10295
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
10296 10297 10298 10299 10300 10301
     * 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:
10302
    if (vm) {
10303
        if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
10304
            if (qemuDomainSnapshotWriteMetadata(vm, snap,
10305
                                                driver->snapshotDir) < 0) {
10306 10307
                VIR_WARN("unable to save metadata for snapshot %s",
                         snap->def->name);
10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323
            } else {
                if (update_current)
                    vm->current_snapshot = snap;
                if (snap->def->parent) {
                    other = virDomainSnapshotFindByName(&vm->snapshots,
                                                        snap->def->parent);
                    snap->parent = other;
                    other->nchildren++;
                    snap->sibling = other->first_child;
                    other->first_child = snap;
                } else {
                    vm->snapshots.nroots++;
                    snap->sibling = vm->snapshots.first_root;
                    vm->snapshots.first_root = snap;
                }
            }
10324
        } else if (snap) {
10325
            virDomainSnapshotObjListRemove(&vm->snapshots, snap);
10326
        }
C
Chris Lalancette 已提交
10327
        virDomainObjUnlock(vm);
10328 10329
    }
    virDomainSnapshotDefFree(def);
10330
    VIR_FREE(xml);
C
Chris Lalancette 已提交
10331 10332 10333 10334 10335 10336
    qemuDriverUnlock(driver);
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
10337
                                       unsigned int flags)
C
Chris Lalancette 已提交
10338 10339 10340 10341 10342
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

10343
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
10344 10345
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
10346

C
Chris Lalancette 已提交
10347 10348 10349 10350 10351 10352 10353 10354 10355 10356
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

10357 10358
    n = virDomainSnapshotObjListGetNames(&vm->snapshots, names, nameslen,
                                         flags);
C
Chris Lalancette 已提交
10359 10360 10361 10362 10363 10364 10365 10366 10367

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return n;
}

static int qemuDomainSnapshotNum(virDomainPtr domain,
10368
                                 unsigned int flags)
C
Chris Lalancette 已提交
10369 10370 10371 10372 10373
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

10374
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
10375 10376
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
10377

C
Chris Lalancette 已提交
10378 10379 10380 10381 10382 10383 10384 10385 10386 10387
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

10388 10389 10390 10391
    /* All qemu snapshots have libvirt metadata, so
     * VIR_DOMAIN_SNAPSHOT_LIST_METADATA makes no difference to our
     * answer.  */

10392
    n = virDomainSnapshotObjListNum(&vm->snapshots, flags);
C
Chris Lalancette 已提交
10393 10394 10395 10396 10397 10398 10399 10400

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return n;
}

10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412
static int
qemuDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
                                    char **names,
                                    int nameslen,
                                    unsigned int flags)
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
10413 10414
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(snapshot->domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

E
Eric Blake 已提交
10434
    n = virDomainSnapshotObjListGetNamesFrom(snap, names, nameslen, flags);
10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return n;
}

static int
qemuDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
10453 10454
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA |
                  VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, -1);
10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(snapshot->domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

    /* All qemu snapshots have libvirt metadata, so
     * VIR_DOMAIN_SNAPSHOT_LIST_METADATA makes no difference to our
     * answer.  */

E
Eric Blake 已提交
10478
    n = virDomainSnapshotObjListNumFrom(snap, flags);
10479 10480 10481 10482 10483 10484 10485 10486

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return n;
}

C
Chris Lalancette 已提交
10487 10488
static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
10489
                                                           unsigned int flags)
C
Chris Lalancette 已提交
10490 10491 10492 10493 10494 10495
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

10496 10497
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no snapshot with matching name '%s'"), name);
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return snapshot;
}

static int qemuDomainHasCurrentSnapshot(virDomainPtr domain,
10525
                                        unsigned int flags)
C
Chris Lalancette 已提交
10526 10527 10528 10529 10530
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

10531 10532
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    ret = (vm->current_snapshot != NULL);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596
static virDomainSnapshotPtr
qemuDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(snapshot->domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

    if (!snap->def->parent) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("snapshot '%s' does not have a parent"),
                        snap->def->name);
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return parent;
}

C
Chris Lalancette 已提交
10597
static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
10598
                                                      unsigned int flags)
C
Chris Lalancette 已提交
10599 10600 10601 10602 10603
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

10604 10605
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!vm->current_snapshot) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                        _("the domain does not have a current snapshot"));
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return snapshot;
}

10631 10632
static char *qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                                          unsigned int flags)
C
Chris Lalancette 已提交
10633 10634 10635 10636 10637 10638 10639
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

10640
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
10641

C
Chris Lalancette 已提交
10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658
    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

10659
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
10660 10661 10662 10663 10664 10665 10666 10667

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return xml;
}

10668 10669
/* The domain is expected to be locked and inactive. */
static int
E
Eric Blake 已提交
10670 10671
qemuDomainSnapshotRevertInactive(struct qemud_driver *driver,
                                 virDomainObjPtr vm,
10672 10673 10674
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
10675
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
10676 10677 10678
    return ret > 0 ? -1 : ret;
}

C
Chris Lalancette 已提交
10679
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
10680
                                      unsigned int flags)
C
Chris Lalancette 已提交
10681 10682 10683 10684 10685 10686 10687
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainEventPtr event = NULL;
10688
    virDomainEventPtr event2 = NULL;
10689
    int detail;
C
Chris Lalancette 已提交
10690 10691
    qemuDomainObjPrivatePtr priv;
    int rc;
10692
    virDomainDefPtr config = NULL;
C
Chris Lalancette 已提交
10693

10694
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
10695 10696
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
10697

10698 10699 10700 10701 10702 10703 10704 10705 10706 10707
    /* 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
10708 10709
     * Also, several transitions occur even if we fail partway through,
     * and use of FORCE can cause multiple transitions.
10710 10711
     */

C
Chris Lalancette 已提交
10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728
    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

10729 10730 10731 10732 10733 10734 10735 10736 10737 10738
    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) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("transient domain needs to request run or pause "
                          "to revert to inactive snapshot"));
        goto cleanup;
    }
10739 10740 10741 10742 10743 10744
    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("revert to external disk snapshot not supported "
                          "yet"));
        goto cleanup;
    }
10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762
    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
        if (!snap->def->dom) {
            qemuReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                            _("snapshot '%s' lacks domain '%s' rollback info"),
                            snap->def->name, vm->def->name);
            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))) {
            qemuReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                            _("must respawn qemu to start inactive snapshot"));
            goto cleanup;
        }
    }

10763

10764 10765 10766 10767 10768 10769 10770 10771 10772 10773
    if (vm->current_snapshot) {
        vm->current_snapshot->def->current = false;
        if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                            driver->snapshotDir) < 0)
            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?  */
    }

10774 10775 10776 10777 10778
    /* Prepare to copy the snapshot inactive xml as the config of this
     * domain.  Easiest way is by a round trip through xml.
     *
     * XXX Should domain snapshots track live xml rather
     * than inactive xml?  */
10779
    snap->def->current = true;
10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792
    if (snap->def->dom) {
        char *xml;
        if (!(xml = virDomainDefFormat(snap->def->dom,
                                       (VIR_DOMAIN_XML_INACTIVE |
                                        VIR_DOMAIN_XML_SECURE))))
            goto cleanup;
        config = virDomainDefParseString(driver->caps, xml,
                                         QEMU_EXPECTED_VIRT_TYPES,
                                         VIR_DOMAIN_XML_INACTIVE);
        VIR_FREE(xml);
        if (!config)
            goto cleanup;
    }
C
Chris Lalancette 已提交
10793

10794
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
10795 10796 10797 10798
        goto cleanup;

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {
10799 10800 10801 10802 10803 10804 10805 10806 10807
        /* 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 已提交
10808
        if (virDomainObjIsActive(vm)) {
10809
            /* Transitions 5, 6, 8, 9 */
10810 10811
            /* Check for ABI compatibility.  */
            if (config && !virDomainDefCheckABIStability(vm->def, config)) {
10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831
                virErrorPtr err = virGetLastError();

                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
                    /* Re-spawn error using correct category. */
                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
                        qemuReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                                        err->str2);
                    goto endjob;
                }
                virResetError(err);
                qemuProcessStop(driver, vm, 0,
                                VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
                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;
10832 10833
            }

C
Chris Lalancette 已提交
10834
            priv = vm->privateData;
10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854
            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)) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                    _("guest unexpectedly quit"));
                    goto endjob;
                }
            }
10855
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
10856 10857
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
10858 10859 10860
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
10861
                goto endjob;
10862
            }
10863 10864
            if (config)
                virDomainObjAssignDef(vm, config, false);
E
Eric Blake 已提交
10865
        } else {
10866
            /* Transitions 2, 3 */
10867
        load:
10868
            was_stopped = true;
10869 10870 10871
            if (config)
                virDomainObjAssignDef(vm, config, false);

10872
            rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
10873
                                  false, true, false, -1, NULL, snap,
10874
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE);
10875
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
10876 10877 10878 10879
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
10880
            if (rc < 0)
10881
                goto endjob;
C
Chris Lalancette 已提交
10882 10883
        }

10884
        /* Touch up domain state.  */
10885 10886 10887
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907
            /* 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)) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("guest unexpectedly quit"));
                goto endjob;
            }
            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
                                      QEMU_ASYNC_JOB_NONE);
H
Hu Tao 已提交
10908
            if (rc < 0)
10909
                goto endjob;
10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924
            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 已提交
10925
        }
E
Eric Blake 已提交
10926
    } else {
10927
        /* Transitions 1, 4, 7 */
10928 10929 10930
        /* 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 已提交
10931 10932 10933
         */

        if (virDomainObjIsActive(vm)) {
10934
            /* Transitions 4, 7 */
J
Jiri Denemark 已提交
10935
            qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
10936
            virDomainAuditStop(vm, "from-snapshot");
10937
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
C
Chris Lalancette 已提交
10938 10939
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
10940
                                             detail);
10941 10942
        }

E
Eric Blake 已提交
10943
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
10944
            if (!vm->persistent) {
10945
                if (qemuDomainObjEndJob(driver, vm) > 0)
10946
                    qemuDomainRemoveInactive(driver, vm);
10947
                vm = NULL;
10948
                goto cleanup;
10949
            }
10950
            goto endjob;
C
Chris Lalancette 已提交
10951
        }
10952 10953
        if (config)
            virDomainObjAssignDef(vm, config, false);
10954

10955 10956 10957 10958 10959 10960 10961 10962
        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;

            if (event)
                qemuDomainEventQueue(driver, event);
            rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
10963
                                  false, paused, false, -1, NULL, NULL,
10964
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE);
10965 10966 10967 10968
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
                    if (qemuDomainObjEndJob(driver, vm) > 0)
10969
                        qemuDomainRemoveInactive(driver, vm);
10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985
                    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 已提交
10986 10987 10988 10989
    }

    ret = 0;

10990
endjob:
10991
    if (vm && qemuDomainObjEndJob(driver, vm) == 0)
C
Chris Lalancette 已提交
10992 10993
        vm = NULL;

10994
cleanup:
10995 10996 10997 10998 10999 11000 11001 11002 11003
    if (vm && ret == 0) {
        if (qemuDomainSnapshotWriteMetadata(vm, snap,
                                            driver->snapshotDir) < 0)
            ret = -1;
        else
            vm->current_snapshot = snap;
    } else if (snap) {
        snap->def->current = false;
    }
11004
    if (event) {
C
Chris Lalancette 已提交
11005
        qemuDomainEventQueue(driver, event);
11006 11007 11008
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
11009 11010 11011 11012 11013 11014 11015
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    return ret;
}

11016 11017
struct snap_reparent {
    struct qemud_driver *driver;
11018
    virDomainSnapshotObjPtr parent;
11019 11020
    virDomainObjPtr vm;
    int err;
11021
    virDomainSnapshotObjPtr last;
11022 11023 11024 11025
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
11026
                                   const void *name ATTRIBUTE_UNUSED,
11027 11028 11029 11030 11031 11032 11033 11034 11035
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    struct snap_reparent *rep = data;

    if (rep->err < 0) {
        return;
    }

11036
    VIR_FREE(snap->def->parent);
11037
    snap->parent = rep->parent;
11038

11039 11040
    if (rep->parent) {
        snap->def->parent = strdup(rep->parent->def->name);
11041

11042 11043 11044 11045
        if (snap->def->parent == NULL) {
            virReportOOMError();
            rep->err = -1;
            return;
11046 11047
        }
    }
11048

11049 11050 11051
    if (!snap->sibling)
        rep->last = snap;

11052 11053
    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
                                               rep->driver->snapshotDir);
11054 11055
}

C
Chris Lalancette 已提交
11056 11057 11058 11059 11060 11061 11062 11063
static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                                    unsigned int flags)
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
11064
    struct qemu_snap_remove rem;
11065
    struct snap_reparent rep;
11066
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
11067
    int external = 0;
C
Chris Lalancette 已提交
11068

11069
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
11070 11071
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
11072

C
Chris Lalancette 已提交
11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089
    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

11090 11091 11092 11093 11094
    if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)) {
        if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
            snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT)
            external++;
        if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
E
Eric Blake 已提交
11095
            virDomainSnapshotForEachDescendant(snap,
11096 11097 11098 11099 11100 11101 11102 11103 11104 11105
                                               qemuDomainSnapshotCountExternal,
                                               &external);
        if (external) {
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                            _("deletion of %d external disk snapshots not "
                              "supported yet"), external);
            goto cleanup;
        }
    }

11106
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
11107 11108
        goto cleanup;

11109 11110
    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
C
Chris Lalancette 已提交
11111 11112
        rem.driver = driver;
        rem.vm = vm;
11113
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
11114
        rem.err = 0;
11115
        rem.current = false;
E
Eric Blake 已提交
11116
        virDomainSnapshotForEachDescendant(snap,
E
Eric Blake 已提交
11117
                                           qemuDomainSnapshotDiscardAll,
11118
                                           &rem);
C
Chris Lalancette 已提交
11119
        if (rem.err < 0)
11120
            goto endjob;
11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132
        if (rem.current) {
            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
                snap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, snap,
                                                    driver->snapshotDir) < 0) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    _("failed to set snapshot '%s' as current"),
                                    snap->def->name);
                    snap->def->current = false;
                    goto endjob;
                }
            }
11133
            vm->current_snapshot = snap;
11134
        }
11135
    } else if (snap->nchildren) {
11136
        rep.driver = driver;
11137
        rep.parent = snap->parent;
11138 11139
        rep.vm = vm;
        rep.err = 0;
11140
        rep.last = NULL;
E
Eric Blake 已提交
11141
        virDomainSnapshotForEachChild(snap,
11142 11143
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
11144 11145
        if (rep.err < 0)
            goto endjob;
11146 11147 11148 11149 11150 11151 11152 11153 11154 11155
        /* Can't modify siblings during ForEachChild, so do it now.  */
        if (snap->parent) {
            snap->parent->nchildren += snap->nchildren;
            rep.last->sibling = snap->parent->first_child;
            snap->parent->first_child = snap->first_child;
        } else {
            vm->snapshots.nroots += snap->nchildren;
            rep.last->sibling = vm->snapshots.first_root;
            vm->snapshots.first_root = snap->first_child;
        }
C
Chris Lalancette 已提交
11156 11157
    }

11158 11159 11160
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
        snap->nchildren = 0;
        snap->first_child = NULL;
11161
        ret = 0;
11162 11163
    } else {
        virDomainSnapshotDropParent(&vm->snapshots, snap);
11164
        ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
11165
    }
C
Chris Lalancette 已提交
11166

11167
endjob:
11168
    if (qemuDomainObjEndJob(driver, vm) == 0)
11169 11170
        vm = NULL;

C
Chris Lalancette 已提交
11171 11172 11173 11174 11175 11176
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
11177

11178 11179 11180 11181 11182 11183 11184
static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
                                    char **result, unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
11185
    bool hmp;
11186

11187
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

11205 11206 11207 11208 11209 11210 11211 11212 11213
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

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

11214 11215
    priv = vm->privateData;

11216
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
11217

11218 11219
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

11220
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
11221
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
11222
    qemuDomainObjExitMonitorWithDriver(driver, vm);
11223 11224

endjob:
11225
    if (qemuDomainObjEndJob(driver, vm) == 0) {
11226 11227 11228 11229 11230 11231 11232 11233 11234 11235
        vm = NULL;
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

11236

11237
static virDomainPtr qemuDomainAttach(virConnectPtr conn,
11238
                                     unsigned int pid_value,
11239 11240 11241 11242 11243 11244 11245 11246
                                     unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
11247
    pid_t pid = pid_value;
11248
    char *pidfile = NULL;
11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259

    virCheckFlags(0, NULL);

    qemuDriverLock(driver);

    if (!(def = qemuParseCommandLinePid(driver->caps, pid,
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

    if (!monConfig) {
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11260
                        _("No monitor connection for pid %u"), pid_value);
11261 11262 11263 11264
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
11265 11266 11267 11268
                        _("Cannot connect to monitor connection of type '%s' "
                          "for pid %u"),
                        virDomainChrTypeToString(monConfig->type),
                        pid_value);
11269 11270 11271 11272
        goto cleanup;
    }

    if (!(def->name) &&
11273
        virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0) {
11274 11275 11276 11277 11278 11279 11280 11281 11282 11283
        virReportOOMError();
        goto cleanup;
    }

    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;

    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

11284
    if (qemuDomainAssignAddresses(def) < 0)
11285 11286 11287 11288 11289 11290 11291 11292 11293
        goto cleanup;

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, false)))
        goto cleanup;

    def = NULL;

11294
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308
        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:
11309
    if (qemuDomainObjEndJob(driver, vm) == 0) {
11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 11324
        vm = NULL;
        goto cleanup;
    }

cleanup:
    virDomainDefFree(def);
    virDomainChrSourceDefFree(monConfig);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    VIR_FREE(pidfile);
    return dom;
}


11325 11326
static int
qemuDomainOpenConsole(virDomainPtr dom,
11327
                      const char *dev_name,
11328 11329 11330 11331 11332 11333 11334 11335 11336
                      virStreamPtr st,
                      unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    int i;
    virDomainChrDefPtr chr = NULL;
11337
    qemuDomainObjPrivatePtr priv;
11338

11339 11340
    virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE |
                  VIR_DOMAIN_CONSOLE_FORCE, -1);
11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

11357 11358
    priv = vm->privateData;

11359
    if (dev_name) {
11360 11361 11362 11363 11364
        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];
        }
11365
        for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
11366
            if (STREQ(dev_name, vm->def->serials[i]->info.alias))
11367 11368 11369
                chr = vm->def->serials[i];
        }
        for (i = 0 ; !chr && i < vm->def->nparallels ; i++) {
11370
            if (STREQ(dev_name, vm->def->parallels[i]->info.alias))
11371 11372 11373
                chr = vm->def->parallels[i];
        }
    } else {
11374 11375
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
11376 11377 11378 11379 11380 11381 11382
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find character device %s"),
11383
                        NULLSTR(dev_name));
11384 11385 11386
        goto cleanup;
    }

11387
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
11388 11389
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("character device %s is not using a PTY"),
11390
                        NULLSTR(dev_name));
11391 11392 11393
        goto cleanup;
    }

11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404
    /* handle mutually exclusive access to console devices */
    ret = virConsoleOpen(priv->cons,
                         chr->source.data.file.path,
                         st,
                         (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0);

    if (ret == 1) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("Active console session exists for this domain"));
        ret = -1;
    }
11405 11406 11407 11408 11409 11410 11411 11412

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

E
Eric Blake 已提交
11413
static char *
E
Eric Blake 已提交
11414
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path, int *idx)
E
Eric Blake 已提交
11415
{
11416 11417
    int i;
    char *ret = NULL;
11418
    virDomainDiskDefPtr disk;
11419

11420 11421 11422
    i = virDomainDiskIndexByName(vm->def, path, true);
    if (i < 0)
        goto cleanup;
11423

11424
    disk = vm->def->disks[i];
E
Eric Blake 已提交
11425 11426
    if (idx)
        *idx = i;
11427

11428 11429 11430 11431 11432 11433 11434 11435
    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;
11436 11437 11438
        }
    }

11439
cleanup:
11440 11441 11442 11443 11444 11445 11446 11447
    if (!ret) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("No device found for specified path"));
    }
    return ret;
}

static int
11448
qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base,
11449 11450 11451 11452 11453 11454 11455
                       unsigned long bandwidth, virDomainBlockJobInfoPtr info,
                       int mode)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
E
Eric Blake 已提交
11456
    char *device = NULL;
11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467
    int ret = -1;

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

E
Eric Blake 已提交
11468
    device = qemuDiskPathToAlias(vm, path, NULL);
11469 11470 11471 11472 11473 11474
    if (!device) {
        goto cleanup;
    }

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;
11475 11476 11477 11478 11479 11480 11481

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

11482
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
11483
    priv = vm->privateData;
11484 11485 11486 11487 11488 11489
    /* XXX - add a qemu capability check, since only qemu 1.1 or newer
     * supports the base argument.
     * XXX - libvirt should really be tracking the backing file chain
     * itself, and validating that base is on the chain, rather than
     * relying on qemu to do this.  */
    ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode);
11490
    qemuDomainObjExitMonitorWithDriver(driver, vm);
11491 11492

endjob:
11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    VIR_FREE(device);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainBlockJobAbort(virDomainPtr dom, const char *path, unsigned int flags)
{
    virCheckFlags(0, -1);
11510
    return qemuDomainBlockJobImpl(dom, path, NULL, 0, NULL, BLOCK_JOB_ABORT);
11511 11512 11513 11514 11515 11516 11517
}

static int
qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
                           virDomainBlockJobInfoPtr info, unsigned int flags)
{
    virCheckFlags(0, -1);
11518
    return qemuDomainBlockJobImpl(dom, path, NULL, 0, info, BLOCK_JOB_INFO);
11519 11520 11521 11522 11523 11524 11525
}

static int
qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
                           unsigned long bandwidth, unsigned int flags)
{
    virCheckFlags(0, -1);
11526 11527
    return qemuDomainBlockJobImpl(dom, path, NULL, bandwidth, NULL,
                                  BLOCK_JOB_SPEED);
11528 11529 11530
}

static int
11531 11532
qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
                      unsigned long bandwidth, unsigned int flags)
11533
{
11534 11535
    int ret;

11536
    virCheckFlags(0, -1);
11537 11538
    ret = qemuDomainBlockJobImpl(dom, path, base, bandwidth, NULL,
                                 BLOCK_JOB_PULL);
11539
    if (ret == 0 && bandwidth != 0)
11540
        ret = qemuDomainBlockJobImpl(dom, path, NULL, bandwidth, NULL,
11541 11542
                                     BLOCK_JOB_SPEED);
    return ret;
11543
}
11544

11545 11546 11547 11548 11549 11550 11551
static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
                    unsigned int flags)
{
    return qemuDomainBlockRebase(dom, path, NULL, bandwidth, flags);
}

11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620
static int
qemuDomainOpenGraphics(virDomainPtr dom,
                       unsigned int idx,
                       int fd,
                       unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
    const char *protocol;

    virCheckFlags(VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH, -1);

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

    priv = vm->privateData;

    if (idx >= vm->def->ngraphics) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No graphics backend with index %d"), idx);
        goto cleanup;
    }
    switch (vm->def->graphics[idx]->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
        protocol = "vnc";
        break;
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        protocol = "spice";
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Can only open VNC or SPICE graphics backends, not %s"),
                        virDomainGraphicsTypeToString(vm->def->graphics[idx]->type));
        goto cleanup;
    }

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorOpenGraphics(priv->mon, protocol, fd, "graphicsfd",
                                  (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH) != 0);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632
static int
qemuDomainSetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int nparams,
                         unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo info;
E
Eric Blake 已提交
11633
    virDomainBlockIoTuneInfo *oldinfo;
11634 11635 11636 11637 11638
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    const char *device = NULL;
    int ret = -1;
    int i;
    int idx = -1;
E
Eric Blake 已提交
11639 11640
    bool set_bytes = false;
    bool set_iops = false;
11641 11642 11643

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658
    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;
11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670

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

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

E
Eric Blake 已提交
11671
    device = qemuDiskPathToAlias(vm, disk, &idx);
11672 11673 11674 11675 11676 11677 11678
    if (!device) {
        goto cleanup;
    }

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

11679 11680
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
11681 11682 11683 11684 11685 11686 11687
        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 已提交
11688
            set_bytes = true;
11689 11690 11691
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC)) {
            info.read_bytes_sec = param->value.ul;
E
Eric Blake 已提交
11692
            set_bytes = true;
11693 11694 11695
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC)) {
            info.write_bytes_sec = param->value.ul;
E
Eric Blake 已提交
11696
            set_bytes = true;
11697 11698 11699
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC)) {
            info.total_iops_sec = param->value.ul;
E
Eric Blake 已提交
11700
            set_iops = true;
11701 11702 11703
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC)) {
            info.read_iops_sec = param->value.ul;
E
Eric Blake 已提交
11704
            set_iops = true;
11705 11706 11707
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC)) {
            info.write_iops_sec = param->value.ul;
E
Eric Blake 已提交
11708
            set_iops = true;
11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726
        }
    }

    if ((info.total_bytes_sec && info.read_bytes_sec) ||
        (info.total_bytes_sec && info.write_bytes_sec)) {
        qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                        _("total and read/write of bytes_sec cannot be set at the same time"));
        goto endjob;
    }

    if ((info.total_iops_sec && info.read_iops_sec) ||
        (info.total_iops_sec && info.write_iops_sec)) {
        qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                        _("total and read/write of iops_sec cannot be set at the same time"));
        goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
E
Eric Blake 已提交
11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740
        /* 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;
        }
11741 11742 11743 11744
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
        qemuDomainObjExitMonitorWithDriver(driver, vm);
E
Eric Blake 已提交
11745
        vm->def->disks[idx]->blkdeviotune = info;
L
Lei Li 已提交
11746 11747
        if (ret < 0)
            goto endjob;
11748 11749 11750
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
11751 11752 11753 11754
        sa_assert(persistentDef);
        idx = virDomainDiskIndexByName(persistentDef, disk, true);
        if (idx < 0)
            goto endjob;
E
Eric Blake 已提交
11755 11756 11757 11758 11759 11760 11761 11762 11763 11764 11765
        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;
        }
11766 11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 11825 11826
        persistentDef->disks[idx]->blkdeviotune = info;
        ret = virDomainSaveConfig(driver->configDir, persistentDef);
        if (ret < 0) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Write to config file failed"));
            goto endjob;
        }
    }

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

cleanup:
    VIR_FREE(device);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int *nparams,
                         unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    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;

    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;

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    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 已提交
11827
    device = qemuDiskPathToAlias(vm, disk, NULL);
11828 11829 11830 11831 11832 11833 11834 11835

    if (!device) {
        goto cleanup;
    }

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

11836 11837
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860
        goto endjob;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply);
        qemuDomainObjExitMonitorWithDriver(driver, vm);
        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];

        switch(i) {
        case 0:
11861 11862 11863 11864
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_bytes_sec) < 0)
11865 11866 11867
                goto endjob;
            break;
        case 1:
11868 11869 11870 11871
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_bytes_sec) < 0)
11872 11873 11874
                goto endjob;
            break;
        case 2:
11875 11876 11877 11878
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_bytes_sec) < 0)
11879 11880 11881
                goto endjob;
            break;
        case 3:
11882 11883 11884 11885
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_iops_sec) < 0)
11886 11887 11888
                goto endjob;
            break;
        case 4:
11889 11890 11891 11892
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_iops_sec) < 0)
11893 11894 11895
                goto endjob;
            break;
        case 5:
11896 11897 11898 11899
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_iops_sec) < 0)
11900 11901 11902 11903 11904 11905 11906 11907 11908 11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920 11921
                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)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
11922

11923 11924 11925 11926 11927 11928 11929 11930 11931 11932 11933 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998 11999 12000 12001 12002 12003 12004 12005 12006 12007
static int
qemuDomainGetDiskErrors(virDomainPtr dom,
                        virDomainDiskErrorPtr errors,
                        unsigned int nerrors,
                        unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virHashTablePtr table = NULL;
    int ret = -1;
    int i;
    int n = 0;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    priv = vm->privateData;

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

    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        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)
        virDomainObjUnlock(vm);
    virHashFree(table);
    if (ret < 0) {
        for (i = 0; i < n; i++)
            VIR_FREE(errors[i].disk);
    }
    return ret;
}

12008 12009 12010 12011 12012 12013 12014 12015 12016 12017 12018 12019 12020 12021 12022 12023 12024 12025 12026 12027 12028 12029 12030 12031 12032 12033 12034 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044 12045 12046 12047 12048 12049 12050 12051 12052 12053 12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064 12065 12066 12067 12068 12069 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081 12082 12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108 12109 12110 12111 12112 12113 12114 12115 12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128 12129 12130 12131 12132 12133 12134 12135 12136 12137 12138 12139 12140 12141 12142 12143 12144 12145 12146 12147 12148 12149 12150 12151 12152 12153 12154 12155 12156 12157 12158 12159 12160 12161 12162 12163 12164 12165 12166 12167 12168 12169 12170 12171 12172 12173 12174 12175 12176 12177 12178 12179
static int
qemuDomainSetMetadata(virDomainPtr dom,
                      int type,
                      const char *metadata,
                      const char *key ATTRIBUTE_UNUSED,
                      const char *uri ATTRIBUTE_UNUSED,
                      unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDefPtr persistentDef;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &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:
            qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                            _("QEmu driver does not support modifying"
                              "<metadata> element"));
            goto cleanup;
            break;
        default:
            qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                            _("unknown metadata type"));
            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:
            qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                            _("QEMU driver does not support"
                              "<metadata> element"));
            goto cleanup;
         default:
            qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                            _("unknown metadata type"));
            goto cleanup;
            break;
        }

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
no_memory:
    virReportOOMError();
    goto cleanup;
}

static char *
qemuDomainGetMetadata(virDomainPtr dom,
                      int type,
                      const char *uri ATTRIBUTE_UNUSED,
                      unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDefPtr def;
    char *ret = NULL;
    char *field = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, NULL);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &def) < 0)
        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:
        qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                        _("QEMU driver does not support"
                          "<metadata> element"));
        goto cleanup;
        break;
    default:
        qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                        _("unknown metadata type"));
        goto cleanup;
        break;
    }

    if (!field) {
        qemuReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                        _("Requested metadata element is not present"));
        goto cleanup;
    }

    if (!(ret = strdup(field))) {
        virReportOOMError();
        goto cleanup;
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

12180 12181 12182 12183 12184 12185 12186 12187 12188 12189
/* 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 已提交
12190
        return QEMU_NB_TOTAL_CPU_STAT_PARAM;
12191 12192 12193 12194 12195 12196 12197
    /* 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 已提交
12198 12199 12200 12201 12202 12203 12204 12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225 12226
    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;
12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246
}

static int
qemuDomainGetPercpuStats(virDomainPtr domain,
                         virCgroupPtr group,
                         virTypedParameterPtr params,
                         unsigned int nparams,
                         int start_cpu,
                         unsigned int ncpus)
{
    char *map = NULL;
    int rv = -1;
    int i, max_id;
    char *pos;
    char *buf = NULL;
    virTypedParameterPtr ent;
    int param_idx;

    /* return the number of supported params */
    if (nparams == 0 && ncpus != 0)
E
Eric Blake 已提交
12247
        return QEMU_NB_PER_CPU_STAT_PARAM; /* only cpu_time is supported */
12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271

    /* return percpu cputime in index 0 */
    param_idx = 0;
    /* to parse account file, we need "present" cpu map */
    map = nodeGetCPUmap(domain->conn, &max_id, "present");
    if (!map)
        return rv;

    if (ncpus == 0) { /* returns max cpu ID */
        rv = max_id + 1;
        goto cleanup;
    }

    if (start_cpu > max_id) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("start_cpu %d larger than maximum of %d"),
                        start_cpu, max_id);
        goto cleanup;
    }

    /* we get percpu cputime accounting info. */
    if (virCgroupGetCpuacctPercpuUsage(group, &buf))
        goto cleanup;
    pos = buf;
12272
    memset(params, 0, nparams * ncpus);
12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289

    if (max_id - start_cpu > ncpus - 1)
        max_id = start_cpu + ncpus - 1;

    for (i = 0; i <= max_id; i++) {
        unsigned long long cpu_time;

        if (!map[i]) {
            cpu_time = 0;
        } else if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cpuacct parse error"));
            goto cleanup;
        }
        if (i < start_cpu)
            continue;
        ent = &params[ (i - start_cpu) * nparams + param_idx];
E
Eric Blake 已提交
12290 12291 12292
        if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
            goto cleanup;
12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 12317 12318 12319 12320 12321 12322 12323 12324 12325 12326 12327 12328 12329 12330 12331 12332 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349 12350 12351 12352 12353 12354 12355 12356 12357 12358
    }
    rv = param_idx + 1;
cleanup:
    VIR_FREE(buf);
    VIR_FREE(map);
    return rv;
}


static int
qemuDomainGetCPUStats(virDomainPtr domain,
                virTypedParameterPtr params,
                unsigned int nparams,
                int start_cpu,
                unsigned int ncpus,
                unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    bool isActive;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    qemuDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), domain->uuid);
        goto cleanup;
    }

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

    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUACCT)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup CPUACCT controller is not mounted"));
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
        goto cleanup;
    }

    if (start_cpu == -1)
        ret = qemuDomainGetTotalcpuStats(group, params, nparams);
    else
        ret = qemuDomainGetPercpuStats(domain, group, params, nparams,
                                       start_cpu, ncpus);
cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

12359 12360 12361 12362 12363 12364 12365 12366 12367 12368 12369 12370 12371 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403
static int
qemuDomainPMSuspendForDuration(virDomainPtr dom,
                               unsigned int target,
                               unsigned long long duration,
                               unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    if (duration) {
        qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                        _("Duration not supported. Use 0 for now"));
        return -1;
    }

    if (!(target == VIR_NODE_SUSPEND_TARGET_MEM ||
          target == VIR_NODE_SUSPEND_TARGET_DISK ||
          target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("Unknown suspend target: %u"),
                        target);
        return -1;
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

    priv = vm->privateData;

    if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP) &&
        (target == VIR_NODE_SUSPEND_TARGET_MEM ||
         target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
O
Osier Yang 已提交
12404 12405 12406 12407
        qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                        _("Unable to suspend domain due to "
                          "missing system_wakeup monitor command"));
        goto cleanup;
12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 12423 12424 12425 12426 12427 12428 12429 12430 12431 12432 12433 12434 12435 12436 12437 12438 12439 12440 12441 12442 12443 12444
    }

    if (priv->agentError) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("QEMU guest agent is not available due to an error"));
        goto cleanup;
    }

    if (!priv->agent) {
        qemuReportError(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)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }

    qemuDomainObjEnterAgent(driver, vm);
    ret = qemuAgentSuspend(priv->agent, target);
    qemuDomainObjExitAgent(driver, vm);

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

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

12445 12446 12447 12448 12449 12450 12451 12452 12453 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 12466 12467 12468 12469 12470 12471 12472 12473 12474 12475 12476 12477 12478 12479 12480 12481 12482 12483 12484 12485 12486 12487 12488 12489 12490 12491 12492 12493 12494 12495 12496 12497 12498 12499
static int
qemuDomainPMWakeup(virDomainPtr dom,
                   unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

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

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

    priv = vm->privateData;

    if (!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP)) {
       qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Unable to wake up domain due to "
                         "missing system_wakeup monitor command"));
       goto endjob;
    }

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

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

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

12500
static virDriver qemuDriver = {
12501 12502
    .no = VIR_DRV_QEMU,
    .name = "QEMU",
12503 12504 12505 12506 12507 12508 12509 12510 12511 12512 12513 12514 12515 12516 12517 12518 12519 12520
    .open = qemudOpen, /* 0.2.0 */
    .close = qemudClose, /* 0.2.0 */
    .supports_feature = qemudSupportsFeature, /* 0.5.0 */
    .type = qemudGetType, /* 0.2.0 */
    .version = qemudGetVersion, /* 0.2.0 */
    .getHostname = virGetHostname, /* 0.3.3 */
    .getSysinfo = qemuGetSysinfo, /* 0.8.8 */
    .getMaxVcpus = qemudGetMaxVCPUs, /* 0.2.1 */
    .nodeGetInfo = nodeGetInfo, /* 0.2.0 */
    .getCapabilities = qemudGetCapabilities, /* 0.2.1 */
    .listDomains = qemudListDomains, /* 0.2.0 */
    .numOfDomains = qemudNumDomains, /* 0.2.0 */
    .domainCreateXML = qemudDomainCreate, /* 0.2.0 */
    .domainLookupByID = qemudDomainLookupByID, /* 0.2.0 */
    .domainLookupByUUID = qemudDomainLookupByUUID, /* 0.2.0 */
    .domainLookupByName = qemudDomainLookupByName, /* 0.2.0 */
    .domainSuspend = qemudDomainSuspend, /* 0.2.0 */
    .domainResume = qemudDomainResume, /* 0.2.0 */
12521
    .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
12522
    .domainShutdownFlags = qemuDomainShutdownFlags, /* 0.9.10 */
12523
    .domainReboot = qemuDomainReboot, /* 0.9.3 */
12524
    .domainReset = qemuDomainReset, /* 0.9.7 */
12525 12526
    .domainDestroy = qemuDomainDestroy, /* 0.2.0 */
    .domainDestroyFlags = qemuDomainDestroyFlags, /* 0.9.4 */
12527
    .domainGetOSType = qemudDomainGetOSType, /* 0.2.2 */
12528
    .domainGetMaxMemory = qemuDomainGetMaxMemory, /* 0.4.2 */
12529 12530 12531 12532 12533 12534 12535 12536 12537
    .domainSetMaxMemory = qemudDomainSetMaxMemory, /* 0.4.2 */
    .domainSetMemory = qemudDomainSetMemory, /* 0.4.2 */
    .domainSetMemoryFlags = qemudDomainSetMemoryFlags, /* 0.9.0 */
    .domainSetMemoryParameters = qemuDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */
    .domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */
    .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */
    .domainGetInfo = qemudDomainGetInfo, /* 0.2.0 */
    .domainGetState = qemuDomainGetState, /* 0.9.2 */
12538
    .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */
12539 12540
    .domainSave = qemuDomainSave, /* 0.2.0 */
    .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */
12541
    .domainRestore = qemuDomainRestore, /* 0.2.0 */
12542
    .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */
12543 12544
    .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */
    .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */
12545 12546
    .domainCoreDump = qemudDomainCoreDump, /* 0.7.0 */
    .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */
12547 12548
    .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */
    .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */
12549 12550
    .domainGetVcpusFlags = qemudDomainGetVcpusFlags, /* 0.8.5 */
    .domainPinVcpu = qemudDomainPinVcpu, /* 0.4.4 */
12551
    .domainPinVcpuFlags = qemudDomainPinVcpuFlags, /* 0.9.3 */
E
Eric Blake 已提交
12552
    .domainGetVcpuPinInfo = qemudDomainGetVcpuPinInfo, /* 0.9.3 */
12553 12554 12555 12556 12557 12558 12559 12560 12561
    .domainGetVcpus = qemudDomainGetVcpus, /* 0.4.4 */
    .domainGetMaxVcpus = qemudDomainGetMaxVcpus, /* 0.4.4 */
    .domainGetSecurityLabel = qemudDomainGetSecurityLabel, /* 0.6.1 */
    .nodeGetSecurityModel = qemudNodeGetSecurityModel, /* 0.6.1 */
    .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */
    .domainXMLFromNative = qemuDomainXMLFromNative, /* 0.6.4 */
    .domainXMLToNative = qemuDomainXMLToNative, /* 0.6.4 */
    .listDefinedDomains = qemudListDefinedDomains, /* 0.2.0 */
    .numOfDefinedDomains = qemudNumDefinedDomains, /* 0.2.0 */
12562 12563
    .domainCreate = qemuDomainStart, /* 0.2.0 */
    .domainCreateWithFlags = qemuDomainStartWithFlags, /* 0.8.2 */
12564 12565
    .domainDefineXML = qemudDomainDefine, /* 0.2.0 */
    .domainUndefine = qemudDomainUndefine, /* 0.2.0 */
12566
    .domainUndefineFlags = qemuDomainUndefineFlags, /* 0.9.4 */
12567 12568 12569 12570 12571 12572 12573 12574 12575
    .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 */
    .domainGetAutostart = qemudDomainGetAutostart, /* 0.2.1 */
    .domainSetAutostart = qemudDomainSetAutostart, /* 0.2.1 */
    .domainGetSchedulerType = qemuGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = qemuGetSchedulerParameters, /* 0.7.0 */
12576
    .domainGetSchedulerParametersFlags = qemuGetSchedulerParametersFlags, /* 0.9.2 */
12577
    .domainSetSchedulerParameters = qemuSetSchedulerParameters, /* 0.7.0 */
12578
    .domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */
12579
    .domainMigratePerform = qemudDomainMigratePerform, /* 0.5.0 */
12580
    .domainBlockResize = qemuDomainBlockResize, /* 0.9.8 */
12581 12582
    .domainBlockStats = qemuDomainBlockStats, /* 0.4.1 */
    .domainBlockStatsFlags = qemuDomainBlockStatsFlags, /* 0.9.5 */
12583 12584 12585 12586 12587
    .domainInterfaceStats = qemudDomainInterfaceStats, /* 0.4.1 */
    .domainMemoryStats = qemudDomainMemoryStats, /* 0.7.5 */
    .domainBlockPeek = qemudDomainBlockPeek, /* 0.4.4 */
    .domainMemoryPeek = qemudDomainMemoryPeek, /* 0.4.4 */
    .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
12588
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
12589
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
12590 12591 12592 12593 12594 12595 12596 12597 12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610
    .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.4.4 */
    .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.4.4 */
    .domainEventRegister = qemuDomainEventRegister, /* 0.5.0 */
    .domainEventDeregister = qemuDomainEventDeregister, /* 0.5.0 */
    .domainMigratePrepare2 = qemudDomainMigratePrepare2, /* 0.5.0 */
    .domainMigrateFinish2 = qemudDomainMigrateFinish2, /* 0.5.0 */
    .nodeDeviceDettach = qemudNodeDeviceDettach, /* 0.6.1 */
    .nodeDeviceReAttach = qemudNodeDeviceReAttach, /* 0.6.1 */
    .nodeDeviceReset = qemudNodeDeviceReset, /* 0.6.1 */
    .domainMigratePrepareTunnel = qemudDomainMigratePrepareTunnel, /* 0.7.2 */
    .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 */
    .domainAbortJob = qemuDomainAbortJob, /* 0.7.7 */
    .domainMigrateSetMaxDowntime = qemuDomainMigrateSetMaxDowntime, /* 0.8.0 */
    .domainMigrateSetMaxSpeed = qemuDomainMigrateSetMaxSpeed, /* 0.9.0 */
12611
    .domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
12612 12613 12614 12615 12616 12617 12618 12619 12620
    .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 */
12621 12622
    .domainSnapshotNumChildren = qemuDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = qemuDomainSnapshotListChildrenNames, /* 0.9.7 */
12623 12624
    .domainSnapshotLookupByName = qemuDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = qemuDomainHasCurrentSnapshot, /* 0.8.0 */
12625
    .domainSnapshotGetParent = qemuDomainSnapshotGetParent, /* 0.9.7 */
12626 12627 12628 12629
    .domainSnapshotCurrent = qemuDomainSnapshotCurrent, /* 0.8.0 */
    .domainRevertToSnapshot = qemuDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = qemuDomainSnapshotDelete, /* 0.8.0 */
    .qemuDomainMonitorCommand = qemuDomainMonitorCommand, /* 0.8.3 */
12630
    .qemuDomainAttach = qemuDomainAttach, /* 0.9.4 */
12631
    .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */
12632
    .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */
12633
    .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */
12634 12635 12636 12637 12638 12639
    .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 */
12640
    .domainSendKey = qemuDomainSendKey, /* 0.9.4 */
12641 12642 12643 12644
    .domainBlockJobAbort = qemuDomainBlockJobAbort, /* 0.9.4 */
    .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
    .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
    .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
12645
    .domainBlockRebase = qemuDomainBlockRebase, /* 0.9.10 */
12646
    .isAlive = qemuIsAlive, /* 0.9.8 */
12647
    .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
12648 12649
    .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
    .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
12650 12651
    .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */
    .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
12652 12653
    .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
    .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
12654
    .domainGetDiskErrors = qemuDomainGetDiskErrors, /* 0.9.10 */
12655 12656
    .domainSetMetadata = qemuDomainSetMetadata, /* 0.9.10 */
    .domainGetMetadata = qemuDomainGetMetadata, /* 0.9.10 */
12657
    .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
12658
    .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
12659
    .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
12660 12661 12662
};


12663
static virStateDriver qemuStateDriver = {
12664
    .name = "QEMU",
12665 12666 12667 12668
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
12669
};
12670

12671
static void
12672
qemuVMDriverLock(void) {
12673 12674 12675 12676 12677
    qemuDriverLock(qemu_driver);
};


static void
12678
qemuVMDriverUnlock(void) {
12679 12680 12681 12682
    qemuDriverUnlock(qemu_driver);
};


12683 12684 12685 12686 12687 12688 12689 12690 12691
static int
qemuVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
                    virHashIterator iter, void *data)
{
    virHashForEach(qemu_driver->domains.objs, iter, data);

    return 0;
}

S
Stefan Berger 已提交
12692 12693
static virNWFilterCallbackDriver qemuCallbackDriver = {
    .name = "QEMU",
12694 12695 12696
    .vmFilterRebuild = qemuVMFilterRebuild,
    .vmDriverLock = qemuVMDriverLock,
    .vmDriverUnlock = qemuVMDriverUnlock,
S
Stefan Berger 已提交
12697 12698
};

12699
int qemuRegister(void) {
12700 12701
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
S
Stefan Berger 已提交
12702
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
12703 12704
    return 0;
}