qemu_driver.c 309.5 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-2011 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 50
#include "qemu_driver.h"
#include "qemu_conf.h"
51
#include "qemu_capabilities.h"
52
#include "qemu_command.h"
53
#include "qemu_cgroup.h"
54
#include "qemu_hostdev.h"
55
#include "qemu_hotplug.h"
56
#include "qemu_monitor.h"
57
#include "qemu_bridge_filter.h"
58
#include "qemu_process.h"
59
#include "qemu_migration.h"
60 61 62 63

#include "virterror_internal.h"
#include "logging.h"
#include "datatypes.h"
64
#include "buf.h"
65
#include "util.h"
66
#include "nodeinfo.h"
67
#include "stats_linux.h"
68
#include "capabilities.h"
69
#include "memory.h"
70
#include "uuid.h"
71
#include "domain_conf.h"
72
#include "domain_audit.h"
73 74
#include "node_device_conf.h"
#include "pci.h"
75
#include "hostusb.h"
76
#include "processinfo.h"
C
Chris Lalancette 已提交
77
#include "libvirt_internal.h"
78
#include "xml.h"
79
#include "cpu/cpu.h"
80
#include "macvtap.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 "virkeycode.h"
91

92 93
#define VIR_FROM_THIS VIR_FROM_QEMU

94 95
#define QEMU_NB_MEM_PARAM  3

96 97 98
#if HAVE_LINUX_KVM_H
# include <linux/kvm.h>
#endif
99

100 101
/* device for kvm ioctls */
#define KVM_DEVICE "/dev/kvm"
102

103 104 105 106 107 108 109 110 111 112 113
/* 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

114
#define QEMU_NB_BLKIO_PARAM  1
115

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

118 119
static int qemudShutdown(void);

120 121 122
static int qemuDomainObjStart(virConnectPtr conn,
                              struct qemud_driver *driver,
                              virDomainObjPtr vm,
123
                              unsigned int flags);
J
Jiri Denemark 已提交
124

125
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
126

127
struct qemud_driver *qemu_driver = NULL;
128 129


130 131 132 133
struct qemuAutostartData {
    struct qemud_driver *driver;
    virConnectPtr conn;
};
134

135
static void
136 137
qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED,
                    void *opaque)
138 139 140
{
    virDomainObjPtr vm = payload;
    struct qemuAutostartData *data = opaque;
141
    virErrorPtr err;
142 143 144 145
    int flags = 0;

    if (data->driver->autoStartBypassCache)
        flags |= VIR_DOMAIN_START_BYPASS_CACHE;
146 147

    virDomainObjLock(vm);
148
    virResetLastError();
149 150
    if (qemuDomainObjBeginJobWithDriver(data->driver, vm,
                                        QEMU_JOB_MODIFY) < 0) {
151 152 153 154 155 156 157
        err = virGetLastError();
        VIR_ERROR(_("Failed to start job on VM '%s': %s"),
                  vm->def->name,
                  err ? err->message : _("unknown error"));
    } else {
        if (vm->autostart &&
            !virDomainObjIsActive(vm) &&
158
            qemuDomainObjStart(data->conn, data->driver, vm, flags) < 0) {
159
            err = virGetLastError();
160
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
161
                      vm->def->name,
162
                      err ? err->message : _("unknown error"));
163
        }
164

165
        if (qemuDomainObjEndJob(data->driver, vm) == 0)
166
            vm = NULL;
167
    }
168 169 170

    if (vm)
        virDomainObjUnlock(vm);
171 172
}

173

174
static void
175 176
qemuAutostartDomains(struct qemud_driver *driver)
{
177 178 179 180 181
    /* 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
     */
182 183 184
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
185
    /* Ignoring NULL conn which is mostly harmless here */
186
    struct qemuAutostartData data = { driver, conn };
187

188
    qemuDriverLock(driver);
189
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
190
    qemuDriverUnlock(driver);
191

192 193
    if (conn)
        virConnectClose(conn);
194 195
}

196
static int
197
qemuSecurityInit(struct qemud_driver *driver)
198
{
199 200 201 202
    virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName,
                                                      driver->allowDiskFormatProbing);
    if (!mgr)
        goto error;
D
Daniel Veillard 已提交
203

204 205 206 207 208 209 210
    if (driver->privileged) {
        virSecurityManagerPtr dac = virSecurityManagerNewDAC(driver->user,
                                                             driver->group,
                                                             driver->allowDiskFormatProbing,
                                                             driver->dynamicOwnership);
        if (!dac)
            goto error;
211

212
        if (!(driver->securityManager = virSecurityManagerNewStack(mgr,
E
Eric Blake 已提交
213 214 215
                                                                   dac))) {

            virSecurityManagerFree(dac);
216
            goto error;
E
Eric Blake 已提交
217
        }
218 219 220
    } else {
        driver->securityManager = mgr;
    }
D
Daniel Veillard 已提交
221

222
    return 0;
223

224
error:
225
    VIR_ERROR(_("Failed to initialize security drivers"));
226 227 228
    virSecurityManagerFree(mgr);
    return -1;
}
229

230

231 232 233 234 235
static virCapsPtr
qemuCreateCapabilities(virCapsPtr oldcaps,
                       struct qemud_driver *driver)
{
    virCapsPtr caps;
236

237 238 239 240
    /* Basic host arch / guest machine capabilities */
    if (!(caps = qemuCapsInit(oldcaps))) {
        virReportOOMError();
        return NULL;
241 242
    }

243 244 245 246 247 248
    if (driver->allowDiskFormatProbing) {
        caps->defaultDiskDriverName = NULL;
        caps->defaultDiskDriverType = NULL;
    } else {
        caps->defaultDiskDriverName = "qemu";
        caps->defaultDiskDriverType = "raw";
249 250
    }

251 252
    qemuDomainSetPrivateDataHooks(caps);
    qemuDomainSetNamespaceHooks(caps);
253

254 255 256 257
    if (virGetHostUUID(caps->host.host_uuid)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot get the host uuid"));
        goto err_exit;
258
    }
259

260 261
    /* Security driver data */
    const char *doi, *model;
262

263 264 265 266 267 268 269
    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;
270
    }
271

272 273
    VIR_DEBUG("Initialized caps for security driver \"%s\" with "
              "DOI \"%s\"", model, doi);
274

275
    return caps;
276

277 278 279 280
no_memory:
    virReportOOMError();
err_exit:
    virCapabilitiesFree(caps);
281 282 283
    return NULL;
}

284
static void qemuDomainSnapshotLoad(void *payload,
285
                                   const void *name ATTRIBUTE_UNUSED,
286
                                   void *data)
287
{
288 289 290 291 292 293 294 295 296
    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;
297
    virDomainSnapshotObjPtr snap = NULL;
298
    virDomainSnapshotObjPtr current = NULL;
299
    char ebuf[1024];
300 301
    unsigned int flags = (VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE |
                          VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL);
302

303 304 305 306
    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);
307
        goto cleanup;
308 309
    }

310 311
    VIR_INFO("Scanning for snapshots for domain %s in %s", vm->def->name,
             snapDir);
312

313 314 315 316 317
    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)));
318
        goto cleanup;
319 320
    }

321 322 323
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.')
            continue;
324

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

329
        if (virAsprintf(&fullpath, "%s/%s", snapDir, entry->d_name) < 0) {
330
            VIR_ERROR(_("Failed to allocate memory for path"));
331 332
            continue;
        }
333

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

343 344 345
        def = virDomainSnapshotDefParseString(xmlStr, qemu_driver->caps,
                                              QEMU_EXPECTED_VIRT_TYPES,
                                              flags);
346 347
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
348 349
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
                      fullpath);
350 351 352 353
            VIR_FREE(fullpath);
            VIR_FREE(xmlStr);
            continue;
        }
354

355 356 357
        snap = virDomainSnapshotAssignDef(&vm->snapshots, def);
        if (snap == NULL) {
            virDomainSnapshotDefFree(def);
358 359 360 361
        } else if (snap->def->current) {
            current = snap;
            if (!vm->current_snapshot)
                vm->current_snapshot = snap;
362
        }
363

364 365
        VIR_FREE(fullpath);
        VIR_FREE(xmlStr);
366 367
    }

368 369 370 371 372 373
    if (vm->current_snapshot != current) {
        VIR_ERROR(_("Too many snapshots claiming to be current for domain %s"),
                  vm->def->name);
        vm->current_snapshot = NULL;
    }

374 375 376 377 378 379 380 381
    /* 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.
     */
382

383
    virResetLastError();
384

385 386 387 388
cleanup:
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
389 390 391
    virDomainObjUnlock(vm);
}

392 393 394 395 396
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
397
static int
398 399 400 401 402
qemudStartup(int privileged) {
    char *base = NULL;
    char *driverConf = NULL;
    int rc;
    virConnectPtr conn = NULL;
403

404 405
    if (VIR_ALLOC(qemu_driver) < 0)
        return -1;
406

407
    if (virMutexInit(&qemu_driver->lock) < 0) {
408
        VIR_ERROR(_("cannot initialize mutex"));
409 410
        VIR_FREE(qemu_driver);
        return -1;
411
    }
412 413
    qemuDriverLock(qemu_driver);
    qemu_driver->privileged = privileged;
414

415 416
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;
417

418 419
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;
420

421 422 423 424 425 426
    /* Init domain events */
    qemu_driver->domainEventState = virDomainEventStateNew(qemuDomainEventFlush,
                                                           qemu_driver,
                                                           NULL,
                                                           true);
    if (!qemu_driver->domainEventState)
427
        goto error;
428

429 430 431 432
    /* Allocate bitmap for vnc port reservation */
    if ((qemu_driver->reservedVNCPorts =
         virBitmapAlloc(QEMU_VNC_PORT_MAX - QEMU_VNC_PORT_MIN)) == NULL)
        goto out_of_memory;
433

434 435 436
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();
437

438 439 440 441
    if (privileged) {
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
442

443 444
        if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL)
            goto out_of_memory;
445

446 447 448
        if (virAsprintf(&qemu_driver->stateDir,
                      "%s/run/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
449

450 451 452
        if (virAsprintf(&qemu_driver->libDir,
                      "%s/lib/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
453

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
        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;
471

472 473 474 475 476
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
            goto out_of_memory;
        }
477

478 479 480 481 482
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
            goto out_of_memory;
        }
        VIR_FREE(userdir);
483

484 485 486 487 488 489 490 491 492 493 494 495
        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;
496
    }
H
Hu Tao 已提交
497

498
    if (virFileMakePath(qemu_driver->stateDir) < 0) {
499 500 501 502
        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 已提交
503
    }
504
    if (virFileMakePath(qemu_driver->libDir) < 0) {
505 506 507 508 509
        char ebuf[1024];
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
510
    if (virFileMakePath(qemu_driver->cacheDir) < 0) {
511 512 513 514 515
        char ebuf[1024];
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
516
    if (virFileMakePath(qemu_driver->saveDir) < 0) {
517 518 519 520 521
        char ebuf[1024];
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
                  qemu_driver->saveDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
522
    if (virFileMakePath(qemu_driver->snapshotDir) < 0) {
523 524 525 526 527
        char ebuf[1024];
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
                  qemu_driver->snapshotDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
528
    if (virFileMakePath(qemu_driver->autoDumpPath) < 0) {
529 530 531 532
        char ebuf[1024];
        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
                  qemu_driver->autoDumpPath, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
533 534
    }

535 536 537 538 539 540 541
    /* 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;
542

543
    VIR_FREE(base);
544

545 546 547 548 549
    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)));
550 551
    }

552 553 554 555
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
        goto error;
    }
    VIR_FREE(driverConf);
556

557 558 559 560 561 562 563 564
    /* 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;
    }

565 566
    if (qemuSecurityInit(qemu_driver) < 0)
        goto error;
567

568 569 570
    if ((qemu_driver->caps = qemuCreateCapabilities(NULL,
                                                    qemu_driver)) == NULL)
        goto error;
571

572
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
573
        goto error;
574

575 576 577 578 579 580
    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;
581
        }
582
        if (chown(qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group) < 0) {
583
            virReportSystemError(errno,
584 585 586
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
587
        }
588 589 590 591 592 593 594 595 596 597 598
        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;
599
        }
600
    }
601

602 603 604 605 606 607
    /* 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
608
     */
609 610 611 612 613
    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;
614

615 616
        if (virFileMakePath(mempath) < 0) {
            virReportSystemError(errno,
617 618 619
                                 _("unable to create hugepage path %s"), mempath);
            VIR_FREE(mempath);
            goto error;
620
        }
621 622 623 624 625 626 627
        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 已提交
628
        }
E
Eric Blake 已提交
629

630
        qemu_driver->hugepage_path = mempath;
631
    }
632

633 634 635
    if (qemuProcessAutoDestroyInit(qemu_driver) < 0)
        goto error;

636 637 638 639 640
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
M
Matthias Bolte 已提交
641 642
                                1, QEMU_EXPECTED_VIRT_TYPES,
                                NULL, NULL) < 0)
643
        goto error;
644

645 646 647
    conn = virConnectOpen(qemu_driver->privileged ?
                          "qemu:///system" :
                          "qemu:///session");
648

649
    qemuProcessReconnectAll(conn, qemu_driver);
650

651 652 653 654 655
    /* Then inactive persistent configs */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->configDir,
                                qemu_driver->autostartDir,
M
Matthias Bolte 已提交
656 657
                                0, QEMU_EXPECTED_VIRT_TYPES,
                                NULL, NULL) < 0)
658
        goto error;
659

660

661 662
    virHashForEach(qemu_driver->domains.objs, qemuDomainSnapshotLoad,
                   qemu_driver->snapshotDir);
663

664 665 666
    qemu_driver->workerPool = virThreadPoolNew(0, 1, processWatchdogEvent, qemu_driver);
    if (!qemu_driver->workerPool)
        goto error;
667

668 669 670 671
    qemuDriverUnlock(qemu_driver);

    qemuAutostartDomains(qemu_driver);

672 673
    if (conn)
        virConnectClose(conn);
674

675
    return 0;
676

677 678 679 680 681 682 683 684 685 686
out_of_memory:
    virReportOOMError();
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
    if (conn)
        virConnectClose(conn);
    VIR_FREE(base);
    VIR_FREE(driverConf);
    qemudShutdown();
687
    return -1;
688 689
}

690 691 692
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;
693

694 695 696 697 698 699 700
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
E
Eric Blake 已提交
701
    }
702
}
E
Eric Blake 已提交
703

704 705 706 707 708 709 710 711 712 713
/**
 * 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;
714

715 716 717 718 719
    qemuDriverLock(qemu_driver);
    virDomainLoadAllConfigs(qemu_driver->caps,
                            &qemu_driver->domains,
                            qemu_driver->configDir,
                            qemu_driver->autostartDir,
M
Matthias Bolte 已提交
720 721
                            0, QEMU_EXPECTED_VIRT_TYPES,
                            qemudNotifyLoadDomain, qemu_driver);
722
    qemuDriverUnlock(qemu_driver);
723

724
    qemuAutostartDomains(qemu_driver);
725

726 727
    return 0;
}
S
Stefan Berger 已提交
728

729 730 731 732 733 734 735 736 737 738 739
/**
 * 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;
740

741 742
    if (!qemu_driver)
        return 0;
743

744 745 746 747 748 749
    /* 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;
}
750

751 752 753 754 755 756 757 758
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
    int i;
759

760 761
    if (!qemu_driver)
        return -1;
762

763 764 765
    qemuDriverLock(qemu_driver);
    pciDeviceListFree(qemu_driver->activePciHostdevs);
    virCapabilitiesFree(qemu_driver->caps);
766

767 768
    virDomainObjListDeinit(&qemu_driver->domains);
    virBitmapFree(qemu_driver->reservedVNCPorts);
769

770
    virSysinfoDefFree(qemu_driver->hostsysinfo);
771

772 773
    qemuProcessAutoDestroyShutdown(qemu_driver);

774 775 776 777 778 779 780 781
    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 已提交
782
    VIR_FREE(qemu_driver->qemuImgBinary);
783 784 785 786 787 788 789 790 791 792 793 794
    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);
795

796
    virSecurityManagerFree(qemu_driver->securityManager);
797

798
    ebtablesContextFree(qemu_driver->ebtables);
799

800 801 802 803
    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 已提交
804 805
    }

806
    /* Free domain callback list */
807
    virDomainEventStateFree(qemu_driver->domainEventState);
D
Daniel P. Berrange 已提交
808

809 810
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);
811

812
    virCgroupFree(&qemu_driver->cgroup);
813

814 815
    virLockManagerPluginUnref(qemu_driver->lockManager);

816 817 818 819
    qemuDriverUnlock(qemu_driver);
    virMutexDestroy(&qemu_driver->lock);
    virThreadPoolFree(qemu_driver->workerPool);
    VIR_FREE(qemu_driver);
820

821
    return 0;
822 823
}

824

825
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
826
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
827
                                  unsigned int flags)
828
{
E
Eric Blake 已提交
829 830
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

831
    if (conn->uri == NULL) {
832 833 834
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

835
        conn->uri = xmlParseURI(qemu_driver->privileged ?
836 837
                                "qemu:///system" :
                                "qemu:///session");
838
        if (!conn->uri) {
839
            virReportOOMError();
840 841
            return VIR_DRV_OPEN_ERROR;
        }
842 843 844 845 846 847 848 849 850 851
    } 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;

852
        if (qemu_driver == NULL) {
853 854
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("qemu state driver is not active"));
855 856 857
            return VIR_DRV_OPEN_ERROR;
        }

858
        if (conn->uri->path == NULL) {
859 860 861 862 863
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no QEMU URI path given, try %s"),
                            qemu_driver->privileged
                            ? "qemu:///system"
                            : "qemu:///session");
864 865 866
                return VIR_DRV_OPEN_ERROR;
        }

867
        if (qemu_driver->privileged) {
868 869
            if (STRNEQ (conn->uri->path, "/system") &&
                STRNEQ (conn->uri->path, "/session")) {
870 871 872
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///system"),
                                conn->uri->path);
873 874 875 876
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
877 878 879
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///session"),
                                conn->uri->path);
880 881 882
                return VIR_DRV_OPEN_ERROR;
            }
        }
883 884 885 886 887 888 889
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
890
    struct qemud_driver *driver = conn->privateData;
891 892

    /* Get rid of callbacks registered for this conn */
893
    qemuDriverLock(driver);
894 895
    virDomainEventCallbackListRemoveConn(conn,
                                         driver->domainEventState->callbacks);
896
    qemuProcessAutoDestroyRun(driver, conn);
897
    qemuDriverUnlock(driver);
898 899 900 901 902 903

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
904 905 906 907 908
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
909
    case VIR_DRV_FEATURE_MIGRATION_V2:
910
    case VIR_DRV_FEATURE_MIGRATION_V3:
911
    case VIR_DRV_FEATURE_MIGRATION_P2P:
912
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
913 914 915
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
916 917 918
    }
}

919
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
920
    return "QEMU";
921 922
}

923

924 925 926 927 928 929 930 931 932 933 934 935 936
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;
}


937 938 939 940
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
941

942 943
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
944
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
945
        return -1;
946 947 948 949 950 951
    }

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

952
    VIR_FORCE_CLOSE(fd);
953 954 955 956
    return maxvcpus;
}


E
Eric Blake 已提交
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
static char *
qemuGetSysinfo(virConnectPtr conn, unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;

    virCheckFlags(0, NULL);

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

    return virSysinfoFormat(driver->hostsysinfo, "");
}

973
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
974 975 976
    if (!type)
        return 16;

977
    if (STRCASEEQ(type, "qemu"))
978 979
        return 16;

980
    if (STRCASEEQ(type, "kvm"))
981
        return kvmGetMaxVCPUs();
982

983
    if (STRCASEEQ(type, "kqemu"))
984
        return 1;
985

986 987
    qemuReportError(VIR_ERR_INVALID_ARG,
                    _("unknown type '%s'"), type);
988 989 990
    return -1;
}

991

992
static char *qemudGetCapabilities(virConnectPtr conn) {
993
    struct qemud_driver *driver = conn->privateData;
994
    virCapsPtr caps = NULL;
995
    char *xml = NULL;
996

997
    qemuDriverLock(driver);
998

999
    if ((caps = qemuCreateCapabilities(qemu_driver->caps,
1000
                                       qemu_driver)) == NULL) {
1001 1002 1003
        virCapabilitiesFree(caps);
        goto cleanup;
    }
1004

1005
    virCapabilitiesFree(qemu_driver->caps);
1006 1007 1008
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1009
        virReportOOMError();
1010 1011

cleanup:
1012
    qemuDriverUnlock(driver);
1013

1014
    return xml;
1015 1016 1017
}


1018 1019 1020 1021 1022
static int
qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid,
                    int tid)
{
    char *proc;
D
Daniel P. Berrange 已提交
1023
    FILE *pidinfo;
1024
    unsigned long long usertime, systime;
1025 1026
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
1027

1028
    if (tid)
1029
        ret = virAsprintf(&proc, "/proc/%d/task/%d/stat", pid, tid);
1030
    else
1031 1032
        ret = virAsprintf(&proc, "/proc/%d/stat", pid);
    if (ret < 0)
D
Daniel P. Berrange 已提交
1033 1034 1035 1036
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
1037 1038 1039 1040
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
1041
        VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1042 1043
        return 0;
    }
1044
    VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1045

1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
    /* 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 */
               "%*d %*d %*d %*d %*d %*u %*u %*d %*u %*u %*u %*u"
               /* startstack -> processor */
               "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
               &usertime, &systime, &cpu) != 3) {
1056
        VIR_FORCE_FCLOSE(pidinfo);
1057
        VIR_WARN("cannot parse process status data");
1058
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
1059 1060 1061 1062 1063 1064 1065 1066
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
1067 1068 1069 1070 1071
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

D
Daniel P. Berrange 已提交
1072

1073 1074
    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
              pid, tid, usertime, systime, cpu);
D
Daniel P. Berrange 已提交
1075

1076
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
1077 1078 1079 1080 1081

    return 0;
}


1082
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
1083
                                          int id) {
1084 1085 1086 1087
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1088
    qemuDriverLock(driver);
1089
    vm  = virDomainFindByID(&driver->domains, id);
1090
    qemuDriverUnlock(driver);
1091 1092

    if (!vm) {
1093 1094
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching id %d"), id);
1095
        goto cleanup;
1096 1097
    }

1098
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1099
    if (dom) dom->id = vm->def->id;
1100 1101

cleanup:
1102 1103
    if (vm)
        virDomainObjUnlock(vm);
1104 1105
    return dom;
}
1106

1107
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
1108
                                            const unsigned char *uuid) {
1109 1110 1111
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1112

1113
    qemuDriverLock(driver);
1114
    vm = virDomainFindByUUID(&driver->domains, uuid);
1115 1116
    qemuDriverUnlock(driver);

1117
    if (!vm) {
1118 1119
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
1120 1121
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1122
        goto cleanup;
1123 1124
    }

1125
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1126
    if (dom) dom->id = vm->def->id;
1127 1128

cleanup:
1129 1130
    if (vm)
        virDomainObjUnlock(vm);
1131 1132
    return dom;
}
1133

1134
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
1135
                                            const char *name) {
1136 1137 1138
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1139

1140
    qemuDriverLock(driver);
1141
    vm = virDomainFindByName(&driver->domains, name);
1142 1143
    qemuDriverUnlock(driver);

1144
    if (!vm) {
1145 1146
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), name);
1147
        goto cleanup;
1148 1149
    }

1150
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1151
    if (dom) dom->id = vm->def->id;
1152 1153

cleanup:
1154 1155
    if (vm)
        virDomainObjUnlock(vm);
1156 1157 1158
    return dom;
}

1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169

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 已提交
1170 1171 1172 1173
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
        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 已提交
1194 1195 1196 1197
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
        goto cleanup;
    }
    ret = obj->persistent;

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

1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
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 已提交
1218 1219 1220 1221
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1222 1223 1224 1225 1226 1227 1228 1229 1230
        goto cleanup;
    }
    ret = obj->updated;

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

1232
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
1233 1234 1235
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

1236
    qemuDriverLock(driver);
1237
    if (qemuCapsExtractVersion(driver->caps, &driver->qemuVersion) < 0)
1238
        goto cleanup;
1239

1240
    *version = driver->qemuVersion;
1241 1242 1243
    ret = 0;

cleanup:
1244
    qemuDriverUnlock(driver);
1245
    return ret;
D
Daniel P. Berrange 已提交
1246 1247
}

1248
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
1249
    struct qemud_driver *driver = conn->privateData;
1250
    int n;
1251

1252
    qemuDriverLock(driver);
1253
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1254
    qemuDriverUnlock(driver);
1255

1256
    return n;
D
Daniel P. Berrange 已提交
1257
}
1258

1259
static int qemudNumDomains(virConnectPtr conn) {
1260
    struct qemud_driver *driver = conn->privateData;
1261
    int n;
1262

1263
    qemuDriverLock(driver);
1264
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1265
    qemuDriverUnlock(driver);
1266

1267
    return n;
D
Daniel P. Berrange 已提交
1268
}
1269

1270
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
1271
                                      unsigned int flags) {
1272
    struct qemud_driver *driver = conn->privateData;
1273
    virDomainDefPtr def;
1274
    virDomainObjPtr vm = NULL;
1275
    virDomainPtr dom = NULL;
1276
    virDomainEventPtr event = NULL;
1277
    virDomainEventPtr event2 = NULL;
D
Daniel P. Berrange 已提交
1278

1279 1280
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_AUTODESTROY, NULL);
1281

1282
    qemuDriverLock(driver);
1283
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1284
                                        QEMU_EXPECTED_VIRT_TYPES,
1285
                                        VIR_DOMAIN_XML_INACTIVE)))
1286
        goto cleanup;
1287

1288
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1289 1290
        goto cleanup;

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

1294 1295 1296
    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

1297
    if (qemuDomainAssignPCIAddresses(def) < 0)
1298 1299
        goto cleanup;

1300
    if (!(vm = virDomainAssignDef(driver->caps,
1301
                                  &driver->domains,
1302
                                  def, false)))
1303 1304 1305
        goto cleanup;

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

1307
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
1308 1309
        goto cleanup; /* XXXX free the 'vm' we created ? */

1310 1311
    if (qemuProcessStart(conn, driver, vm, NULL,
                         (flags & VIR_DOMAIN_START_PAUSED) != 0,
1312
                         (flags & VIR_DOMAIN_START_AUTODESTROY) != 0,
1313
                         -1, NULL, NULL, VIR_VM_OP_CREATE) < 0) {
1314
        virDomainAuditStart(vm, "booted", false);
1315
        if (qemuDomainObjEndJob(driver, vm) > 0)
1316 1317
            virDomainRemoveInactive(&driver->domains,
                                    vm);
1318
        vm = NULL;
1319
        goto cleanup;
D
Daniel P. Berrange 已提交
1320
    }
1321 1322 1323 1324

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
    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);
    }
1335
    virDomainAuditStart(vm, "booted", true);
D
Daniel P. Berrange 已提交
1336

1337
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1338
    if (dom) dom->id = vm->def->id;
1339

1340
    if (vm &&
1341
        qemuDomainObjEndJob(driver, vm) == 0)
1342
        vm = NULL;
1343

1344 1345
cleanup:
    virDomainDefFree(def);
1346 1347
    if (vm)
        virDomainObjUnlock(vm);
1348
    if (event) {
1349
        qemuDomainEventQueue(driver, event);
1350 1351 1352
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
1353
    qemuDriverUnlock(driver);
1354
    return dom;
D
Daniel P. Berrange 已提交
1355 1356 1357
}


1358
static int qemudDomainSuspend(virDomainPtr dom) {
1359 1360 1361
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1362
    virDomainEventPtr event = NULL;
1363
    qemuDomainObjPrivatePtr priv;
1364 1365
    virDomainPausedReason reason;
    int eventDetail;
1366

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

D
Daniel P. Berrange 已提交
1370
    if (!vm) {
1371 1372
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1373 1374
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1375
        goto cleanup;
D
Daniel P. Berrange 已提交
1376
    }
D
Daniel P. Berrange 已提交
1377
    if (!virDomainObjIsActive(vm)) {
1378 1379
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1380
        goto cleanup;
D
Daniel P. Berrange 已提交
1381
    }
1382 1383 1384

    priv = vm->privateData;

1385
    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) {
1386 1387
        reason = VIR_DOMAIN_PAUSED_MIGRATION;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED;
1388
    } else {
1389 1390 1391
        reason = VIR_DOMAIN_PAUSED_USER;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
    }
1392

1393 1394 1395 1396 1397 1398 1399 1400 1401
    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) {
1402
        if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) {
1403
            goto endjob;
1404
        }
1405 1406 1407
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         eventDetail);
D
Daniel P. Berrange 已提交
1408
    }
1409 1410 1411
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto endjob;
    ret = 0;
1412

1413
endjob:
1414
    if (qemuDomainObjEndJob(driver, vm) == 0)
1415
        vm = NULL;
1416

1417
cleanup:
1418 1419
    if (vm)
        virDomainObjUnlock(vm);
1420

1421
    if (event)
1422
        qemuDomainEventQueue(driver, event);
1423
    qemuDriverUnlock(driver);
1424
    return ret;
D
Daniel P. Berrange 已提交
1425 1426 1427
}


1428
static int qemudDomainResume(virDomainPtr dom) {
1429 1430 1431
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1432
    virDomainEventPtr event = NULL;
1433

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

D
Daniel P. Berrange 已提交
1437
    if (!vm) {
1438 1439
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1440 1441
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1442
        goto cleanup;
D
Daniel P. Berrange 已提交
1443
    }
1444

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

D
Daniel P. Berrange 已提交
1448
    if (!virDomainObjIsActive(vm)) {
1449 1450
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1451
        goto endjob;
D
Daniel P. Berrange 已提交
1452
    }
J
Jiri Denemark 已提交
1453 1454
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
        if (qemuProcessStartCPUs(driver, vm, dom->conn,
1455 1456
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
1457
            if (virGetLastError() == NULL)
1458 1459
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resume operation failed"));
1460
            goto endjob;
1461
        }
1462 1463 1464
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
1465
    }
1466
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
1467
        goto endjob;
1468 1469
    ret = 0;

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

1474
cleanup:
1475 1476
    if (vm)
        virDomainObjUnlock(vm);
1477
    if (event)
1478
        qemuDomainEventQueue(driver, event);
1479
    qemuDriverUnlock(driver);
1480
    return ret;
D
Daniel P. Berrange 已提交
1481 1482 1483
}


1484
static int qemuDomainShutdown(virDomainPtr dom) {
1485 1486 1487
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1488
    qemuDomainObjPrivatePtr priv;
1489

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

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

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

D
Daniel P. Berrange 已提交
1505
    if (!virDomainObjIsActive(vm)) {
1506 1507
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1508
        goto endjob;
1509 1510
    }

1511
    priv = vm->privateData;
1512
    qemuDomainObjEnterMonitor(driver, vm);
1513
    ret = qemuMonitorSystemPowerdown(priv->mon);
1514
    qemuDomainObjExitMonitor(driver, vm);
1515

1516 1517
    priv->fakeReboot = false;

1518
endjob:
1519
    if (qemuDomainObjEndJob(driver, vm) == 0)
1520
        vm = NULL;
1521

1522
cleanup:
1523 1524
    if (vm)
        virDomainObjUnlock(vm);
1525
    return ret;
1526 1527 1528
}


1529 1530 1531 1532
static int qemuDomainReboot(virDomainPtr dom, unsigned int flags) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1533
#if HAVE_YAJL
1534
    qemuDomainObjPrivatePtr priv;
1535
#endif
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551

    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 HAVE_YAJL
1552 1553
    priv = vm->privateData;

1554
    if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
1555
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
1556 1557 1558 1559 1560 1561 1562 1563
            goto cleanup;

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

1564
        qemuDomainObjEnterMonitor(driver, vm);
1565
        ret = qemuMonitorSystemPowerdown(priv->mon);
1566
        qemuDomainObjExitMonitor(driver, vm);
1567 1568 1569 1570

        priv->fakeReboot = true;

    endjob:
1571
        if (qemuDomainObjEndJob(driver, vm) == 0)
1572 1573 1574
            vm = NULL;
    } else {
#endif
1575
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
                        _("Reboot is not supported without the JSON monitor"));
#if HAVE_YAJL
    }
#endif

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


E
Eric Blake 已提交
1588
/* Locate an appropriate 'qemu-img' binary.  */
E
Eric Blake 已提交
1589 1590
static const char *
qemuFindQemuImgBinary(struct qemud_driver *driver)
E
Eric Blake 已提交
1591
{
E
Eric Blake 已提交
1592 1593 1594 1595 1596 1597 1598 1599
    if (!driver->qemuImgBinary) {
        driver->qemuImgBinary = virFindFileInPath("kvm-img");
        if (!driver->qemuImgBinary)
            driver->qemuImgBinary = virFindFileInPath("qemu-img");
        if (!driver->qemuImgBinary)
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("unable to find kvm-img or qemu-img"));
    }
E
Eric Blake 已提交
1600

E
Eric Blake 已提交
1601
    return driver->qemuImgBinary;
E
Eric Blake 已提交
1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
}

static int
qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
                                virDomainSnapshotObjPtr snapshot,
                                char *snapshotDir)
{
    int fd = -1;
    char *newxml = NULL;
    int ret = -1;
    char *snapDir = NULL;
    char *snapFile = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1615
    char *tmp;
E
Eric Blake 已提交
1616 1617

    virUUIDFormat(vm->def->uuid, uuidstr);
1618 1619
    newxml = virDomainSnapshotDefFormat(uuidstr, snapshot->def,
                                        VIR_DOMAIN_XML_SECURE, 1);
E
Eric Blake 已提交
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
    if (newxml == NULL) {
        virReportOOMError();
        return -1;
    }

    if (virAsprintf(&snapDir, "%s/%s", snapshotDir, vm->def->name) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    if (virFileMakePath(snapDir) < 0) {
        virReportSystemError(errno, _("cannot create snapshot directory '%s'"),
                             snapDir);
        goto cleanup;
    }

    if (virAsprintf(&snapFile, "%s/%s.xml", snapDir, snapshot->def->name) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    fd = open(snapFile, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
    if (fd < 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("failed to create snapshot file '%s'"), snapFile);
        goto cleanup;
    }
1645 1646 1647 1648 1649 1650 1651 1652

    if (virAsprintf(&tmp, "snapshot-edit %s", vm->def->name) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    virEmitXMLWarning(fd, snapshot->def->name, tmp);
    VIR_FREE(tmp);

E
Eric Blake 已提交
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671
    if (safewrite(fd, newxml, strlen(newxml)) != strlen(newxml)) {
        virReportSystemError(errno, _("Failed to write snapshot data to %s"),
                             snapFile);
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(snapFile);
    VIR_FREE(snapDir);
    VIR_FREE(newxml);
    VIR_FORCE_CLOSE(fd);
    return ret;
}

/* The domain is expected to be locked and inactive. Return -1 on normal
 * failure, 1 if we skipped a disk due to try_all.  */
static int
E
Eric Blake 已提交
1672 1673
qemuDomainSnapshotForEachQcow2(struct qemud_driver *driver,
                               virDomainObjPtr vm,
E
Eric Blake 已提交
1674 1675 1676 1677 1678 1679 1680 1681 1682
                               virDomainSnapshotObjPtr snap,
                               const char *op,
                               bool try_all)
{
    const char *qemuimgarg[] = { NULL, "snapshot", NULL, NULL, NULL, NULL };
    int ret = -1;
    int i;
    bool skipped = false;

E
Eric Blake 已提交
1683
    qemuimgarg[0] = qemuFindQemuImgBinary(driver);
E
Eric Blake 已提交
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 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
    if (qemuimgarg[0] == NULL) {
        /* qemuFindQemuImgBinary set the error */
        goto cleanup;
    }

    qemuimgarg[2] = op;
    qemuimgarg[3] = snap->def->name;

    for (i = 0; i < vm->def->ndisks; i++) {
        /* FIXME: we also need to handle LVM here */
        /* FIXME: if we fail halfway through this loop, we are in an
         * inconsistent state.  I'm not quite sure what to do about that
         */
        if (vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
            if (!vm->def->disks[i]->driverType ||
                STRNEQ(vm->def->disks[i]->driverType, "qcow2")) {
                if (try_all) {
                    /* Continue on even in the face of error, since other
                     * disks in this VM may have the same snapshot name.
                     */
                    VIR_WARN("skipping snapshot action on %s",
                             vm->def->disks[i]->info.alias);
                    skipped = true;
                    continue;
                }
                qemuReportError(VIR_ERR_OPERATION_INVALID,
                                _("Disk device '%s' does not support"
                                  " snapshotting"),
                                vm->def->disks[i]->info.alias);
                goto cleanup;
            }

            qemuimgarg[4] = vm->def->disks[i]->src;

            if (virRun(qemuimgarg, NULL) < 0) {
                if (try_all) {
                    VIR_WARN("skipping snapshot action on %s",
                             vm->def->disks[i]->info.alias);
                    skipped = true;
                    continue;
                }
                goto cleanup;
            }
        }
    }

    ret = skipped ? 1 : 0;

cleanup:
    VIR_FREE(qemuimgarg[0]);
    return ret;
}

/* Discard one snapshot (or its metadata), without reparenting any children.  */
static int
qemuDomainSnapshotDiscard(struct qemud_driver *driver,
                          virDomainObjPtr vm,
                          virDomainSnapshotObjPtr snap,
                          bool update_current,
                          bool metadata_only)
{
    char *snapFile = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
    virDomainSnapshotObjPtr parentsnap = NULL;

    if (!metadata_only) {
        if (!virDomainObjIsActive(vm)) {
            /* Ignore any skipped disks */
E
Eric Blake 已提交
1753 1754
            if (qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-d",
                                               true) < 0)
E
Eric Blake 已提交
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
                goto cleanup;
        } else {
            priv = vm->privateData;
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            /* we continue on even in the face of error */
            qemuMonitorDeleteSnapshot(priv->mon, snap->def->name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
        }
    }

    if (virAsprintf(&snapFile, "%s/%s/%s.xml", driver->snapshotDir,
                    vm->def->name, snap->def->name) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    if (snap == vm->current_snapshot) {
        if (update_current && snap->def->parent) {
            parentsnap = virDomainSnapshotFindByName(&vm->snapshots,
                                                     snap->def->parent);
            if (!parentsnap) {
                VIR_WARN("missing parent snapshot matching name '%s'",
                         snap->def->parent);
            } else {
                parentsnap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, parentsnap,
                                                    driver->snapshotDir) < 0) {
                    VIR_WARN("failed to set parent snapshot '%s' as current",
                             snap->def->parent);
                    parentsnap->def->current = false;
                    parentsnap = NULL;
                }
            }
        }
        vm->current_snapshot = parentsnap;
    }

    if (unlink(snapFile) < 0)
        VIR_WARN("Failed to unlink %s", snapFile);
    virDomainSnapshotObjListRemove(&vm->snapshots, snap);

    ret = 0;

cleanup:
    VIR_FREE(snapFile);

    return ret;
}

struct snap_remove {
    struct qemud_driver *driver;
    virDomainObjPtr vm;
    int err;
    bool metadata_only;
    bool current;
};

/* Hash iterator callback to discard multiple snapshots.  */
static void
qemuDomainSnapshotDiscardAll(void *payload,
                             const void *name ATTRIBUTE_UNUSED,
                             void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    struct snap_remove *curr = data;
    int err;

    if (snap->def->current)
        curr->current = true;
    err = qemuDomainSnapshotDiscard(curr->driver, curr->vm, snap, false,
                                    curr->metadata_only);
    if (err && !curr->err)
        curr->err = err;
}

1830 1831 1832 1833
static int
qemuDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
1834 1835 1836
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1837
    virDomainEventPtr event = NULL;
1838
    qemuDomainObjPrivatePtr priv;
1839

1840 1841
    virCheckFlags(0, -1);

1842
    qemuDriverLock(driver);
1843
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
1844
    if (!vm) {
1845 1846
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1847 1848
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1849
        goto cleanup;
D
Daniel P. Berrange 已提交
1850
    }
1851

1852 1853 1854
    priv = vm->privateData;
    priv->fakeReboot = false;

1855 1856 1857 1858 1859 1860 1861
    /* 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
     */
    qemuProcessKill(vm);

1862
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_DESTROY) < 0)
1863 1864
        goto cleanup;

D
Daniel P. Berrange 已提交
1865
    if (!virDomainObjIsActive(vm)) {
1866 1867
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1868
        goto endjob;
1869
    }
1870

J
Jiri Denemark 已提交
1871
    qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_DESTROYED);
1872 1873 1874
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1875
    virDomainAuditStop(vm, "destroyed");
1876

1877
    if (!vm->persistent) {
1878
        if (qemuDomainObjEndJob(driver, vm) > 0)
1879 1880
            virDomainRemoveInactive(&driver->domains,
                                    vm);
1881 1882
        vm = NULL;
    }
1883 1884
    ret = 0;

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

1890
cleanup:
1891 1892
    if (vm)
        virDomainObjUnlock(vm);
1893 1894
    if (event)
        qemuDomainEventQueue(driver, event);
1895
    qemuDriverUnlock(driver);
1896
    return ret;
D
Daniel P. Berrange 已提交
1897 1898
}

1899 1900 1901 1902 1903
static int
qemuDomainDestroy(virDomainPtr dom)
{
    return qemuDomainDestroyFlags(dom, 0);
}
D
Daniel P. Berrange 已提交
1904

1905
static char *qemudDomainGetOSType(virDomainPtr dom) {
1906 1907 1908
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1909

1910
    qemuDriverLock(driver);
1911
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1912
    qemuDriverUnlock(driver);
1913
    if (!vm) {
1914 1915
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1916 1917
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1918
        goto cleanup;
1919 1920
    }

1921
    if (!(type = strdup(vm->def->os.type)))
1922
        virReportOOMError();
1923 1924

cleanup:
1925 1926
    if (vm)
        virDomainObjUnlock(vm);
1927 1928 1929
    return type;
}

1930 1931
/* Returns max memory in kb, 0 if error */
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
1932 1933 1934
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
1935

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

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

1948
    ret = vm->def->mem.max_balloon;
1949 1950

cleanup:
1951 1952
    if (vm)
        virDomainObjUnlock(vm);
1953
    return ret;
1954 1955
}

1956 1957
static int qemudDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                     unsigned int flags) {
1958
    struct qemud_driver *driver = dom->conn->privateData;
1959
    qemuDomainObjPrivatePtr priv;
1960
    virDomainObjPtr vm;
1961
    virDomainDefPtr persistentDef = NULL;
1962
    int ret = -1, r;
1963
    bool isActive;
1964

1965 1966
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
1967
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
1968

1969
    qemuDriverLock(driver);
1970
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1971
    qemuDriverUnlock(driver);
1972
    if (!vm) {
1973 1974
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1975 1976
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1977
        goto cleanup;
1978 1979
    }

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

1983 1984
    isActive = virDomainObjIsActive(vm);

1985
    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
1986
        if (isActive)
1987
            flags = VIR_DOMAIN_AFFECT_LIVE;
1988
        else
1989
            flags = VIR_DOMAIN_AFFECT_CONFIG;
1990
    }
1991 1992
    if (flags == VIR_DOMAIN_MEM_MAXIMUM) {
        if (isActive)
1993
            flags = VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_MEM_MAXIMUM;
1994
        else
1995
            flags = VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_MEM_MAXIMUM;
1996
    }
1997

1998
    if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
1999 2000 2001 2002 2003
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }

2004
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2005 2006 2007 2008 2009 2010 2011 2012
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot change persistent config of a transient domain"));
            goto endjob;
        }
        if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
            goto endjob;
    }
2013

2014 2015 2016
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */

2017
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2018 2019 2020
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot resize the maximum memory on an "
                              "active domain"));
2021
            goto endjob;
2022
        }
2023

2024
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2025 2026
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
2027 2028 2029 2030
            persistentDef->mem.max_balloon = newmem;
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
            ret = virDomainSaveConfig(driver->configDir, persistentDef);
2031 2032 2033
            goto endjob;
        }

2034 2035 2036 2037 2038 2039 2040 2041 2042
    } 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;
        }

2043
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2044
            priv = vm->privateData;
2045
            qemuDomainObjEnterMonitor(driver, vm);
2046
            r = qemuMonitorSetBalloon(priv->mon, newmem);
2047
            qemuDomainObjExitMonitor(driver, vm);
2048 2049
            virDomainAuditMemory(vm, vm->def->mem.cur_balloon, newmem, "update",
                                 r == 1);
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060
            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;
            }
        }

2061
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2062
            sa_assert(persistentDef);
2063 2064 2065 2066
            persistentDef->mem.cur_balloon = newmem;
            ret = virDomainSaveConfig(driver->configDir, persistentDef);
            goto endjob;
        }
2067
    }
2068

2069
    ret = 0;
2070
endjob:
2071
    if (qemuDomainObjEndJob(driver, vm) == 0)
2072
        vm = NULL;
2073

2074
cleanup:
2075 2076
    if (vm)
        virDomainObjUnlock(vm);
2077
    return ret;
2078 2079
}

2080 2081
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
2082
    return qemudDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
2083 2084
}

2085 2086 2087 2088 2089
static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
{
    return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
}

2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116
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;

2117
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
2118
        goto cleanup;
2119
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2120 2121
    ret = qemuMonitorInjectNMI(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2122
    if (qemuDomainObjEndJob(driver, vm) == 0) {
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133
        vm = NULL;
        goto cleanup;
    }

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

2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147
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);

2148 2149
    /* translate the keycode to RFB for qemu driver */
    if (codeset != VIR_KEYCODE_SET_RFB) {
2150 2151 2152 2153
        int i;
        int keycode;

        for (i = 0; i < nkeycodes; i++) {
2154
            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_RFB,
2155 2156 2157
                                               keycodes[i]);
            if (keycode < 0) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
2158
             _("cannot translate keycode %u of %s codeset to rfb keycode"),
2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187
                                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"));
        goto cleanup;
    }

2188
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

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

2203
static int qemudDomainGetInfo(virDomainPtr dom,
2204 2205
                              virDomainInfoPtr info)
{
2206 2207 2208
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2209 2210
    int err;
    unsigned long balloon;
2211

2212
    qemuDriverLock(driver);
2213
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2214
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
2215
    if (!vm) {
2216 2217
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2218 2219
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
2220
        goto cleanup;
D
Daniel P. Berrange 已提交
2221 2222
    }

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

D
Daniel P. Berrange 已提交
2225
    if (!virDomainObjIsActive(vm)) {
2226
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2227
    } else {
2228
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
E
Eric Blake 已提交
2229 2230
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("cannot read cputime for domain"));
2231
            goto cleanup;
D
Daniel P. Berrange 已提交
2232 2233 2234
        }
    }

2235
    info->maxMem = vm->def->mem.max_balloon;
2236

D
Daniel P. Berrange 已提交
2237
    if (virDomainObjIsActive(vm)) {
2238
        qemuDomainObjPrivatePtr priv = vm->privateData;
2239 2240 2241

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
2242
            info->memory = vm->def->mem.max_balloon;
2243
        } else if (!priv->job.active) {
2244
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
2245
                goto cleanup;
2246 2247 2248
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
2249
                qemuDomainObjEnterMonitor(driver, vm);
2250
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
2251
                qemuDomainObjExitMonitor(driver, vm);
2252
            }
2253
            if (qemuDomainObjEndJob(driver, vm) == 0) {
2254
                vm = NULL;
2255 2256 2257
                goto cleanup;
            }

2258 2259
            if (err < 0)
                goto cleanup;
2260 2261
            if (err == 0)
                /* Balloon not supported, so maxmem is always the allocation */
2262
                info->memory = vm->def->mem.max_balloon;
2263 2264 2265
            else
                info->memory = balloon;
        } else {
2266
            info->memory = vm->def->mem.cur_balloon;
2267
        }
2268
    } else {
2269
        info->memory = vm->def->mem.cur_balloon;
2270 2271
    }

2272
    info->nrVirtCpu = vm->def->vcpus;
2273 2274 2275
    ret = 0;

cleanup:
2276 2277
    if (vm)
        virDomainObjUnlock(vm);
2278
    return ret;
D
Daniel P. Berrange 已提交
2279 2280
}

2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304
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 已提交
2305
    *state = virDomainObjGetState(vm, reason);
2306 2307 2308 2309 2310 2311 2312 2313
    ret = 0;

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

2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349
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;
2350
    } else if (priv->job.active) {
2351 2352 2353 2354
        if (!priv->monStart) {
            info->state = VIR_DOMAIN_CONTROL_JOB;
            if (virTimeMs(&info->stateTime) < 0)
                goto cleanup;
2355
            info->stateTime -= priv->job.start;
2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373
        } else {
            info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
            if (virTimeMs(&info->stateTime) < 0)
                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 已提交
2374

E
Eric Blake 已提交
2375 2376
#define QEMUD_SAVE_MAGIC   "LibvirtQemudSave"
#define QEMUD_SAVE_PARTIAL "LibvirtQemudPart"
2377 2378
#define QEMUD_SAVE_VERSION 2

E
Eric Blake 已提交
2379 2380
verify(sizeof(QEMUD_SAVE_MAGIC) == sizeof(QEMUD_SAVE_PARTIAL));

2381
enum qemud_save_formats {
2382 2383 2384
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
2385 2386
    /*
     * Deprecated by xz and never used as part of a release
2387
     * QEMUD_SAVE_FORMAT_LZMA
2388 2389
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
2390
    QEMUD_SAVE_FORMAT_LZOP = 4,
2391 2392 2393
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2394 2395

    QEMUD_SAVE_FORMAT_LAST
2396
};
2397

2398 2399 2400 2401 2402
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
2403 2404
              "xz",
              "lzop")
2405

2406 2407
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
2408 2409 2410 2411 2412
    uint32_t version;
    uint32_t xml_len;
    uint32_t was_running;
    uint32_t compressed;
    uint32_t unused[15];
2413 2414
};

2415 2416 2417 2418 2419 2420 2421 2422 2423
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);
}


2424
/* return -errno on failure, or 0 on success */
E
Eric Blake 已提交
2425 2426 2427 2428
static int
qemuDomainSaveHeader(int fd, const char *path, char *xml,
                     struct qemud_save_header *header)
{
2429 2430
    int ret = 0;

E
Eric Blake 已提交
2431
    if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
2432
        ret = -errno;
2433
        qemuReportError(VIR_ERR_OPERATION_FAILED,
2434
                        _("failed to write header to domain save file '%s'"),
E
Eric Blake 已提交
2435
                        path);
2436 2437 2438
        goto endjob;
    }

E
Eric Blake 已提交
2439
    if (safewrite(fd, xml, header->xml_len) != header->xml_len) {
2440
        ret = -errno;
2441
        qemuReportError(VIR_ERR_OPERATION_FAILED,
E
Eric Blake 已提交
2442
                         _("failed to write xml to '%s'"), path);
2443 2444 2445 2446 2447 2448
        goto endjob;
    }
endjob:
    return ret;
}

2449 2450 2451 2452 2453 2454 2455 2456 2457
/* 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 已提交
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 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564
/* 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;
    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;
        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 {
        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR,
                                uid, gid, 0)) < 0) {
            /* 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,
                                    VIR_FILE_OPEN_AS_UID)) < 0) {
                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;
}

2565
/* This internal function expects the driver lock to already be held on
2566 2567 2568 2569
 * 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).
2570
 */
2571 2572 2573
static int
qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
                       virDomainObjPtr vm, const char *path,
2574
                       int compressed, const char *xmlin, unsigned int flags)
2575
{
2576
    char *xml = NULL;
2577
    struct qemud_save_header header;
2578
    bool bypassSecurityDriver = false;
2579
    int ret = -1;
2580
    int rc;
2581
    virDomainEventPtr event = NULL;
2582
    qemuDomainObjPrivatePtr priv;
E
Eric Blake 已提交
2583
    bool needUnlink = false;
2584
    size_t len;
2585
    unsigned long long offset;
2586
    unsigned long long pad;
2587
    int fd = -1;
2588 2589
    int directFlag = 0;
    virFileDirectFdPtr directFd = NULL;
2590
    bool bypass_cache = flags & VIR_DOMAIN_SAVE_BYPASS_CACHE;
2591

2592 2593 2594
    if (qemuProcessAutoDestroyActive(driver, vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is marked for auto destroy"));
2595
        goto cleanup;
2596 2597
    }

2598
    memset(&header, 0, sizeof(header));
E
Eric Blake 已提交
2599
    memcpy(header.magic, QEMUD_SAVE_PARTIAL, sizeof(header.magic));
2600 2601
    header.version = QEMUD_SAVE_VERSION;

2602
    header.compressed = compressed;
2603

2604
    priv = vm->privateData;
2605

2606 2607
    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_SAVE) < 0)
2608 2609
        goto cleanup;

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

2613
    /* Pause */
J
Jiri Denemark 已提交
2614
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
2615
        header.was_running = 1;
2616 2617
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_SAVE) < 0)
2618
            goto endjob;
2619 2620 2621 2622 2623 2624

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto endjob;
        }
2625
    }
2626 2627 2628 2629 2630
    /* 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;
2631

2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653
    /* 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;
        }
        xml = virDomainDefFormat(def, (VIR_DOMAIN_XML_INACTIVE |
                                       VIR_DOMAIN_XML_SECURE));
    } else {
        xml = virDomainDefFormat(vm->def, (VIR_DOMAIN_XML_INACTIVE |
                                           VIR_DOMAIN_XML_SECURE));
    }
2654
    if (!xml) {
2655 2656
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
2657
        goto endjob;
2658
    }
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678
    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;
2679

2680
    /* Obtain the file handle.  */
2681 2682 2683 2684 2685
    if (bypass_cache) {
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("bypass cache unsupported by this system"));
E
Eric Blake 已提交
2686
            goto cleanup;
2687
        }
2688
    }
E
Eric Blake 已提交
2689 2690 2691 2692
    fd = qemuOpenFile(driver, path, O_WRONLY | O_TRUNC | O_CREAT | directFlag,
                      &needUnlink, &bypassSecurityDriver);
    if (fd < 0)
        goto endjob;
2693 2694 2695
    if (bypass_cache && (directFd = virFileDirectFdNew(&fd, path)) == NULL)
        goto endjob;

2696
    /* Write header to file, followed by XML */
E
Eric Blake 已提交
2697
    if (qemuDomainSaveHeader(fd, path, xml, &header) < 0) {
2698 2699 2700 2701
        VIR_FORCE_CLOSE(fd);
        goto endjob;
    }

2702
    /* Perform the migration */
2703
    if (qemuMigrationToFile(driver, vm, fd, offset, path,
2704
                            qemuCompressProgramName(compressed),
E
Eric Blake 已提交
2705
                            bypassSecurityDriver,
2706
                            QEMU_ASYNC_JOB_SAVE) < 0)
2707
        goto endjob;
E
Eric Blake 已提交
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734

    /* Touch up file header to mark image complete.  */
    if (bypass_cache) {
        /* Reopen the file to touch up the header, since we aren't set
         * up to seek backwards on directFd.  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;
        }
        if (virFileDirectFdClose(directFd) < 0)
            goto endjob;
        fd = qemuOpenFile(driver, path, O_WRONLY, NULL, NULL);
        if (fd < 0)
            goto endjob;
    } else {
        if (lseek(fd, 0, SEEK_SET) != 0) {
            virReportSystemError(errno, _("unable to seek %s"), path);
            goto endjob;
        }
    }
    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;
    }
2735 2736
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
2737
        goto endjob;
2738 2739
    }

2740 2741
    ret = 0;

2742
    /* Shut it down */
J
Jiri Denemark 已提交
2743
    qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_SAVED);
2744
    virDomainAuditStop(vm, "saved");
2745 2746 2747
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
2748
    if (!vm->persistent) {
2749
        if (qemuDomainObjEndAsyncJob(driver, vm) > 0)
2750 2751
            virDomainRemoveInactive(&driver->domains,
                                    vm);
2752 2753
        vm = NULL;
    }
2754

2755
endjob:
2756
    if (vm) {
2757
        if (ret != 0) {
2758
            if (header.was_running && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
2759
                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
2760 2761
                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED,
                                          QEMU_ASYNC_JOB_SAVE);
2762
                if (rc < 0)
2763
                    VIR_WARN("Unable to resume guest CPUs after save failure");
2764
            }
2765
        }
2766
        if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
2767
            vm = NULL;
2768
    }
2769

2770
cleanup:
2771
    VIR_FORCE_CLOSE(fd);
2772
    virFileDirectFdFree(directFd);
2773
    VIR_FREE(xml);
E
Eric Blake 已提交
2774
    if (ret != 0 && needUnlink)
2775
        unlink(path);
2776 2777
    if (event)
        qemuDomainEventQueue(driver, event);
2778 2779
    if (vm)
        virDomainObjUnlock(vm);
2780
    return ret;
D
Daniel P. Berrange 已提交
2781 2782
}

2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798
/* 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;
}

2799 2800 2801
static int
qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                    unsigned int flags)
2802 2803 2804
{
    struct qemud_driver *driver = dom->conn->privateData;
    int compressed;
2805 2806 2807
    int ret = -1;
    virDomainObjPtr vm = NULL;

2808 2809 2810
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
2811

2812
    qemuDriverLock(driver);
2813 2814 2815 2816 2817 2818 2819 2820 2821

    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"));
2822
            goto cleanup;
2823
        }
2824 2825 2826 2827
        if (!qemudCompressProgramAvailable(compressed)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Compression program for image format "
                                    "in configuration file isn't available"));
2828
            goto cleanup;
2829
        }
2830 2831
    }

2832 2833 2834 2835 2836 2837 2838 2839 2840
    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;
    }

2841 2842 2843 2844 2845 2846
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2847
    ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
2848
                                 dxml, flags);
2849
    vm = NULL;
2850 2851 2852 2853 2854 2855 2856

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

    return ret;
2857 2858
}

2859 2860 2861 2862 2863 2864
static int
qemuDomainSave(virDomainPtr dom, const char *path)
{
    return qemuDomainSaveFlags(dom, path, NULL, 0);
}

2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885
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;

2886 2887 2888
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
2889 2890 2891 2892 2893 2894 2895 2896

    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);
2897
        goto cleanup;
2898 2899
    }

2900 2901 2902 2903 2904
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }
2905 2906 2907 2908 2909
    if (!vm->persistent) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot do managed save for transient domain"));
        goto cleanup;
    }
2910

2911 2912
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
2913
        goto cleanup;
2914

2915
    VIR_INFO("Saving state to %s", name);
2916 2917

    compressed = QEMUD_SAVE_FORMAT_RAW;
2918
    ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
2919
                                 NULL, flags);
2920
    vm = NULL;
2921 2922 2923 2924 2925

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
2926 2927 2928
    VIR_FREE(name);

    return ret;
2929 2930 2931 2932 2933 2934 2935 2936 2937 2938
}

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

2939
    virCheckFlags(0, -1);
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972

    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;

2973
    virCheckFlags(0, -1);
2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997

    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 已提交
2998

2999 3000 3001 3002
static int
doCoreDump(struct qemud_driver *driver,
           virDomainObjPtr vm,
           const char *path,
3003 3004
           enum qemud_save_formats compress,
           bool bypass_cache)
H
Hu Tao 已提交
3005 3006 3007
{
    int fd = -1;
    int ret = -1;
3008 3009
    virFileDirectFdPtr directFd = NULL;
    int directFlag = 0;
H
Hu Tao 已提交
3010 3011

    /* Create an empty file with appropriate ownership.  */
3012 3013 3014 3015 3016 3017 3018 3019
    if (bypass_cache) {
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("bypass cache unsupported by this system"));
            goto cleanup;
        }
    }
E
Eric Blake 已提交
3020 3021 3022 3023 3024 3025
    /* 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 已提交
3026 3027
        goto cleanup;

3028 3029 3030
    if (bypass_cache && (directFd = virFileDirectFdNew(&fd, path)) == NULL)
        goto cleanup;

3031
    if (qemuMigrationToFile(driver, vm, fd, 0, path,
E
Eric Blake 已提交
3032
                            qemuCompressProgramName(compress), false,
3033
                            QEMU_ASYNC_JOB_DUMP) < 0)
3034 3035
        goto cleanup;

H
Hu Tao 已提交
3036 3037 3038 3039 3040 3041
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
                             _("unable to save file %s"),
                             path);
        goto cleanup;
    }
3042 3043
    if (virFileDirectFdClose(directFd) < 0)
        goto cleanup;
H
Hu Tao 已提交
3044

3045
    ret = 0;
H
Hu Tao 已提交
3046 3047

cleanup:
3048
    VIR_FORCE_CLOSE(fd);
3049
    virFileDirectFdFree(directFd);
H
Hu Tao 已提交
3050 3051 3052 3053 3054
    if (ret != 0)
        unlink(path);
    return ret;
}

3055 3056 3057 3058 3059
static enum qemud_save_formats
getCompressionType(struct qemud_driver *driver)
{
    int compress = QEMUD_SAVE_FORMAT_RAW;

3060 3061 3062 3063 3064 3065
    /*
     * 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);
3066 3067 3068
        /* Use "raw" as the format if the specified format is not valid,
         * or the compress program is not available.
         */
3069
        if (compress < 0) {
3070 3071
            VIR_WARN("%s", _("Invalid dump image format specified in "
                             "configuration file, using raw"));
3072
            return QEMUD_SAVE_FORMAT_RAW;
3073
        }
3074
        if (!qemudCompressProgramAvailable(compress)) {
3075 3076 3077
            VIR_WARN("%s", _("Compression program for dump image format "
                             "in configuration file isn't available, "
                             "using raw"));
3078
            return QEMUD_SAVE_FORMAT_RAW;
3079
        }
3080
    }
3081 3082 3083 3084 3085
    return compress;
}

static int qemudDomainCoreDump(virDomainPtr dom,
                               const char *path,
3086
                               unsigned int flags)
3087
{
3088 3089 3090
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int resume = 0, paused = 0;
H
Hu Tao 已提交
3091
    int ret = -1;
3092 3093
    virDomainEventPtr event = NULL;

3094
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH | VIR_DUMP_BYPASS_CACHE, -1);
3095

P
Paolo Bonzini 已提交
3096 3097 3098 3099 3100 3101
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3102 3103
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
3104 3105 3106
        goto cleanup;
    }

3107 3108
    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_DUMP) < 0)
3109 3110
        goto cleanup;

D
Daniel P. Berrange 已提交
3111
    if (!virDomainObjIsActive(vm)) {
3112 3113
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
3114
        goto endjob;
P
Paolo Bonzini 已提交
3115 3116
    }

P
Paolo Bonzini 已提交
3117 3118
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
J
Jiri Denemark 已提交
3119
    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
3120 3121

    /* Pause domain for non-live dump */
J
Jiri Denemark 已提交
3122 3123
    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3124 3125
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP,
                                QEMU_ASYNC_JOB_DUMP) < 0)
3126
            goto endjob;
P
Paolo Bonzini 已提交
3127
        paused = 1;
3128 3129 3130 3131 3132 3133

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

3136 3137
    ret = doCoreDump(driver, vm, path, getCompressionType(driver),
                     (flags & VIR_DUMP_BYPASS_CACHE) != 0);
3138 3139 3140 3141
    if (ret < 0)
        goto endjob;

    paused = 1;
3142 3143

endjob:
3144
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
J
Jiri Denemark 已提交
3145
        qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_CRASHED);
3146
        virDomainAuditStop(vm, "crashed");
3147 3148 3149 3150 3151
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
3152 3153 3154
    /* 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.  */
3155
    else if (resume && paused && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
3156
        if (qemuProcessStartCPUs(driver, vm, dom->conn,
3157 3158
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_DUMP) < 0) {
3159
            if (virGetLastError() == NULL)
3160 3161
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3162 3163
        }
    }
3164

3165
    if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3166
        vm = NULL;
3167
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
3168 3169 3170 3171
        virDomainRemoveInactive(&driver->domains,
                                vm);
        vm = NULL;
    }
3172 3173

cleanup:
P
Paolo Bonzini 已提交
3174 3175
    if (vm)
        virDomainObjUnlock(vm);
3176 3177
    if (event)
        qemuDomainEventQueue(driver, event);
3178
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
3179 3180 3181
    return ret;
}

3182 3183 3184 3185
static char *
qemuDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
3186
                     unsigned int flags)
3187 3188 3189 3190 3191 3192 3193
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *tmp = NULL;
    int tmp_fd = -1;
    char *ret = NULL;
E
Eric Blake 已提交
3194
    bool unlink_tmp = false;
3195

E
Eric Blake 已提交
3196 3197
    virCheckFlags(0, NULL);

3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211
    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;

3212
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238
        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 已提交
3239
    unlink_tmp = true;
3240

3241 3242
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm, tmp);

3243
    qemuDomainObjEnterMonitor(driver, vm);
3244
    if (qemuMonitorScreendump(priv->mon, tmp) < 0) {
3245
        qemuDomainObjExitMonitor(driver, vm);
3246 3247
        goto endjob;
    }
3248
    qemuDomainObjExitMonitor(driver, vm);
3249 3250 3251 3252 3253 3254

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

E
Eric Blake 已提交
3255
    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
3256 3257 3258 3259 3260 3261 3262 3263 3264
        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 已提交
3265 3266
    if (unlink_tmp)
        unlink(tmp);
E
Eric Blake 已提交
3267
    VIR_FREE(tmp);
3268

3269
    if (qemuDomainObjEndJob(driver, vm) == 0)
3270 3271 3272 3273 3274 3275 3276 3277
        vm = NULL;

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

H
Hu Tao 已提交
3278 3279 3280
static void processWatchdogEvent(void *data, void *opaque)
{
    int ret;
3281
    struct qemuDomainWatchdogEvent *wdEvent = data;
H
Hu Tao 已提交
3282 3283
    struct qemud_driver *driver = opaque;

W
Wen Congyang 已提交
3284 3285 3286
    qemuDriverLock(driver);
    virDomainObjLock(wdEvent->vm);

H
Hu Tao 已提交
3287 3288 3289 3290 3291
    switch (wdEvent->action) {
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;

E
Eric Blake 已提交
3292
            if (virAsprintf(&dumpfile, "%s/%s-%u",
H
Hu Tao 已提交
3293 3294
                            driver->autoDumpPath,
                            wdEvent->vm->def->name,
E
Eric Blake 已提交
3295 3296
                            (unsigned int)time(NULL)) < 0) {
                virReportOOMError();
W
Wen Congyang 已提交
3297
                goto unlock;
E
Eric Blake 已提交
3298
            }
H
Hu Tao 已提交
3299

3300 3301
            if (qemuDomainObjBeginAsyncJobWithDriver(driver, wdEvent->vm,
                                                     QEMU_ASYNC_JOB_DUMP) < 0) {
W
Wen Congyang 已提交
3302 3303 3304
                VIR_FREE(dumpfile);
                goto unlock;
            }
H
Hu Tao 已提交
3305 3306 3307 3308

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

3313
            ret = doCoreDump(driver, wdEvent->vm, dumpfile,
3314 3315
                             getCompressionType(driver),
                             driver->autoDumpBypassCache);
H
Hu Tao 已提交
3316 3317 3318 3319
            if (ret < 0)
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("Dump failed"));

J
Jiri Denemark 已提交
3320
            ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL,
3321 3322
                                       VIR_DOMAIN_RUNNING_UNPAUSED,
                                       QEMU_ASYNC_JOB_DUMP);
H
Hu Tao 已提交
3323 3324 3325 3326 3327 3328 3329 3330

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

            VIR_FREE(dumpfile);
        }
        break;
W
Wen Congyang 已提交
3331 3332
    default:
        goto unlock;
H
Hu Tao 已提交
3333 3334
    }

W
Wen Congyang 已提交
3335 3336 3337 3338
endjob:
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleWatchdog().
     */
3339
    ignore_value(qemuDomainObjEndAsyncJob(driver, wdEvent->vm));
W
Wen Congyang 已提交
3340 3341 3342 3343 3344

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

3348 3349 3350
static int qemudDomainHotplugVcpus(struct qemud_driver *driver,
                                   virDomainObjPtr vm,
                                   unsigned int nvcpus)
3351 3352
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3353
    int i, rc = 1;
3354
    int ret = -1;
3355
    int oldvcpus = vm->def->vcpus;
E
Eric Blake 已提交
3356
    int vcpus = oldvcpus;
3357

3358
    qemuDomainObjEnterMonitor(driver, vm);
3359

3360 3361 3362
    /* 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 已提交
3363 3364
    if (nvcpus > vcpus) {
        for (i = vcpus ; i < nvcpus ; i++) {
3365 3366 3367 3368 3369 3370 3371
            /* Online new CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3372
            vcpus++;
3373 3374
        }
    } else {
E
Eric Blake 已提交
3375
        for (i = vcpus - 1 ; i >= nvcpus ; i--) {
3376 3377 3378 3379 3380 3381 3382
            /* Offline old CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3383
            vcpus--;
3384 3385 3386 3387 3388 3389
        }
    }

    ret = 0;

cleanup:
3390
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
3391
    vm->def->vcpus = vcpus;
3392
    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
3393 3394 3395 3396 3397 3398 3399 3400 3401
    return ret;

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


3402
static int
3403 3404
qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3405
{
3406 3407
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3408
    virDomainDefPtr persistentDef;
3409 3410
    const char * type;
    int max;
3411
    int ret = -1;
3412 3413
    bool isActive;
    bool maximum;
3414

3415 3416
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
3417 3418 3419 3420 3421
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

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

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

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

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

3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458
    isActive = virDomainObjIsActive(vm);
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_DOMAIN_AFFECT_LIVE;
        else
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
    }

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

    if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
3459 3460
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
3461
        goto endjob;
3462 3463
    }

3464
    if (!vm->persistent && (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
3465 3466 3467 3468 3469
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot change persistent config of a transient domain"));
        goto endjob;
    }

3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482
    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;
    }

3483
    if (!maximum && vm->def->maxvcpus < max) {
3484 3485 3486
        max = vm->def->maxvcpus;
    }

3487 3488 3489 3490 3491 3492 3493
    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;
    }

3494 3495 3496
    if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
        goto endjob;

3497
    switch (flags) {
3498
    case VIR_DOMAIN_AFFECT_CONFIG:
3499 3500 3501 3502 3503 3504 3505
        if (maximum) {
            persistentDef->maxvcpus = nvcpus;
            if (nvcpus < persistentDef->vcpus)
                persistentDef->vcpus = nvcpus;
        } else {
            persistentDef->vcpus = nvcpus;
        }
3506 3507 3508
        ret = 0;
        break;

3509
    case VIR_DOMAIN_AFFECT_LIVE:
3510
        ret = qemudDomainHotplugVcpus(driver, vm, nvcpus);
3511 3512
        break;

3513
    case VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG:
3514
        ret = qemudDomainHotplugVcpus(driver, vm, nvcpus);
3515 3516 3517
        if (ret == 0) {
            persistentDef->vcpus = nvcpus;
        }
3518 3519
        break;
    }
3520

3521
    /* Save the persistent config to disk */
3522
    if (flags & VIR_DOMAIN_AFFECT_CONFIG)
3523 3524
        ret = virDomainSaveConfig(driver->configDir, persistentDef);

3525
endjob:
3526
    if (qemuDomainObjEndJob(driver, vm) == 0)
3527
        vm = NULL;
3528

3529
cleanup:
3530 3531
    if (vm)
        virDomainObjUnlock(vm);
3532
    return ret;
3533 3534
}

3535
static int
3536
qemuDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3537
{
3538
    return qemuDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
3539 3540
}

3541 3542

static int
3543 3544 3545 3546 3547 3548
qemudDomainPinVcpuFlags(virDomainPtr dom,
                        unsigned int vcpu,
                        unsigned char *cpumap,
                        int maplen,
                        unsigned int flags) {

3549 3550
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3551
    virDomainDefPtr persistentDef = NULL;
3552
    int maxcpu, hostcpus;
3553
    virNodeInfo nodeinfo;
3554
    int ret = -1;
3555
    bool isActive;
3556
    qemuDomainObjPrivatePtr priv;
3557
    bool canResetting = true;
E
Eric Blake 已提交
3558
    int pcpu;
3559

3560 3561 3562
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

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

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

3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586
    isActive = virDomainObjIsActive(vm);
    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
        if (isActive)
            flags = VIR_DOMAIN_AFFECT_LIVE;
        else
            flags = VIR_DOMAIN_AFFECT_CONFIG;
    }

    if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("a domain is inactive; can change only "
                          "persistent config"));
3587
        goto cleanup;
3588 3589
    }

3590 3591 3592
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
3593 3594 3595
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("vcpu number out of range %d > %d"),
                        vcpu, priv->nvcpupids);
3596
        goto cleanup;
3597 3598
    }

3599 3600 3601 3602 3603 3604 3605 3606 3607
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("cannot change persistent config of a transient domain"));
            goto cleanup;
        }
        if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
            goto cleanup;
    }
3608

3609 3610 3611 3612 3613 3614 3615 3616 3617
    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 已提交
3618
    for (pcpu = 0; pcpu < hostcpus; pcpu++) {
3619 3620 3621 3622 3623
        if ((cpumap[pcpu/8] & (1 << (pcpu % 8))) == 0) {
            canResetting = false;
            break;
        }
    }
3624

3625
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3626 3627 3628 3629 3630 3631

        if (priv->vcpupids != NULL) {
            if (virProcessInfoSetAffinity(priv->vcpupids[vcpu],
                                          cpumap, maplen, maxcpu) < 0)
                goto cleanup;
        } else {
3632
            qemuReportError(VIR_ERR_OPERATION_INVALID,
3633 3634 3635 3636
                            "%s", _("cpu affinity is not supported"));
            goto cleanup;
        }

3637
        if (canResetting) {
E
Eric Blake 已提交
3638
            if (virDomainVcpuPinDel(vm->def, vcpu) < 0) {
3639 3640 3641 3642 3643 3644
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("failed to delete vcpupin xml of "
                                  "a running domain"));
                goto cleanup;
            }
        } else {
E
Eric Blake 已提交
3645
            if (virDomainVcpuPinAdd(vm->def, cpumap, maplen, vcpu) < 0) {
3646 3647 3648 3649 3650
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("failed to update or add vcpupin xml of "
                                  "a running domain"));
                goto cleanup;
            }
3651 3652
        }

3653 3654
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            goto cleanup;
3655
    }
3656

3657 3658
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

3659
        if (canResetting) {
E
Eric Blake 已提交
3660
            if (virDomainVcpuPinDel(persistentDef, vcpu) < 0) {
3661 3662 3663 3664 3665 3666
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("failed to delete vcpupin xml of "
                                  "a persistent domain"));
                goto cleanup;
            }
        } else {
E
Eric Blake 已提交
3667
            if (virDomainVcpuPinAdd(persistentDef, cpumap, maplen, vcpu) < 0) {
3668 3669 3670 3671 3672
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("failed to update or add vcpupin xml of "
                                  "a persistent domain"));
                goto cleanup;
            }
3673
        }
3674

3675
        ret = virDomainSaveConfig(driver->configDir, persistentDef);
3676 3677 3678
        goto cleanup;
    }

3679
    ret = 0;
3680

3681
cleanup:
3682 3683
    if (vm)
        virDomainObjUnlock(vm);
3684
    return ret;
3685 3686
}

3687 3688 3689 3690 3691 3692 3693 3694 3695
static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
    return qemudDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                   VIR_DOMAIN_AFFECT_LIVE);
}

3696
static int
E
Eric Blake 已提交
3697
qemudDomainGetVcpuPinInfo(virDomainPtr dom,
3698 3699 3700 3701 3702 3703
                          int ncpumaps,
                          unsigned char *cpumaps,
                          int maplen,
                          unsigned int flags) {

    struct qemud_driver *driver = dom->conn->privateData;
E
Eric Blake 已提交
3704
    virDomainObjPtr vm = NULL;
3705 3706 3707 3708 3709 3710
    virNodeInfo nodeinfo;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    bool isActive;
    int maxcpu, hostcpus, vcpu, pcpu;
    int n;
E
Eric Blake 已提交
3711
    virDomainVcpuPinDefPtr *vcpupin_list;
3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763
    char *cpumask = NULL;
    unsigned char *cpumap;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    if ((flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) ==
        (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) {
        qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                        _("cannot get live and persistent info concurrently"));
        goto cleanup;
    }

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

    isActive = virDomainObjIsActive(vm);
    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
        if (isActive)
            flags = VIR_DOMAIN_AFFECT_LIVE;
        else
            flags = VIR_DOMAIN_AFFECT_CONFIG;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!isActive) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
            goto cleanup;
        }
        targetDef = vm->def;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("cannot get persistent config of a transient domain"));
            goto cleanup;
        }
        if (!(targetDef = virDomainObjGetPersistentDef(driver->caps, vm)))
            goto cleanup;
    }

3764 3765 3766
    /* Coverity didn't realize that targetDef must be set if we got here.  */
    sa_assert(targetDef);

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

3810 3811 3812 3813 3814 3815
static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
3816 3817
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3818
    virNodeInfo nodeinfo;
3819
    int i, v, maxcpu, hostcpus;
3820
    int ret = -1;
3821
    qemuDomainObjPrivatePtr priv;
3822

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

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

D
Daniel P. Berrange 已提交
3835
    if (!virDomainObjIsActive(vm)) {
3836 3837 3838
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",
                        _("cannot list vcpu pinning for an inactive domain"));
3839
        goto cleanup;
3840 3841
    }

3842 3843
    priv = vm->privateData;

3844
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
3845
        goto cleanup;
3846

3847
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
3848
    maxcpu = maplen * 8;
3849 3850
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
3851 3852

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

3856 3857 3858 3859 3860 3861
    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;
3862

3863
                if (priv->vcpupids != NULL &&
3864 3865 3866
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
                                        vm->pid,
3867
                                        priv->vcpupids[i]) < 0) {
3868
                    virReportSystemError(errno, "%s",
3869 3870 3871
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
3872
            }
3873 3874
        }

3875 3876
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
3877
            if (priv->vcpupids != NULL) {
3878 3879 3880
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);

3881
                    if (virProcessInfoGetAffinity(priv->vcpupids[v],
3882
                                                  cpumap, maplen, maxcpu) < 0)
3883
                        goto cleanup;
3884
                }
3885
            } else {
3886
                qemuReportError(VIR_ERR_OPERATION_INVALID,
3887
                                "%s", _("cpu affinity is not available"));
3888
                goto cleanup;
3889 3890 3891
            }
        }
    }
3892
    ret = maxinfo;
3893

3894
cleanup:
3895 3896
    if (vm)
        virDomainObjUnlock(vm);
3897
    return ret;
3898 3899 3900
}


3901 3902 3903
static int
qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
3904 3905
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3906
    virDomainDefPtr def;
3907
    int ret = -1;
3908
    bool active;
3909

3910 3911
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
3912 3913
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

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

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

3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939
    active = virDomainObjIsActive(vm);

    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0) {
        if (active)
            flags |= VIR_DOMAIN_VCPU_LIVE;
        else
            flags |= VIR_DOMAIN_VCPU_CONFIG;
    }
    if ((flags & VIR_DOMAIN_AFFECT_LIVE) && (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid flag combination: (0x%x)"), flags);
        return -1;
    }

3940
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3941
        if (!active) {
3942 3943 3944 3945 3946 3947
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("domain not active"));
            goto cleanup;
        }
        def = vm->def;
    } else {
3948 3949 3950 3951 3952
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("domain is transient"));
            goto cleanup;
        }
3953
        def = vm->newDef ? vm->newDef : vm->def;
3954 3955
    }

3956
    ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
3957

3958
cleanup:
3959 3960
    if (vm)
        virDomainObjUnlock(vm);
3961 3962 3963
    return ret;
}

3964 3965 3966
static int
qemudDomainGetMaxVcpus(virDomainPtr dom)
{
3967
    return qemudDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
3968 3969 3970
                                          VIR_DOMAIN_VCPU_MAXIMUM));
}

3971 3972 3973 3974 3975 3976 3977 3978 3979
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);

3980 3981
    memset(seclabel, 0, sizeof(*seclabel));

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

3990
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
3991 3992 3993
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010
        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 已提交
4011
    if (virDomainObjIsActive(vm)) {
4012 4013
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
                                              vm, seclabel) < 0) {
4014 4015 4016
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Failed to get security label"));
            goto cleanup;
4017 4018 4019 4020 4021 4022 4023 4024
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
4025
    qemuDriverUnlock(driver);
4026 4027 4028
    return ret;
}

4029 4030
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
4031 4032 4033
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
4034
    int ret = 0;
4035

4036
    qemuDriverLock(driver);
4037 4038 4039 4040 4041
    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)
4042
        goto cleanup;
4043

4044 4045
    p = driver->caps->host.secModel.model;
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
4046 4047 4048
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security model string exceeds max %d bytes"),
                        VIR_SECURITY_MODEL_BUFLEN-1);
4049 4050
        ret = -1;
        goto cleanup;
4051 4052 4053 4054 4055
    }
    strcpy(secmodel->model, p);

    p = driver->caps->host.secModel.doi;
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
4056 4057 4058
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security DOI string exceeds max %d bytes"),
                        VIR_SECURITY_DOI_BUFLEN-1);
4059 4060
        ret = -1;
        goto cleanup;
4061 4062
    }
    strcpy(secmodel->doi, p);
4063 4064 4065 4066

cleanup:
    qemuDriverUnlock(driver);
    return ret;
4067 4068
}

E
Eric Blake 已提交
4069
/* Return -1 on most failures after raising error, -2 if edit was specified
4070 4071 4072
 * 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.  */
4073
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
4074 4075 4076
qemuDomainSaveImageOpen(struct qemud_driver *driver,
                        const char *path,
                        virDomainDefPtr *ret_def,
4077
                        struct qemud_save_header *ret_header,
4078
                        bool bypass_cache, virFileDirectFdPtr *directFd,
4079 4080
                        const char *xmlin, int state, bool edit,
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
4081 4082
{
    int fd;
4083
    struct qemud_save_header header;
J
Jiri Denemark 已提交
4084 4085
    char *xml = NULL;
    virDomainDefPtr def = NULL;
4086
    int oflags = edit ? O_RDWR : O_RDONLY;
4087

4088
    if (bypass_cache) {
4089
        int directFlag = virFileDirectFdFlag();
4090 4091 4092 4093 4094
        if (directFlag < 0) {
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("bypass cache unsupported by this system"));
            goto error;
        }
4095
        oflags |= directFlag;
4096
    }
4097

E
Eric Blake 已提交
4098 4099
    if ((fd = qemuOpenFile(driver, path, oflags, NULL, NULL)) < 0)
        goto error;
4100 4101
    if (bypass_cache && (*directFd = virFileDirectFdNew(&fd, path)) == NULL)
        goto error;
4102 4103

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
4104 4105
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
4106
        goto error;
4107 4108 4109
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
E
Eric Blake 已提交
4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125
        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 已提交
4126
        goto error;
4127 4128 4129
    }

    if (header.version > QEMUD_SAVE_VERSION) {
4130 4131 4132 4133 4134
        /* convert endianess and try again */
        bswap_header(&header);
    }

    if (header.version > QEMUD_SAVE_VERSION) {
4135 4136 4137
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("image version is not supported (%d > %d)"),
                        header.version, QEMUD_SAVE_VERSION);
J
Jiri Denemark 已提交
4138
        goto error;
4139 4140
    }

4141 4142 4143
    if (header.xml_len <= 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
4144
        goto error;
4145 4146
    }

4147 4148
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
J
Jiri Denemark 已提交
4149
        goto error;
4150 4151 4152
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
4153 4154
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
4155
        goto error;
4156 4157
    }

4158 4159
    if (edit && STREQ(xml, xmlin) &&
        (state < 0 || state == header.was_running)) {
4160 4161 4162 4163 4164 4165 4166
        VIR_FREE(xml);
        if (VIR_CLOSE(fd) < 0) {
            virReportSystemError(errno, _("cannot close file: %s"), path);
            goto error;
        }
        return -2;
    }
4167 4168
    if (state >= 0)
        header.was_running = state;
4169

4170
    /* Create a domain from this XML */
4171
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
4172
                                        QEMU_EXPECTED_VIRT_TYPES,
4173
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
4174
        goto error;
4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188
    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;
    }
4189

J
Jiri Denemark 已提交
4190
    VIR_FREE(xml);
4191

J
Jiri Denemark 已提交
4192 4193
    *ret_def = def;
    *ret_header = header;
4194

J
Jiri Denemark 已提交
4195
    return fd;
4196

J
Jiri Denemark 已提交
4197 4198 4199
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
4200
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
4201 4202 4203 4204

    return -1;
}

4205 4206 4207 4208 4209 4210
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,
4211 4212
                           const char *path,
                           bool start_paused)
J
Jiri Denemark 已提交
4213 4214 4215 4216
{
    int ret = -1;
    virDomainEventPtr event;
    int intermediatefd = -1;
4217
    virCommandPtr cmd = NULL;
J
Jiri Denemark 已提交
4218 4219 4220

    if (header->version == 2) {
        const char *prog = qemudSaveCompressionTypeToString(header->compressed);
4221
        if (prog == NULL) {
4222 4223
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("Invalid compressed save format %d"),
J
Jiri Denemark 已提交
4224 4225
                            header->compressed);
            goto out;
4226
        }
4227

J
Jiri Denemark 已提交
4228
        if (header->compressed != QEMUD_SAVE_FORMAT_RAW) {
4229
            cmd = virCommandNewArgList(prog, "-dc", NULL);
4230 4231
            intermediatefd = *fd;
            *fd = -1;
4232 4233 4234 4235 4236

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

            if (virCommandRunAsync(cmd, NULL) < 0) {
4237 4238
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Failed to start decompression binary %s"),
4239
                                prog);
4240
                *fd = intermediatefd;
J
Jiri Denemark 已提交
4241
                goto out;
4242 4243 4244
            }
        }
    }
J
Jiri Denemark 已提交
4245

4246
    /* Set the migration source and start it up. */
4247
    ret = qemuProcessStart(conn, driver, vm, "stdio", true,
4248
                           false, *fd, path, NULL, VIR_VM_OP_RESTORE);
J
Jiri Denemark 已提交
4249

4250
    if (intermediatefd != -1) {
4251
        if (ret < 0) {
4252 4253 4254
            /* if there was an error setting up qemu, the intermediate
             * process will wait forever to write to stdout, so we
             * must manually kill it.
4255 4256
             */
            VIR_FORCE_CLOSE(intermediatefd);
4257
            VIR_FORCE_CLOSE(*fd);
4258 4259
        }

4260 4261
        if (virCommandWait(cmd, NULL) < 0)
            ret = -1;
4262
    }
4263
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
4264

4265 4266 4267
    if (VIR_CLOSE(*fd) < 0) {
        virReportSystemError(errno, _("cannot close file: %s"), path);
        ret = -1;
4268
    }
J
Jiri Denemark 已提交
4269

4270
    if (ret < 0) {
4271
        virDomainAuditStart(vm, "restored", false);
J
Jiri Denemark 已提交
4272
        goto out;
4273
    }
4274

4275 4276 4277
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
4278
    virDomainAuditStart(vm, "restored", true);
J
Jiri Denemark 已提交
4279 4280 4281
    if (event)
        qemuDomainEventQueue(driver, event);

4282

4283 4284
    /* If it was running before, resume it now unless caller requested pause. */
    if (header->was_running && !start_paused) {
J
Jiri Denemark 已提交
4285
        if (qemuProcessStartCPUs(driver, vm, conn,
4286 4287
                                 VIR_DOMAIN_RUNNING_RESTORED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
4288
            if (virGetLastError() == NULL)
4289 4290
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("failed to resume domain"));
J
Jiri Denemark 已提交
4291
            goto out;
4292
        }
4293 4294
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
J
Jiri Denemark 已提交
4295
            goto out;
4296
        }
4297 4298 4299 4300 4301 4302 4303 4304
    } 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);
4305
    }
J
Jiri Denemark 已提交
4306

4307
    ret = 0;
4308

J
Jiri Denemark 已提交
4309
out:
4310
    virCommandFree(cmd);
4311 4312
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
                                                 vm, path) < 0)
4313 4314
        VIR_WARN("failed to restore save state label on %s", path);

J
Jiri Denemark 已提交
4315 4316 4317
    return ret;
}

4318
static int
4319 4320 4321 4322
qemuDomainRestoreFlags(virConnectPtr conn,
                       const char *path,
                       const char *dxml,
                       unsigned int flags)
4323
{
J
Jiri Denemark 已提交
4324 4325 4326 4327 4328 4329
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    int ret = -1;
    struct qemud_save_header header;
4330
    virFileDirectFdPtr directFd = NULL;
4331
    int state = -1;
J
Jiri Denemark 已提交
4332

4333 4334 4335
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
4336

J
Jiri Denemark 已提交
4337 4338
    qemuDriverLock(driver);

4339 4340 4341 4342 4343
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

4344 4345
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
4346
                                 &directFd, dxml, state, false, false);
J
Jiri Denemark 已提交
4347 4348 4349 4350 4351 4352 4353 4354 4355
    if (fd < 0)
        goto cleanup;

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

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, true))) {
4356
        /* virDomainAssignDef already set the error */
J
Jiri Denemark 已提交
4357 4358 4359 4360
        goto cleanup;
    }
    def = NULL;

4361
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
4362 4363
        goto cleanup;

4364 4365
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     false);
4366 4367
    if (virFileDirectFdClose(directFd) < 0)
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
4368

4369
    if (qemuDomainObjEndJob(driver, vm) == 0)
4370
        vm = NULL;
J
Jiri Denemark 已提交
4371 4372 4373 4374
    else if (ret < 0 && !vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
4375

4376 4377
cleanup:
    virDomainDefFree(def);
4378
    VIR_FORCE_CLOSE(fd);
4379
    virFileDirectFdFree(directFd);
4380 4381 4382
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
4383
    return ret;
D
Daniel P. Berrange 已提交
4384 4385
}

4386 4387 4388 4389 4390 4391 4392
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408
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,
4409
                                 NULL, -1, false, false);
4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433

    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;
4434
    int state = -1;
4435

4436 4437
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
4438 4439 4440

    qemuDriverLock(driver);

4441 4442 4443 4444 4445
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

4446
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
4447
                                 dxml, state, true, false);
4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471

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

4472
    if (lseek(fd, 0, SEEK_SET) != 0) {
4473 4474 4475
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
4476 4477
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492
        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 已提交
4493 4494
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
4495 4496 4497 4498
static int
qemuDomainObjRestore(virConnectPtr conn,
                     struct qemud_driver *driver,
                     virDomainObjPtr vm,
4499
                     const char *path,
4500
                     bool start_paused,
4501
                     bool bypass_cache)
J
Jiri Denemark 已提交
4502 4503 4504 4505 4506
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    int ret = -1;
    struct qemud_save_header header;
4507
    virFileDirectFdPtr directFd = NULL;
J
Jiri Denemark 已提交
4508

4509
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
4510 4511
                                 bypass_cache, &directFd, NULL, -1, false,
                                 true);
E
Eric Blake 已提交
4512 4513 4514
    if (fd < 0) {
        if (fd == -3)
            ret = 1;
J
Jiri Denemark 已提交
4515
        goto cleanup;
E
Eric Blake 已提交
4516
    }
J
Jiri Denemark 已提交
4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534

    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;

4535 4536
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     start_paused);
4537 4538
    if (virFileDirectFdClose(directFd) < 0)
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
4539 4540 4541

cleanup:
    virDomainDefFree(def);
4542
    VIR_FORCE_CLOSE(fd);
4543
    virFileDirectFdFree(directFd);
J
Jiri Denemark 已提交
4544 4545 4546
    return ret;
}

D
Daniel P. Berrange 已提交
4547

4548
static char *qemuDomainGetXMLDesc(virDomainPtr dom,
4549 4550
                                  unsigned int flags)
{
4551 4552 4553
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
4554 4555
    unsigned long balloon;
    int err;
4556

4557
    /* Flags checked by virDomainDefFormat */
4558

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

D
Daniel P. Berrange 已提交
4562
    if (!vm) {
4563 4564
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4565 4566
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4567
        goto cleanup;
D
Daniel P. Berrange 已提交
4568 4569
    }

4570 4571 4572 4573
    /* 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))) {
4574
        qemuDomainObjPrivatePtr priv = vm->privateData;
4575 4576
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
4577
        if (!priv->job.active) {
4578
            if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_QUERY) < 0)
4579 4580
                goto cleanup;

4581
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
4582
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
4583
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4584
            if (qemuDomainObjEndJob(driver, vm) == 0) {
4585 4586 4587
                vm = NULL;
                goto cleanup;
            }
4588 4589 4590
            if (err < 0)
                goto cleanup;
            if (err > 0)
4591
                vm->def->mem.cur_balloon = balloon;
4592 4593
            /* err == 0 indicates no balloon support, so ignore it */
        }
4594
    }
4595

4596
    ret = qemuDomainFormatXML(driver, vm, flags);
4597 4598

cleanup:
4599 4600
    if (vm)
        virDomainObjUnlock(vm);
4601
    qemuDriverUnlock(driver);
4602
    return ret;
D
Daniel P. Berrange 已提交
4603 4604 4605
}


4606 4607 4608
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
E
Eric Blake 已提交
4609 4610
                                     unsigned int flags)
{
4611
    struct qemud_driver *driver = conn->privateData;
4612 4613 4614
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
4615 4616
    virCheckFlags(0, NULL);

4617
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
4618 4619
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
4620 4621 4622
        goto cleanup;
    }

4623
    qemuDriverLock(driver);
4624 4625
    def = qemuParseCommandLineString(driver->caps, config,
                                     NULL, NULL, NULL);
4626
    qemuDriverUnlock(driver);
4627 4628 4629
    if (!def)
        goto cleanup;

4630 4631 4632 4633 4634 4635
    if (!def->name &&
        !(def->name = strdup("unnamed"))) {
        virReportOOMError();
        goto cleanup;
    }

4636
    xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
4637 4638 4639 4640 4641 4642

cleanup:
    virDomainDefFree(def);
    return xml;
}

4643 4644 4645
static char *qemuDomainXMLToNative(virConnectPtr conn,
                                   const char *format,
                                   const char *xmlData,
E
Eric Blake 已提交
4646 4647
                                   unsigned int flags)
{
4648 4649
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
4650
    virDomainChrSourceDef monConfig;
4651
    virBitmapPtr qemuCaps = NULL;
E
Eric Blake 已提交
4652
    virCommandPtr cmd = NULL;
4653 4654 4655
    char *ret = NULL;
    int i;

E
Eric Blake 已提交
4656 4657
    virCheckFlags(0, NULL);

4658 4659
    qemuDriverLock(driver);

4660
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
4661 4662
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
4663 4664 4665
        goto cleanup;
    }

M
Matthias Bolte 已提交
4666 4667
    def = virDomainDefParseString(driver->caps, xmlData,
                                  QEMU_EXPECTED_VIRT_TYPES, 0);
4668 4669 4670
    if (!def)
        goto cleanup;

4671 4672
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
4673 4674 4675 4676 4677
     * 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];
4678
        int bootIndex = net->bootIndex;
4679 4680 4681 4682
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

4683
            VIR_FREE(net->data.network.name);
4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716
            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;
                net->data.ethernet.dev = brnamecopy;
                net->data.ethernet.script = NULL;
                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;
                net->data.ethernet.dev = NULL;
                net->data.ethernet.script = 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);
4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735

            memset(net, 0, sizeof *net);

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
            net->data.ethernet.dev = NULL;
            net->data.ethernet.script = NULL;
            net->data.ethernet.ipaddr = NULL;
        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
            char *brname = net->data.bridge.brname;
            char *script = net->data.bridge.script;
            char *ipaddr = net->data.bridge.ipaddr;

            memset(net, 0, sizeof *net);

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
            net->data.ethernet.dev = brname;
            net->data.ethernet.script = script;
            net->data.ethernet.ipaddr = ipaddr;
        }
4736
        net->bootIndex = bootIndex;
4737 4738 4739 4740
    }
    for (i = 0 ; i < def->ngraphics ; i++) {
        if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
            def->graphics[i]->data.vnc.autoport)
4741
            def->graphics[i]->data.vnc.port = QEMU_VNC_PORT_MIN;
4742 4743
    }

4744
    if (qemuCapsExtractVersionInfo(def->emulator, def->os.arch,
4745
                                   NULL,
4746
                                   &qemuCaps) < 0)
4747 4748
        goto cleanup;

4749
    if (qemuProcessPrepareMonitorChr(driver, &monConfig, def->name) < 0)
4750
        goto cleanup;
4751

4752
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
4753
                                     &monConfig, false, qemuCaps,
4754
                                     NULL, -1, NULL, VIR_VM_OP_NO_OP)))
4755 4756
        goto cleanup;

E
Eric Blake 已提交
4757
    ret = virCommandToString(cmd);
4758 4759

cleanup:
4760
    qemuDriverUnlock(driver);
4761

4762
    qemuCapsFree(qemuCaps);
E
Eric Blake 已提交
4763
    virCommandFree(cmd);
4764 4765 4766 4767 4768
    virDomainDefFree(def);
    return ret;
}


4769
static int qemudListDefinedDomains(virConnectPtr conn,
4770
                            char **const names, int nnames) {
4771
    struct qemud_driver *driver = conn->privateData;
4772
    int n;
4773

4774
    qemuDriverLock(driver);
4775
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
4776
    qemuDriverUnlock(driver);
4777
    return n;
D
Daniel P. Berrange 已提交
4778 4779
}

4780
static int qemudNumDefinedDomains(virConnectPtr conn) {
4781
    struct qemud_driver *driver = conn->privateData;
4782
    int n;
4783

4784
    qemuDriverLock(driver);
4785
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
4786
    qemuDriverUnlock(driver);
4787

4788
    return n;
D
Daniel P. Berrange 已提交
4789 4790 4791
}


4792 4793 4794 4795
static int
qemuDomainObjStart(virConnectPtr conn,
                   struct qemud_driver *driver,
                   virDomainObjPtr vm,
4796
                   unsigned int flags)
J
Jiri Denemark 已提交
4797 4798 4799
{
    int ret = -1;
    char *managed_save;
4800 4801 4802 4803
    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 已提交
4804 4805 4806

    /*
     * If there is a managed saved state restore it instead of starting
4807
     * from scratch. The old state is removed once the restoring succeeded.
J
Jiri Denemark 已提交
4808 4809
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
4810 4811 4812 4813

    if (!managed_save)
        goto cleanup;

E
Eric Blake 已提交
4814
    if (virFileExists(managed_save)) {
4815 4816 4817 4818 4819 4820 4821 4822 4823
        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,
4824
                                       start_paused, bypass_cache);
J
Jiri Denemark 已提交
4825

E
Eric Blake 已提交
4826
            if (ret == 0 && unlink(managed_save) < 0)
4827
                VIR_WARN("Failed to remove the managed state %s", managed_save);
E
Eric Blake 已提交
4828 4829 4830 4831
            if (ret > 0)
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
            else
                goto cleanup;
4832
        }
J
Jiri Denemark 已提交
4833 4834
    }

4835
    ret = qemuProcessStart(conn, driver, vm, NULL, start_paused,
4836
                           autodestroy, -1, NULL, NULL, VIR_VM_OP_CREATE);
4837
    virDomainAuditStart(vm, "booted", ret >= 0);
4838
    if (ret >= 0) {
J
Jiri Denemark 已提交
4839 4840 4841 4842
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
4843
        if (event) {
J
Jiri Denemark 已提交
4844
            qemuDomainEventQueue(driver, event);
4845 4846 4847 4848 4849 4850 4851 4852
            if (start_paused) {
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
                if (event)
                    qemuDomainEventQueue(driver, event);
            }
        }
J
Jiri Denemark 已提交
4853 4854 4855 4856 4857 4858 4859
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

4860
static int
4861
qemuDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
4862
{
4863 4864 4865
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4866

4867
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
4868
                  VIR_DOMAIN_START_AUTODESTROY |
4869 4870
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
4871

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

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

4883
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
4884 4885 4886
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
4887 4888
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is already running"));
4889 4890 4891
        goto endjob;
    }

4892
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
4893 4894 4895
        goto endjob;

    ret = 0;
4896

4897
endjob:
4898
    if (qemuDomainObjEndJob(driver, vm) == 0)
4899
        vm = NULL;
4900

4901
cleanup:
4902 4903
    if (vm)
        virDomainObjUnlock(vm);
4904
    qemuDriverUnlock(driver);
4905
    return ret;
D
Daniel P. Berrange 已提交
4906 4907
}

4908
static int
4909
qemuDomainStart(virDomainPtr dom)
4910
{
4911
    return qemuDomainStartWithFlags(dom, 0);
4912 4913
}

4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928
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;

4929
        if (def->os.machine && STRNEQ(def->os.machine, machine->name))
4930 4931 4932
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
4933
            virReportOOMError();
4934 4935 4936 4937 4938 4939 4940 4941 4942
            return -1;
        }

        break;
    }

    return 0;
}

4943 4944 4945 4946 4947 4948
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
    int i, nmachines = 0;

4949
    if (qemuCapsProbeMachineTypes(def->emulator, &machines, &nmachines) < 0)
4950 4951 4952 4953 4954 4955
        return -1;

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

4956
        if (def->os.machine && STRNEQ(def->os.machine, machines[i]->name))
4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

4969 4970
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
4971 4972 4973 4974 4975 4976
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
4977
        virCapsGuestDomainInfoPtr info;
4978 4979 4980
        int j;

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

4983 4984 4985 4986 4987 4988 4989 4990 4991
            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;
4992 4993
        }

4994 4995 4996 4997
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
4998 4999 5000 5001
                return -1;
            goto out;
        }
    }
5002 5003 5004 5005

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

5006 5007 5008 5009 5010 5011 5012
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
5013

5014
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
5015
    struct qemud_driver *driver = conn->privateData;
5016
    virDomainDefPtr def;
5017
    virDomainObjPtr vm = NULL;
5018
    virDomainPtr dom = NULL;
5019
    virDomainEventPtr event = NULL;
5020
    int dupVM;
5021

5022
    qemuDriverLock(driver);
5023
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
5024
                                        QEMU_EXPECTED_VIRT_TYPES,
5025
                                        VIR_DOMAIN_XML_INACTIVE)))
5026
        goto cleanup;
5027

5028
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
5029 5030
        goto cleanup;

5031 5032
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
5033

5034
    if (qemudCanonicalizeMachine(driver, def) < 0)
5035 5036
        goto cleanup;

5037
    if (qemuDomainAssignPCIAddresses(def) < 0)
5038 5039
        goto cleanup;

5040
    if (!(vm = virDomainAssignDef(driver->caps,
5041
                                  &driver->domains,
5042
                                  def, false))) {
5043
        goto cleanup;
5044
    }
5045
    def = NULL;
5046
    vm->persistent = 1;
5047

5048
    if (virDomainSaveConfig(driver->configDir,
5049
                            vm->newDef ? vm->newDef : vm->def) < 0) {
5050
        VIR_INFO("Defining domain '%s'", vm->def->name);
5051 5052
        virDomainRemoveInactive(&driver->domains,
                                vm);
5053
        vm = NULL;
5054
        goto cleanup;
5055 5056
    }

5057 5058
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
5059
                                     !dupVM ?
5060 5061
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
5062

5063
    VIR_INFO("Creating domain '%s'", vm->def->name);
5064
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
5065
    if (dom) dom->id = vm->def->id;
5066 5067

cleanup:
5068
    virDomainDefFree(def);
5069 5070
    if (vm)
        virDomainObjUnlock(vm);
5071 5072
    if (event)
        qemuDomainEventQueue(driver, event);
5073
    qemuDriverUnlock(driver);
5074
    return dom;
D
Daniel P. Berrange 已提交
5075 5076
}

5077 5078 5079 5080
static int
qemuDomainUndefineFlags(virDomainPtr dom,
                         unsigned int flags)
{
5081 5082
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5083
    virDomainEventPtr event = NULL;
5084
    char *name = NULL;
5085
    int ret = -1;
5086
    int nsnapshots;
D
Daniel P. Berrange 已提交
5087

5088 5089
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
5090

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

D
Daniel P. Berrange 已提交
5094
    if (!vm) {
5095 5096
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5097 5098
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5099
        goto cleanup;
D
Daniel P. Berrange 已提交
5100 5101
    }

5102 5103
    if (!virDomainObjIsActive(vm) &&
        (nsnapshots = virDomainSnapshotObjListNum(&vm->snapshots, 0))) {
5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120
        struct snap_remove rem;

        if (flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            _("cannot delete inactive domain with %d "
                              "snapshots"),
                            nsnapshots);
            goto cleanup;
        }

        rem.driver = driver;
        rem.vm = vm;
        rem.metadata_only = true;
        rem.err = 0;
        virHashForEach(vm->snapshots.objs, qemuDomainSnapshotDiscardAll, &rem);
        if (rem.err < 0)
            goto cleanup;
5121 5122
    }

5123
    if (!vm->persistent) {
5124
        qemuReportError(VIR_ERR_OPERATION_INVALID,
5125
                        "%s", _("cannot undefine transient domain"));
5126
        goto cleanup;
5127 5128
    }

5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148
    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;
        }
    }

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

5152 5153 5154
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
5155

5156
    VIR_INFO("Undefining domain '%s'", vm->def->name);
5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169

    /* 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 {
        virDomainRemoveInactive(&driver->domains,
                                vm);
        vm = NULL;
    }

5170
    ret = 0;
D
Daniel P. Berrange 已提交
5171

5172
cleanup:
5173
    VIR_FREE(name);
5174 5175
    if (vm)
        virDomainObjUnlock(vm);
5176 5177
    if (event)
        qemuDomainEventQueue(driver, event);
5178
    qemuDriverUnlock(driver);
5179
    return ret;
D
Daniel P. Berrange 已提交
5180 5181
}

5182 5183 5184 5185 5186 5187
static int
qemudDomainUndefine(virDomainPtr dom)
{
    return qemuDomainUndefineFlags(dom, 0);
}

5188 5189 5190
static int
qemuDomainAttachDeviceDiskLive(struct qemud_driver *driver,
                               virDomainObjPtr vm,
5191
                               virDomainDeviceDefPtr dev)
5192 5193 5194 5195
{
    virDomainDiskDefPtr disk = dev->data.disk;
    virCgroupPtr cgroup = NULL;
    int ret = -1;
5196

5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216
    if (disk->driverName != NULL && !STREQ(disk->driverName, "qemu")) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("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:
5217
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, false);
5218 5219 5220 5221
        break;
    case VIR_DOMAIN_DISK_DEVICE_DISK:
        if (disk->bus == VIR_DOMAIN_DISK_BUS_USB)
            ret = qemuDomainAttachUsbMassstorageDevice(driver, vm,
5222
                                                       disk);
5223
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
5224
            ret = qemuDomainAttachPciDiskDevice(driver, vm, disk);
5225
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI)
5226
            ret = qemuDomainAttachSCSIDisk(driver, vm, disk);
5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252
        else
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                            _("disk bus '%s' cannot be hotplugged."),
                            virDomainDiskBusTypeToString(disk->bus));
        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,
5253
                                     virDomainDeviceDefPtr dev)
5254 5255 5256 5257 5258 5259
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5260
        ret = qemuDomainAttachPciControllerDevice(driver, vm, cont);
5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273
        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,
5274
                           virDomainPtr dom)
5275 5276 5277 5278 5279 5280
{
    struct qemud_driver *driver = dom->conn->privateData;
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5281
        qemuDomainObjCheckDiskTaint(driver, vm, dev->data.disk, -1);
5282
        ret = qemuDomainAttachDeviceDiskLive(driver, vm, dev);
5283 5284 5285 5286 5287
        if (!ret)
            dev->data.disk = NULL;
        break;

    case VIR_DOMAIN_DEVICE_CONTROLLER:
5288
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
5289 5290 5291 5292
        if (!ret)
            dev->data.controller = NULL;
        break;

5293 5294 5295 5296 5297 5298 5299
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

5300
    case VIR_DOMAIN_DEVICE_NET:
5301
        qemuDomainObjCheckNetTaint(driver, vm, dev->data.net, -1);
5302
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
5303
                                        dev->data.net);
5304 5305 5306 5307 5308 5309
        if (!ret)
            dev->data.net = NULL;
        break;

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = qemuDomainAttachHostDevice(driver, vm,
5310
                                         dev->data.hostdev);
5311 5312 5313 5314
        if (!ret)
            dev->data.hostdev = NULL;
        break;

5315 5316 5317 5318 5319 5320 5321
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334
    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,
5335
                               virDomainDeviceDefPtr dev)
5336 5337 5338 5339 5340 5341 5342
{
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_DISK:
        if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
5343
            ret = qemuDomainDetachPciDiskDevice(driver, vm, dev);
5344
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI)
5345
            ret =  qemuDomainDetachDiskDevice(driver, vm, dev);
5346
        else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB)
5347
            ret = qemuDomainDetachDiskDevice(driver, vm, dev);
5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363
        else
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                            _("This type of disk cannot be hot unplugged"));
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("device type '%s' cannot be detached"),
                        virDomainDeviceTypeToString(dev->type));
        break;
    }
    return ret;
}

static int
qemuDomainDetachDeviceControllerLive(struct qemud_driver *driver,
                                     virDomainObjPtr vm,
5364
                                     virDomainDeviceDefPtr dev)
5365 5366 5367 5368 5369 5370
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5371
        ret = qemuDomainDetachPciControllerDevice(driver, vm, dev);
5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383
        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,
5384
                           virDomainPtr dom)
5385 5386 5387 5388 5389 5390
{
    struct qemud_driver *driver = dom->conn->privateData;
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5391
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
5392 5393
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5394
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
5395
        break;
5396 5397 5398
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
5399
    case VIR_DOMAIN_DEVICE_NET:
5400
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
5401 5402
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
5403
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
5404 5405 5406 5407 5408 5409 5410 5411 5412 5413
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        "%s", _("This type of device cannot be hot unplugged"));
        break;
    }

    return ret;
}

5414 5415 5416 5417 5418 5419 5420 5421
static int
qemuDomainChangeDiskMediaLive(virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev,
                              struct qemud_driver *driver,
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
    virCgroupPtr cgroup = NULL;
5422
    int ret = -1;
5423 5424 5425

    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup,
5426
                               vm->def->name, &cgroup, 0) != 0) {
5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438
            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:
5439
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, force);
5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471
        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:
5472
        ret = qemuDomainChangeDiskMediaLive(vm, dev, driver, force);
5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("device type '%s' cannot be updated"),
                        virDomainDeviceTypeToString(dev->type));
        break;
    }

    return ret;
}

5487
static int
5488
qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
5489 5490
                             virDomainDeviceDefPtr dev)
{
5491
    virDomainDiskDefPtr disk;
5492
    virDomainNetDefPtr net;
5493
    virDomainLeaseDefPtr lease;
5494

5495
    switch (dev->type) {
5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
        if (virDomainDiskIndexByName(vmdef, disk->dst) >= 0) {
            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;
        if (qemuDomainAssignPCIAddresses(vmdef) < 0)
            return -1;
        break;

5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
        if (virDomainNetIndexByMac(vmdef, net->mac) >= 0) {
            char macbuf[VIR_MAC_STRING_BUFLEN];
            virFormatMacAddr(net->mac, macbuf);
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("mac %s already exists"), macbuf);
            return -1;
        }
        if (virDomainNetInsert(vmdef, net)) {
            virReportOOMError();
            return -1;
        }
        dev->data.net = NULL;
        if (qemuDomainAssignPCIAddresses(vmdef) < 0)
            return -1;
        break;
5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548

    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;

5549 5550 5551 5552 5553 5554 5555 5556 5557 5558
    default:
         qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                         _("persistent attach of device is not supported"));
         return -1;
    }
    return 0;
}


static int
5559
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
5560 5561
                             virDomainDeviceDefPtr dev)
{
5562
    virDomainDiskDefPtr disk;
5563
    virDomainNetDefPtr net;
5564
    virDomainLeaseDefPtr lease;
5565

5566
    switch (dev->type) {
5567 5568 5569 5570 5571 5572 5573 5574
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
        if (virDomainDiskRemoveByName(vmdef, disk->dst)) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("no target device %s"), disk->dst);
            return -1;
        }
        break;
5575

5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
        if (virDomainNetRemoveByMac(vmdef, net->mac)) {
            char macbuf[VIR_MAC_STRING_BUFLEN];

            virFormatMacAddr(net->mac, macbuf);
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("no nic of mac %s"), macbuf);
            return -1;
        }
        break;
5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597

    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
        if (virDomainLeaseRemove(vmdef, lease) < 0) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Lease %s in lockspace %s does not exist"),
                            lease->key, NULLSTR(lease->lockspace));
            return -1;
        }
        break;

5598 5599 5600 5601 5602 5603 5604 5605 5606
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent detach of device is not supported"));
        return -1;
    }
    return 0;
}

static int
5607
qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
5608 5609
                             virDomainDeviceDefPtr dev)
{
5610 5611 5612
    virDomainDiskDefPtr orig, disk;
    int pos;

5613
    switch (dev->type) {
5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
        pos = virDomainDiskIndexByName(vmdef, disk->dst);
        if (pos < 0) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("target %s doesn't exists."), disk->dst);
            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;
5649 5650 5651 5652 5653 5654 5655 5656
    default:
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                         _("persistent update of device is not supported"));
        return -1;
    }
    return 0;
}

5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667
/* 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)
5668
{
5669
    struct qemud_driver *driver = dom->conn->privateData;
5670
    virDomainObjPtr vm = NULL;
5671
    virDomainDefPtr vmdef = NULL;
5672
    virDomainDeviceDefPtr dev = NULL;
5673
    bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
5674
    int ret = -1;
5675
    unsigned int affect;
5676

5677 5678
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
5679 5680 5681
                  (action == QEMU_DEVICE_UPDATE ?
                   VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);

5682 5683
    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

5684 5685 5686 5687 5688 5689 5690
    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);
5691 5692 5693
        goto cleanup;
    }

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

5697
    if (virDomainObjIsActive(vm)) {
5698
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
5699
            flags |= VIR_DOMAIN_AFFECT_LIVE;
5700
    } else {
5701
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
5702
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
5703
        /* check consistency between flags and the vm state */
5704
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
5705 5706 5707 5708 5709 5710
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s",
                            _("cannot do live update a device on "
                              "inactive domain"));
            goto endjob;
        }
5711
    }
5712

5713
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
5714 5715 5716 5717
         qemuReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("cannot modify device on transient domain"));
         goto endjob;
    }
5718

5719
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5720 5721 5722 5723 5724
        dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                      VIR_DOMAIN_XML_INACTIVE);
        if (dev == NULL)
            goto endjob;

5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743
        /* 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;
        }
5744

5745 5746 5747 5748 5749
        if (ret == -1)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
5750 5751 5752 5753
        /* If dev exists it was created to modify the domain config. Free it. */
        virDomainDeviceDefFree(dev);
        dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                      VIR_DOMAIN_XML_INACTIVE);
5754 5755
        if (dev == NULL) {
            ret = -1;
5756
            goto endjob;
5757
        }
5758

5759 5760
        switch (action) {
        case QEMU_DEVICE_ATTACH:
5761
            ret = qemuDomainAttachDeviceLive(vm, dev, dom);
5762 5763
            break;
        case QEMU_DEVICE_DETACH:
5764
            ret = qemuDomainDetachDeviceLive(vm, dev, dom);
5765 5766
            break;
        case QEMU_DEVICE_UPDATE:
5767
            ret = qemuDomainUpdateDeviceLive(vm, dev, dom, force);
5768 5769 5770 5771
            break;
        default:
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("unknown domain modify action %d"), action);
5772
            ret = -1;
5773 5774
            break;
        }
5775 5776 5777

        if (ret == -1)
            goto endjob;
5778 5779
        /*
         * update domain status forcibly because the domain status may be
5780 5781
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
5782
         */
5783
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
5784
            ret = -1;
5785 5786
            goto endjob;
        }
5787
    }
5788

5789
    /* Finally, if no error until here, we can save config. */
5790
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5791 5792 5793 5794 5795 5796
        ret = virDomainSaveConfig(driver->configDir, vmdef);
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false);
            vmdef = NULL;
        }
    }
5797 5798

endjob:
5799
    if (qemuDomainObjEndJob(driver, vm) == 0)
5800 5801 5802
        vm = NULL;

cleanup:
5803
    virDomainDefFree(vmdef);
5804 5805 5806 5807
    virDomainDeviceDefFree(dev);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
5808 5809 5810
    return ret;
}

5811 5812 5813 5814 5815 5816
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_ATTACH);
}

5817 5818 5819
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
5820
                                       VIR_DOMAIN_AFFECT_LIVE);
5821
}
5822

5823

5824 5825 5826 5827
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
5828
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_UPDATE);
5829 5830
}

5831 5832 5833
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
5834
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_DETACH);
5835 5836
}

5837 5838 5839
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
5840
                                       VIR_DOMAIN_AFFECT_LIVE);
5841 5842
}

5843
static int qemudDomainGetAutostart(virDomainPtr dom,
5844
                                   int *autostart) {
5845 5846 5847
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5848

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

5853
    if (!vm) {
5854 5855
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5856 5857
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5858
        goto cleanup;
5859 5860 5861
    }

    *autostart = vm->autostart;
5862
    ret = 0;
5863

5864
cleanup:
5865 5866
    if (vm)
        virDomainObjUnlock(vm);
5867
    return ret;
5868 5869
}

5870
static int qemudDomainSetAutostart(virDomainPtr dom,
5871
                                   int autostart) {
5872 5873
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5874 5875
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
5876

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

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

5888
    if (!vm->persistent) {
5889
        qemuReportError(VIR_ERR_OPERATION_INVALID,
5890
                        "%s", _("cannot set autostart for transient domain"));
5891
        goto cleanup;
5892 5893
    }

5894 5895
    autostart = (autostart != 0);

5896
    if (vm->autostart != autostart) {
5897
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
5898
            goto cleanup;
5899
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
5900
            goto cleanup;
5901

5902
        if (autostart) {
5903 5904
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
5905 5906
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
5907 5908
                goto cleanup;
            }
5909

5910
            if (symlink(configFile, autostartLink) < 0) {
5911
                virReportSystemError(errno,
5912 5913
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
5914 5915 5916 5917
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
5918
                virReportSystemError(errno,
5919 5920
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
5921 5922
                goto cleanup;
            }
5923 5924
        }

5925
        vm->autostart = autostart;
5926
    }
5927
    ret = 0;
5928

5929 5930 5931
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
5932 5933
    if (vm)
        virDomainObjUnlock(vm);
5934
    qemuDriverUnlock(driver);
5935
    return ret;
5936 5937
}

5938

5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971
/*
 * 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;
}


5972 5973 5974 5975
static char *qemuGetSchedulerType(virDomainPtr dom,
                                  int *nparams)
{
    struct qemud_driver *driver = dom->conn->privateData;
5976
    char *ret = NULL;
5977
    int rc;
5978

5979
    qemuDriverLock(driver);
5980
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5981 5982
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup CPU controller is not mounted"));
5983
        goto cleanup;
5984 5985
    }

5986 5987 5988 5989 5990 5991 5992 5993 5994
    if (nparams) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        else if (rc == 0)
            *nparams = 1;
        else
            *nparams = 3;
    }
5995 5996 5997

    ret = strdup("posix");
    if (!ret)
5998
        virReportOOMError();
5999 6000 6001

cleanup:
    qemuDriverUnlock(driver);
6002 6003 6004
    return ret;
}

6005
static int qemuDomainSetBlkioParameters(virDomainPtr dom,
6006
                                         virTypedParameterPtr params,
6007 6008 6009 6010 6011 6012 6013
                                         int nparams,
                                         unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6014
    virDomainDefPtr persistentDef = NULL;
6015
    int ret = -1;
6016
    bool isActive;
6017

6018 6019
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6020 6021 6022 6023 6024 6025 6026 6027 6028 6029
    qemuDriverLock(driver);

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

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

6030 6031 6032 6033 6034 6035 6036
    isActive = virDomainObjIsActive(vm);

    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
        if (isActive)
            flags = VIR_DOMAIN_AFFECT_LIVE;
        else
            flags = VIR_DOMAIN_AFFECT_CONFIG;
6037 6038
    }

6039 6040 6041 6042 6043 6044 6045 6046
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!isActive) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
            goto cleanup;
        }

        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
6047
            qemuReportError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted"));
6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065
            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_CONFIG) {
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot change persistent config of a transient domain"));
            goto cleanup;
        }
        if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
            goto cleanup;
6066 6067 6068
    }

    ret = 0;
6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                int rc;
                if (param->type != VIR_TYPED_PARAM_UINT) {
                    qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                    _("invalid type for blkio weight tunable, expected a 'unsigned int'"));
                    ret = -1;
                    continue;
                }

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

6089 6090 6091 6092 6093 6094 6095 6096 6097
                rc = virCgroupSetBlkioWeight(group, params[i].value.ui);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set blkio weight tunable"));
                    ret = -1;
                }
            } else {
                qemuReportError(VIR_ERR_INVALID_ARG,
                                _("Parameter `%s' not supported"), param->field);
6098 6099
                ret = -1;
            }
6100 6101
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
6102 6103 6104
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

6105 6106 6107 6108 6109 6110 6111 6112 6113 6114
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (param->type != VIR_TYPED_PARAM_UINT) {
                    qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                    _("invalid type for blkio weight tunable, expected a 'unsigned int'"));
                    ret = -1;
                    continue;
                }
6115

6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126
                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;
            } else {
                qemuReportError(VIR_ERR_INVALID_ARG,
                                _("Parameter `%s' not supported"), param->field);
6127 6128 6129
                ret = -1;
            }
        }
A
Alex Jia 已提交
6130 6131 6132

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143
    }

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

static int qemuDomainGetBlkioParameters(virDomainPtr dom,
6144
                                         virTypedParameterPtr params,
6145 6146 6147 6148 6149 6150 6151
                                         int *nparams,
                                         unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6152
    virDomainDefPtr persistentDef = NULL;
6153 6154 6155
    unsigned int val;
    int ret = -1;
    int rc;
6156
    bool isActive;
6157

6158 6159
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182
    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 ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

    if ((*nparams) != QEMU_NB_BLKIO_PARAM) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
        goto cleanup;
    }

6183 6184 6185 6186 6187 6188 6189
    isActive = virDomainObjIsActive(vm);

    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
        if (isActive)
            flags = VIR_DOMAIN_AFFECT_LIVE;
        else
            flags = VIR_DOMAIN_AFFECT_CONFIG;
6190 6191
    }

6192 6193 6194 6195 6196 6197
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!isActive) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
            goto cleanup;
        }
6198

6199
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
6200
            qemuReportError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted"));
6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246
            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_CONFIG) {
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot change persistent config of a transient domain"));
            goto cleanup;
        }
        if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        for (i = 0; i < *nparams; i++) {
            virTypedParameterPtr param = &params[i];
            val = 0;
            param->value.ui = 0;
            param->type = VIR_TYPED_PARAM_UINT;

            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;
                }
                if (virStrcpyStatic(param->field, VIR_DOMAIN_BLKIO_WEIGHT) == NULL) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("Field blkio weight too long for destination"));
                    goto cleanup;
                }
                param->value.ui = val;
                break;

            default:
                break;
                /* should not hit here */
6247
            }
6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        for (i = 0; i < *nparams; i++) {
            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,
                                    "%s", _("Field blkio weight too long for destination"));
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
6265

6266 6267 6268 6269
            default:
                break;
                /* should not hit here */
            }
6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282
        }
    }

    ret = 0;

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

static int qemuDomainSetMemoryParameters(virDomainPtr dom,
6285
                                         virTypedParameterPtr params,
6286
                                         int nparams,
6287
                                         unsigned int flags)
6288 6289 6290
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
6291
    virDomainDefPtr persistentDef = NULL;
6292 6293 6294
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
6295 6296
    bool isActive;

6297 6298
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309

    qemuDriverLock(driver);

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

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

6310 6311
    isActive = virDomainObjIsActive(vm);

6312
    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
6313
        if (isActive)
6314
            flags = VIR_DOMAIN_AFFECT_LIVE;
6315
        else
6316
            flags = VIR_DOMAIN_AFFECT_CONFIG;
6317 6318
    }

6319
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338
        if (!isActive) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
            goto cleanup;
        }

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

6339
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6340 6341 6342 6343 6344 6345 6346
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot change persistent config of a transient domain"));
            goto cleanup;
        }
        if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
            goto cleanup;
6347 6348 6349 6350
    }

    ret = 0;
    for (i = 0; i < nparams; i++) {
6351
        virTypedParameterPtr param = &params[i];
6352 6353 6354

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            int rc;
6355
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
6356 6357 6358 6359 6360 6361
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for memory hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

6362
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6363 6364 6365 6366 6367 6368 6369 6370
                rc = virCgroupSetMemoryHardLimit(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set memory hard_limit tunable"));
                    ret = -1;
                }
            }

6371
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6372
                persistentDef->mem.hard_limit = params[i].value.ul;
6373 6374 6375
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
            int rc;
6376
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
6377 6378 6379 6380 6381 6382
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for memory soft_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

6383
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6384 6385 6386 6387 6388 6389 6390 6391
                rc = virCgroupSetMemorySoftLimit(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set memory soft_limit tunable"));
                    ret = -1;
                }
            }

6392
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6393
                persistentDef->mem.soft_limit = params[i].value.ul;
6394
            }
6395
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
6396
            int rc;
6397
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
6398 6399 6400 6401 6402 6403
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for swap_hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

6404
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6405 6406 6407 6408 6409 6410 6411
                rc = virCgroupSetMemSwapHardLimit(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set swap_hard_limit tunable"));
                    ret = -1;
                }
            }
6412
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6413
                persistentDef->mem.swap_hard_limit = params[i].value.ul;
6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Memory tunable `%s' not implemented"), param->field);
            ret = -1;
        } else {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Parameter `%s' not supported"), param->field);
            ret = -1;
        }
    }

6426
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6427 6428
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
6429 6430
    }

6431 6432 6433 6434 6435 6436 6437 6438
cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

6439
static int qemuDomainGetMemoryParameters(virDomainPtr dom,
6440
                                         virTypedParameterPtr params,
6441
                                         int *nparams,
6442
                                         unsigned int flags)
6443 6444 6445 6446 6447
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6448
    virDomainDefPtr persistentDef = NULL;
6449
    unsigned long long val;
6450 6451
    int ret = -1;
    int rc;
6452
    bool isActive;
6453

6454 6455
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6456

6457
    qemuDriverLock(driver);
6458 6459 6460 6461 6462 6463 6464 6465 6466

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

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

6467 6468
    isActive = virDomainObjIsActive(vm);

6469
    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
6470
        if (isActive)
6471
            flags = VIR_DOMAIN_AFFECT_LIVE;
6472
        else
6473
            flags = VIR_DOMAIN_AFFECT_CONFIG;
6474 6475
    }

6476
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495
        if (!isActive) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
            goto cleanup;
        }

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

6496
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6497 6498 6499 6500 6501 6502 6503
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot change persistent config of a transient domain"));
            goto cleanup;
        }
        if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
            goto cleanup;
6504 6505
    }

6506 6507 6508 6509 6510 6511 6512
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

6513
    if ((*nparams) < QEMU_NB_MEM_PARAM) {
6514 6515 6516 6517 6518
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
        goto cleanup;
    }

6519
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6520 6521 6522 6523
        for (i = 0; i < *nparams; i++) {
            virMemoryParameterPtr param = &params[i];
            val = 0;
            param->value.ul = 0;
6524
            param->type = VIR_TYPED_PARAM_ULLONG;
6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559

            switch (i) {
            case 0: /* fill memory hard limit here */
                if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("Field memory hard limit too long for destination"));
                    goto cleanup;
                }
                param->value.ul = persistentDef->mem.hard_limit;
                break;

            case 1: /* fill memory soft limit here */
                if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("Field memory soft limit too long for destination"));
                    goto cleanup;
                }
                param->value.ul = persistentDef->mem.soft_limit;
                break;

            case 2: /* fill swap hard limit here */
                if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT) == NULL) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("Field swap hard limit too long for destination"));
                    goto cleanup;
                }
                param->value.ul = persistentDef->mem.swap_hard_limit;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
6560 6561
    }

6562
    for (i = 0; i < QEMU_NB_MEM_PARAM; i++) {
6563
        virTypedParameterPtr param = &params[i];
6564 6565
        val = 0;
        param->value.ul = 0;
6566
        param->type = VIR_TYPED_PARAM_ULLONG;
6567

6568 6569 6570
        /* Coverity does not realize that if we get here, group is set.  */
        sa_assert(group);

6571
        switch (i) {
6572 6573 6574 6575 6576
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
6577
                goto cleanup;
6578 6579 6580 6581
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field memory hard limit too long for destination"));
6582
                goto cleanup;
6583 6584 6585 6586 6587 6588 6589 6590 6591
            }
            param->value.ul = val;
            break;

        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
6592
                goto cleanup;
6593 6594 6595 6596
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field memory soft limit too long for destination"));
6597
                goto cleanup;
6598 6599 6600 6601 6602
            }
            param->value.ul = val;
            break;

        case 2: /* fill swap hard limit here */
6603
            rc = virCgroupGetMemSwapHardLimit(group, &val);
6604 6605 6606
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
6607
                goto cleanup;
6608
            }
6609
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT) == NULL) {
6610 6611
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field swap hard limit too long for destination"));
6612
                goto cleanup;
6613 6614 6615 6616 6617 6618 6619 6620 6621 6622
            }
            param->value.ul = val;
            break;

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

6623
out:
6624
    *nparams = QEMU_NB_MEM_PARAM;
6625 6626
    ret = 0;

6627 6628 6629 6630 6631 6632 6633 6634 6635
cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

6636 6637 6638 6639 6640 6641 6642 6643
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 已提交
6644 6645 6646
    long long vm_quota = 0;
    long long old_quota = 0;
    unsigned long long old_period = 0;
6647 6648 6649 6650

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

W
Wen Congyang 已提交
6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669
    /* 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;
    }
6670

W
Wen Congyang 已提交
6671 6672 6673 6674 6675
    rc = virCgroupGetCpuCfsPeriod(cgroup, &old_period);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth period tunable"));
        goto cleanup;
6676 6677
    }

W
Wen Congyang 已提交
6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698
    /*
     * 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;
6699
        }
W
Wen Congyang 已提交
6700
    }
6701

W
Wen Congyang 已提交
6702 6703 6704 6705
    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)
6706 6707
            goto cleanup;

W
Wen Congyang 已提交
6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727
    /* 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);
        }
6728 6729
    }

W
Wen Congyang 已提交
6730 6731 6732 6733 6734 6735
    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;

6736 6737 6738 6739 6740 6741 6742
    return 0;

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

6743
static int qemuSetSchedulerParametersFlags(virDomainPtr dom,
6744
                                           virTypedParameterPtr params,
6745 6746
                                           int nparams,
                                           unsigned int flags)
6747 6748 6749 6750 6751
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6752
    virDomainDefPtr vmdef = NULL;
6753
    int ret = -1;
6754
    bool isActive;
6755
    int rc;
6756

6757 6758
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6759

6760
    qemuDriverLock(driver);
6761 6762 6763 6764

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

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

6770 6771
    isActive = virDomainObjIsActive(vm);

6772
    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
6773
        if (isActive)
6774
            flags = VIR_DOMAIN_AFFECT_LIVE;
6775
        else
6776
            flags = VIR_DOMAIN_AFFECT_CONFIG;
6777 6778
    }

6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot change persistent config of a transient domain"));
            goto cleanup;
        }

        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto cleanup;
6790 6791
    }

6792
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811
        if (!isActive) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
            goto cleanup;
        }

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

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

        if (STREQ(param->field, "cpu_shares")) {
6816
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
6817 6818
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for cpu_shares tunable, expected a 'ullong'"));
6819 6820 6821
                goto cleanup;
            }

6822
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6823 6824 6825 6826 6827 6828 6829 6830
                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;
6831
            }
6832

6833
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6834 6835
                vmdef->cputune.shares = params[i].value.ul;
            }
W
Wen Congyang 已提交
6836
        } else if (STREQ(param->field, "vcpu_period")) {
6837 6838
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
W
Wen Congyang 已提交
6839
                                _("invalid type for vcpu_period tunable,"
6840 6841 6842 6843 6844 6845 6846
                                  " expected a 'ullong'"));
                goto cleanup;
            }

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = qemuSetVcpusBWLive(vm, group, params[i].value.ul, 0);
                if (rc != 0)
6847
                    goto cleanup;
6848 6849 6850 6851 6852 6853 6854 6855

                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;
            }
W
Wen Congyang 已提交
6856
        } else if (STREQ(param->field, "vcpu_quota")) {
6857 6858
            if (param->type != VIR_TYPED_PARAM_LLONG) {
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
W
Wen Congyang 已提交
6859
                                _("invalid type for vcpu_quota tunable,"
6860 6861 6862 6863 6864 6865 6866
                                  " expected a 'llong'"));
                goto cleanup;
            }

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = qemuSetVcpusBWLive(vm, group, 0, params[i].value.l);
                if (rc != 0)
6867
                    goto cleanup;
6868 6869 6870 6871 6872 6873 6874

                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;
6875
            }
6876
        } else {
6877 6878
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Invalid parameter `%s'"), param->field);
6879 6880 6881
            goto cleanup;
        }
    }
6882

6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895
    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;
    }

6896 6897 6898
    ret = 0;

cleanup:
6899
    virDomainDefFree(vmdef);
6900 6901 6902
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
6903
    qemuDriverUnlock(driver);
6904 6905 6906
    return ret;
}

6907
static int qemuSetSchedulerParameters(virDomainPtr dom,
6908
                                      virTypedParameterPtr params,
6909 6910 6911 6912 6913
                                      int nparams)
{
    return qemuSetSchedulerParametersFlags(dom,
                                           params,
                                           nparams,
6914
                                           VIR_DOMAIN_AFFECT_LIVE);
6915 6916
}

6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981
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;
}

6982 6983 6984 6985 6986
static int
qemuGetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int *nparams,
                                unsigned int flags)
6987 6988 6989 6990
{
    struct qemud_driver *driver = dom->conn->privateData;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6991 6992 6993
    unsigned long long shares;
    unsigned long long period;
    long long quota;
6994 6995
    int ret = -1;
    int rc;
6996
    bool isActive;
6997
    bool cpu_bw_status = false;
6998
    int saved_nparams = 0;
6999

7000 7001
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7002

7003 7004
    qemuDriverLock(driver);

7005 7006
    if ((flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) ==
        (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) {
7007 7008
        qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                        _("cannot query live and config together"));
7009
        goto cleanup;
7010 7011
    }

7012
    if (*nparams < 1) {
7013 7014
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
7015
        goto cleanup;
7016 7017
    }

7018 7019 7020 7021 7022 7023 7024
    if (*nparams > 1) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        cpu_bw_status = !!rc;
    }

7025 7026 7027
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

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

7033 7034
    isActive = virDomainObjIsActive(vm);

7035
    if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
7036
        if (isActive)
7037
            flags = VIR_DOMAIN_AFFECT_LIVE;
7038
        else
7039
            flags = VIR_DOMAIN_AFFECT_CONFIG;
7040 7041
    }

7042
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057
        if (!vm->persistent) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("cannot query persistent config of a transient domain"));
            goto cleanup;
        }

        if (isActive) {
            virDomainDefPtr persistentDef;

            persistentDef = virDomainObjGetPersistentDef(driver->caps, vm);
            if (!persistentDef) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                _("can't get persistentDef"));
                goto cleanup;
            }
7058 7059 7060 7061 7062
            shares = persistentDef->cputune.shares;
            if (*nparams > 1 && cpu_bw_status) {
                period = persistentDef->cputune.period;
                quota = persistentDef->cputune.quota;
            }
7063
        } else {
7064 7065 7066 7067 7068
            shares = vm->def->cputune.shares;
            if (*nparams > 1 && cpu_bw_status) {
                period = vm->def->cputune.period;
                quota = vm->def->cputune.quota;
            }
7069
        }
7070
        goto out;
7071 7072
    }

7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084
    if (!isActive) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("domain is not running"));
        goto cleanup;
    }

    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup CPU controller is not mounted"));
        goto cleanup;
    }

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

7091
    rc = virCgroupGetCpuShares(group, &shares);
7092
    if (rc != 0) {
7093
        virReportSystemError(-rc, "%s",
7094 7095 7096
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
7097 7098 7099 7100 7101 7102

    if (*nparams > 1 && cpu_bw_status) {
        rc = qemuGetVcpusBWLive(vm, group, &period, &quota);
        if (rc != 0)
            goto cleanup;
    }
7103
out:
7104
    params[0].value.ul = shares;
7105
    params[0].type = VIR_TYPED_PARAM_ULLONG;
C
Chris Lalancette 已提交
7106
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
7107 7108
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Field cpu_shares too long for destination"));
C
Chris Lalancette 已提交
7109 7110
        goto cleanup;
    }
7111

7112 7113 7114 7115 7116 7117
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
            params[1].value.ul = period;
            params[1].type = VIR_TYPED_PARAM_ULLONG;
W
Wen Congyang 已提交
7118
            if (virStrcpyStatic(params[1].field, "vcpu_period") == NULL) {
7119 7120
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s",
W
Wen Congyang 已提交
7121
                                _("Field vcpu_period too long for destination"));
7122 7123 7124 7125 7126 7127 7128 7129
                goto cleanup;
            }
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
            params[2].value.ul = quota;
            params[2].type = VIR_TYPED_PARAM_LLONG;
W
Wen Congyang 已提交
7130
            if (virStrcpyStatic(params[2].field, "vcpu_quota") == NULL) {
7131 7132
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s",
W
Wen Congyang 已提交
7133
                                _("Field vcpu_quota too long for destination"));
7134 7135 7136 7137 7138 7139 7140 7141
                goto cleanup;
            }
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

7142 7143 7144 7145 7146 7147
    ret = 0;

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

7152 7153 7154 7155 7156 7157
static int
qemuGetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int *nparams)
{
    return qemuGetSchedulerParametersFlags(dom, params, nparams,
7158
                                           VIR_DOMAIN_AFFECT_CURRENT);
7159
}
7160

7161 7162 7163 7164 7165 7166 7167 7168 7169
/* 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
qemudDomainBlockStats (virDomainPtr dom,
                       const char *path,
                       struct _virDomainBlockStats *stats)
{
7170
    struct qemud_driver *driver = dom->conn->privateData;
7171
    int i, ret = -1;
7172
    virDomainObjPtr vm;
7173
    virDomainDiskDefPtr disk = NULL;
7174
    qemuDomainObjPrivatePtr priv;
7175

7176
    qemuDriverLock(driver);
7177
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
7178
    qemuDriverUnlock(driver);
7179
    if (!vm) {
7180 7181
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7182 7183
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7184
        goto cleanup;
7185
    }
7186

7187 7188 7189 7190 7191 7192
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

7193 7194 7195 7196 7197 7198 7199 7200
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
7201 7202
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path: %s"), path);
7203
        goto cleanup;
7204 7205
    }

7206
    if (!disk->info.alias) {
7207 7208
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), disk->dst);
7209
        goto cleanup;
7210
    }
7211

7212
    priv = vm->privateData;
7213 7214
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;
7215

7216 7217 7218 7219 7220
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }
7221

7222
    qemuDomainObjEnterMonitor(driver, vm);
7223 7224 7225 7226 7227 7228 7229 7230
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
                                       &stats->wr_req,
                                       &stats->wr_bytes,
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
7231

7232
endjob:
7233 7234
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
7235

7236
cleanup:
7237 7238
    if (vm)
        virDomainObjUnlock(vm);
7239
    return ret;
7240 7241
}

7242
#ifdef __linux__
7243 7244 7245 7246 7247
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
7248 7249
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
7250
    int i;
7251
    int ret = -1;
7252

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

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

D
Daniel P. Berrange 已提交
7265
    if (!virDomainObjIsActive(vm)) {
7266 7267
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
7268
        goto cleanup;
7269 7270 7271
    }

    /* Check the path is one of the domain's network interfaces. */
7272 7273
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
7274 7275 7276 7277
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
7278 7279
    }

7280
    if (ret == 0)
7281
        ret = linuxDomainInterfaceStats(path, stats);
7282
    else
7283 7284
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path, '%s' is not a known interface"), path);
7285

7286
cleanup:
7287 7288
    if (vm)
        virDomainObjUnlock(vm);
7289 7290
    return ret;
}
7291
#else
7292 7293 7294 7295
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
7296
{
7297 7298
    qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                    _("interface stats not implemented on this platform"));
7299 7300
    return -1;
}
7301
#endif
7302

7303 7304 7305
static int
qemudDomainMemoryStats (virDomainPtr dom,
                        struct _virDomainMemoryStat *stats,
7306 7307
                        unsigned int nr_stats,
                        unsigned int flags)
7308 7309 7310 7311 7312
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned int ret = -1;

7313 7314
    virCheckFlags(0, -1);

7315 7316 7317 7318 7319 7320 7321
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

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

7327
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
7328 7329
        goto cleanup;

7330 7331
    if (virDomainObjIsActive(vm)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
7332
        qemuDomainObjEnterMonitor(driver, vm);
7333
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
7334
        qemuDomainObjExitMonitor(driver, vm);
7335
    } else {
7336 7337
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
7338 7339
    }

7340
    if (qemuDomainObjEndJob(driver, vm) == 0)
7341 7342
        vm = NULL;

7343 7344 7345 7346 7347 7348
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

7349 7350 7351 7352 7353
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
E
Eric Blake 已提交
7354
                      unsigned int flags)
7355
{
7356 7357 7358
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
7359

E
Eric Blake 已提交
7360 7361
    virCheckFlags(0, -1);

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

7366
    if (!vm) {
7367 7368
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7369 7370
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7371
        goto cleanup;
7372 7373 7374
    }

    if (!path || path[0] == '\0') {
7375 7376
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("NULL or empty path"));
7377
        goto cleanup;
7378 7379 7380
    }

    /* Check the path belongs to this domain. */
7381 7382
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
7383 7384 7385 7386
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
7387 7388
    }

7389 7390 7391 7392 7393
    if (ret == 0) {
        ret = -1;
        /* The path is correct, now try to open it and get its size. */
        fd = open (path, O_RDONLY);
        if (fd == -1) {
7394 7395
            virReportSystemError(errno,
                                 _("%s: failed to open"), path);
7396 7397
            goto cleanup;
        }
7398

7399 7400 7401 7402 7403 7404
        /* 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) {
7405 7406
            virReportSystemError(errno,
                                 _("%s: failed to seek or read"), path);
7407 7408 7409 7410 7411
            goto cleanup;
        }

        ret = 0;
    } else {
7412 7413
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("invalid path"));
7414 7415
    }

7416
cleanup:
7417
    VIR_FORCE_CLOSE(fd);
7418 7419
    if (vm)
        virDomainObjUnlock(vm);
7420 7421 7422
    return ret;
}

R
Richard W.M. Jones 已提交
7423 7424 7425 7426 7427 7428
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
7429 7430
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
7431
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
7432
    int fd = -1, ret = -1;
7433
    qemuDomainObjPrivatePtr priv;
R
Richard W.M. Jones 已提交
7434

7435 7436
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

7437
    qemuDriverLock(driver);
7438
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
7439
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
7440 7441

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

7449
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
7450 7451
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
7452
        goto cleanup;
R
Richard W.M. Jones 已提交
7453 7454
    }

7455
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
7456 7457
        goto cleanup;

D
Daniel P. Berrange 已提交
7458
    if (!virDomainObjIsActive(vm)) {
7459 7460
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
7461
        goto endjob;
R
Richard W.M. Jones 已提交
7462 7463
    }

7464
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", driver->cacheDir) < 0) {
7465
        virReportOOMError();
7466
        goto endjob;
7467 7468
    }

R
Richard W.M. Jones 已提交
7469 7470
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
7471 7472
        virReportSystemError(errno,
                             _("mkstemp(\"%s\") failed"), tmp);
7473
        goto endjob;
R
Richard W.M. Jones 已提交
7474 7475
    }

7476 7477
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm, tmp);

7478
    priv = vm->privateData;
7479
    qemuDomainObjEnterMonitor(driver, vm);
7480
    if (flags == VIR_MEMORY_VIRTUAL) {
7481
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
7482
            qemuDomainObjExitMonitor(driver, vm);
7483
            goto endjob;
7484
        }
7485
    } else {
7486
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
7487
            qemuDomainObjExitMonitor(driver, vm);
7488
            goto endjob;
7489
        }
R
Richard W.M. Jones 已提交
7490
    }
7491
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
7492 7493 7494

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
7495 7496 7497
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
7498
        goto endjob;
R
Richard W.M. Jones 已提交
7499 7500 7501
    }

    ret = 0;
7502

7503
endjob:
7504
    if (qemuDomainObjEndJob(driver, vm) == 0)
7505
        vm = NULL;
7506

7507
cleanup:
7508
    VIR_FORCE_CLOSE(fd);
7509 7510
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
7511
    VIR_FREE(tmp);
7512 7513
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
7514 7515 7516
    return ret;
}

7517

7518 7519 7520 7521 7522 7523 7524 7525 7526
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;
7527
    virStorageFileMetadata *meta = NULL;
7528
    virDomainDiskDefPtr disk = NULL;
7529 7530
    struct stat sb;
    int i;
7531
    int format;
7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555

    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. */
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
            STREQ (vm->def->disks[i]->src, path)) {
7556
            disk = vm->def->disks[i];
7557 7558 7559 7560
            break;
        }
    }

7561
    if (!disk) {
7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path %s not assigned to domain"), path);
        goto cleanup;
    }

    /* The path is correct, now try to open it and get its size. */
    fd = open (path, O_RDONLY);
    if (fd == -1) {
        virReportSystemError(errno,
                             _("failed to open path '%s'"), path);
        goto cleanup;
    }

    /* Probe for magic formats */
7576 7577 7578 7579 7580 7581 7582 7583
    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 {
7584 7585 7586 7587 7588 7589 7590
        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);
7591
            goto cleanup;
7592
        }
7593 7594
    }

7595 7596 7597 7598 7599
    if (VIR_ALLOC(meta) < 0) {
        virReportOOMError();
        goto cleanup;
    }

7600 7601
    if (virStorageFileGetMetadataFromFD(path, fd,
                                        format,
7602
                                        meta) < 0)
7603 7604 7605 7606 7607 7608 7609 7610 7611 7612
        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)) {
7613
#ifndef WIN32
7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638
        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.
         */
        end = lseek (fd, 0, SEEK_END);
        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 */
7639 7640
    if (meta->capacity)
        info->capacity = meta->capacity;
7641

7642
    /* Set default value .. */
7643 7644
    info->allocation = info->physical;

7645 7646 7647
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
7648
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
7649
        format != VIR_STORAGE_FILE_RAW &&
7650 7651
        S_ISBLK(sb.st_mode) &&
        virDomainObjIsActive(vm)) {
7652
        qemuDomainObjPrivatePtr priv = vm->privateData;
7653

7654 7655
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
            goto cleanup;
7656

7657
        if (virDomainObjIsActive(vm)) {
7658
            qemuDomainObjEnterMonitor(driver, vm);
7659 7660 7661 7662
            ret = qemuMonitorGetBlockExtent(priv->mon,
                                            disk->info.alias,
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
7663
        } else {
7664
            ret = 0;
7665
        }
7666 7667 7668

        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
7669 7670 7671
    } else {
        ret = 0;
    }
7672 7673

cleanup:
7674
    virStorageFileFreeMetadata(meta);
7675
    VIR_FORCE_CLOSE(fd);
7676 7677 7678 7679 7680 7681
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


7682
static int
7683 7684 7685 7686
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
7687
{
7688 7689 7690
    struct qemud_driver *driver = conn->privateData;
    int ret;

7691
    qemuDriverLock(driver);
7692 7693
    ret = virDomainEventCallbackListAdd(conn,
                                        driver->domainEventState->callbacks,
7694
                                        callback, opaque, freecb);
7695
    qemuDriverUnlock(driver);
7696

7697
    return ret;
7698 7699
}

7700

7701
static int
7702 7703
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
7704
{
7705 7706 7707
    struct qemud_driver *driver = conn->privateData;
    int ret;

7708
    qemuDriverLock(driver);
7709 7710 7711
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
7712
    qemuDriverUnlock(driver);
7713

7714
    return ret;
7715 7716
}

7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730

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);
    ret = virDomainEventCallbackListAddID(conn,
7731
                                          driver->domainEventState->callbacks,
7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747
                                          dom, eventID,
                                          callback, opaque, freecb);
    qemuDriverUnlock(driver);

    return ret;
}


static int
qemuDomainEventDeregisterAny(virConnectPtr conn,
                             int callbackID)
{
    struct qemud_driver *driver = conn->privateData;
    int ret;

    qemuDriverLock(driver);
7748 7749 7750
    ret = virDomainEventStateDeregisterAny(conn,
                                           driver->domainEventState,
                                           callbackID);
7751 7752 7753 7754 7755 7756
    qemuDriverUnlock(driver);

    return ret;
}


7757 7758 7759
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
7760

C
Chris Lalancette 已提交
7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775
/* 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;
7776

7777
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
7778

7779 7780
    qemuDriverLock(driver);

C
Chris Lalancette 已提交
7781
    if (!dom_xml) {
7782 7783
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
7784 7785 7786
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
7787
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
7788 7789 7790 7791
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
7792 7793
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
7794 7795 7796
        goto cleanup;
    }

7797 7798 7799 7800 7801 7802 7803
    if (virLockManagerPluginUsesState(driver->lockManager)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot use migrate v2 protocol with lock manager %s"),
                        virLockManagerPluginGetName(driver->lockManager));
        goto cleanup;
    }

7804 7805 7806
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
                                     st, dname, dom_xml);
7807

C
Chris Lalancette 已提交
7808
cleanup:
7809
    qemuDriverUnlock(driver);
C
Chris Lalancette 已提交
7810 7811 7812
    return ret;
}

D
Daniel Veillard 已提交
7813 7814 7815 7816
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
7817
static int ATTRIBUTE_NONNULL (5)
D
Daniel Veillard 已提交
7818
qemudDomainMigratePrepare2 (virConnectPtr dconn,
7819 7820
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
D
Daniel Veillard 已提交
7821 7822
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
7823
                            unsigned long flags,
D
Daniel Veillard 已提交
7824 7825 7826 7827
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
7828
    struct qemud_driver *driver = dconn->privateData;
7829
    int ret = -1;
7830

7831
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
7832

7833
    *uri_out = NULL;
D
Daniel Veillard 已提交
7834

7835
    qemuDriverLock(driver);
7836 7837 7838 7839 7840 7841 7842 7843

    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 已提交
7844 7845 7846 7847
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
7848 7849
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
7850 7851 7852
        goto cleanup;
    }

D
Daniel Veillard 已提交
7853
    if (!dom_xml) {
7854 7855
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
7856
        goto cleanup;
D
Daniel Veillard 已提交
7857 7858
    }

7859 7860 7861 7862
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
7863
    ret = qemuMigrationPrepareDirect(driver, dconn,
7864
                                     NULL, 0, NULL, NULL, /* No cookies */
7865 7866
                                     uri_in, uri_out,
                                     dname, dom_xml);
D
Daniel Veillard 已提交
7867

7868 7869 7870 7871
cleanup:
    qemuDriverUnlock(driver);
    return ret;
}
C
Chris Lalancette 已提交
7872

D
Daniel Veillard 已提交
7873

7874 7875 7876
/* Perform is the second step, and it runs on the source host. */
static int
qemudDomainMigratePerform (virDomainPtr dom,
7877 7878
                           const char *cookie,
                           int cookielen,
7879 7880 7881 7882 7883 7884 7885 7886
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
7887
    const char *dconnuri = NULL;
7888

7889
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
7890

7891
    qemuDriverLock(driver);
7892 7893 7894 7895 7896 7897 7898
    if (virLockManagerPluginUsesState(driver->lockManager)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot use migrate v2 protocol with lock manager %s"),
                        virLockManagerPluginGetName(driver->lockManager));
        goto cleanup;
    }

7899
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
7900
    if (!vm) {
7901 7902
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7903 7904
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7905
        goto cleanup;
D
Daniel Veillard 已提交
7906 7907
    }

7908 7909 7910 7911 7912
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

7913 7914 7915 7916 7917 7918
    /* 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
     */
7919
    ret = qemuMigrationPerform(driver, dom->conn, vm,
7920
                               NULL, dconnuri, uri, cookie, cookielen,
7921
                               NULL, NULL, /* No output cookies in v2 */
7922
                               flags, dname, resource, false);
7923

7924
cleanup:
7925
    qemuDriverUnlock(driver);
7926
    return ret;
D
Daniel Veillard 已提交
7927 7928
}

7929

D
Daniel Veillard 已提交
7930 7931 7932 7933 7934 7935 7936
/* 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 已提交
7937
                           unsigned long flags,
D
Daniel Veillard 已提交
7938 7939
                           int retcode)
{
7940 7941 7942
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
7943

7944
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
7945

7946
    qemuDriverLock(driver);
7947
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
7948
    if (!vm) {
7949 7950
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
7951
        goto cleanup;
D
Daniel Veillard 已提交
7952 7953
    }

7954 7955 7956 7957
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
7958
    dom = qemuMigrationFinish(driver, dconn, vm,
7959
                              NULL, 0, NULL, NULL, /* No cookies */
7960
                              flags, retcode, false);
7961

7962
cleanup:
7963
    qemuDriverUnlock(driver);
7964
    return dom;
D
Daniel Veillard 已提交
7965 7966
}

7967

7968 7969 7970 7971 7972 7973
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
7974
                        const char *xmlin,
7975 7976 7977 7978 7979 7980 7981 7982 7983 7984
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
                        const char *dname ATTRIBUTE_UNUSED,
                        unsigned long resource ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    char *xml = NULL;

7985
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996

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

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

    if (!(xml = qemuMigrationBegin(driver, vm, xmlin,
                                   cookieout, cookieoutlen)))
        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;
    }
8031 8032

cleanup:
8033 8034
    if (vm)
        virDomainObjUnlock(vm);
8035 8036
    qemuDriverUnlock(driver);
    return xml;
8037 8038 8039 8040 8041 8042 8043 8044 8045 8046

endjob:
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobFinish(driver, vm) == 0)
            vm = NULL;
    } else {
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    }
    goto cleanup;
8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064
}

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;

8065
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111

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

8112
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143

    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,
8144
                          const char *xmlin,
8145 8146 8147 8148
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
8149
                          const char *dconnuri,
8150 8151 8152 8153 8154 8155 8156 8157 8158
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

8159
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170

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

8171
    ret = qemuMigrationPerform(driver, dom->conn, vm, xmlin,
8172
                               dconnuri, uri, cookiein, cookieinlen,
8173
                               cookieout, cookieoutlen,
8174
                               flags, dname, resource, true);
8175 8176 8177 8178 8179 8180 8181

cleanup:
    qemuDriverUnlock(driver);
    return ret;
}


8182
static virDomainPtr
8183 8184 8185 8186 8187 8188
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
8189
                         const char *dconnuri ATTRIBUTE_UNUSED,
8190 8191
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
8192
                         int cancelled)
8193 8194 8195
{
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
8196
    virDomainPtr dom = NULL;
8197

8198
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
8199 8200 8201 8202 8203 8204 8205 8206 8207

    qemuDriverLock(driver);
    vm = virDomainFindByName(&driver->domains, dname);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
        goto cleanup;
    }

8208 8209 8210 8211
    dom = qemuMigrationFinish(driver, dconn, vm,
                              cookiein, cookieinlen,
                              cookieout, cookieoutlen,
                              flags, cancelled, true);
8212 8213 8214

cleanup:
    qemuDriverUnlock(driver);
8215
    return dom;
8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227
}

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;
8228
    enum qemuMigrationJobPhase phase;
8229

8230
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241

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

8242
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
8243 8244
        goto cleanup;

8245 8246 8247 8248 8249 8250 8251
    if (cancelled)
        phase = QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED;
    else
        phase = QEMU_MIGRATION_PHASE_CONFIRM3;

    qemuMigrationJobStartPhase(driver, vm, phase);

8252 8253
    ret = qemuMigrationConfirm(driver, domain->conn, vm,
                               cookiein, cookieinlen,
8254 8255
                               flags, cancelled);

8256
    if (qemuMigrationJobFinish(driver, vm) == 0) {
8257 8258 8259 8260 8261 8262 8263 8264 8265
        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);
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }

8266
cleanup:
8267 8268
    if (vm)
        virDomainObjUnlock(vm);
8269 8270 8271 8272 8273
    qemuDriverUnlock(driver);
    return ret;
}


8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289
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;

8290
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE);
8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307
    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) {
8308 8309
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("device %s is not a PCI device"), dev->name);
8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
qemudNodeDeviceDettach (virNodeDevicePtr dev)
{
8323
    struct qemud_driver *driver = dev->conn->privateData;
8324 8325 8326 8327 8328 8329 8330
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

8331
    pci = pciGetDevice(domain, bus, slot, function);
8332 8333 8334
    if (!pci)
        return -1;

8335 8336
    qemuDriverLock(driver);
    if (pciDettachDevice(pci, driver->activePciHostdevs) < 0)
8337 8338 8339 8340
        goto out;

    ret = 0;
out:
8341
    qemuDriverUnlock(driver);
8342
    pciFreeDevice(pci);
8343 8344 8345 8346 8347 8348
    return ret;
}

static int
qemudNodeDeviceReAttach (virNodeDevicePtr dev)
{
8349
    struct qemud_driver *driver = dev->conn->privateData;
8350 8351 8352 8353 8354 8355 8356
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

8357
    pci = pciGetDevice(domain, bus, slot, function);
8358 8359 8360
    if (!pci)
        return -1;

8361 8362
    pciDeviceReAttachInit(pci);

8363 8364
    qemuDriverLock(driver);
    if (pciReAttachDevice(pci, driver->activePciHostdevs) < 0)
8365 8366 8367 8368
        goto out;

    ret = 0;
out:
8369
    qemuDriverUnlock(driver);
8370
    pciFreeDevice(pci);
8371 8372 8373 8374 8375 8376
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
8377
    struct qemud_driver *driver = dev->conn->privateData;
8378 8379 8380 8381 8382 8383 8384
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

8385
    pci = pciGetDevice(domain, bus, slot, function);
8386 8387 8388
    if (!pci)
        return -1;

8389 8390
    qemuDriverLock(driver);

8391
    if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
8392 8393 8394 8395
        goto out;

    ret = 0;
out:
8396
    qemuDriverUnlock(driver);
8397
    pciFreeDevice(pci);
8398 8399 8400
    return ret;
}

8401 8402 8403
static int
qemuCPUCompare(virConnectPtr conn,
               const char *xmlDesc,
E
Eric Blake 已提交
8404
               unsigned int flags)
8405 8406 8407 8408
{
    struct qemud_driver *driver = conn->privateData;
    int ret = VIR_CPU_COMPARE_ERROR;

E
Eric Blake 已提交
8409 8410
    virCheckFlags(0, VIR_CPU_COMPARE_ERROR);

8411 8412 8413
    qemuDriverLock(driver);

    if (!driver->caps || !driver->caps->host.cpu) {
8414
        qemuReportError(VIR_ERR_OPERATION_INVALID,
8415
                        "%s", _("cannot get host CPU capabilities"));
E
Eric Blake 已提交
8416
    } else {
8417
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
E
Eric Blake 已提交
8418
    }
8419 8420 8421 8422 8423 8424

    qemuDriverUnlock(driver);

    return ret;
}

8425

8426 8427 8428 8429
static char *
qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED,
                const char **xmlCPUs,
                unsigned int ncpus,
E
Eric Blake 已提交
8430
                unsigned int flags)
8431 8432 8433
{
    char *cpu;

E
Eric Blake 已提交
8434 8435
    virCheckFlags(0, NULL);

8436 8437 8438 8439 8440
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0);

    return cpu;
}

8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462

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)) {
8463
        if (priv->job.asyncJob) {
8464
            memcpy(info, &priv->job.info, sizeof(*info));
8465 8466 8467 8468 8469 8470

            /* Refresh elapsed time again just to ensure it
             * is fully updated. This is primarily for benefit
             * of incoming migration which we don't currently
             * monitor actively in the background thread
             */
J
Jiri Denemark 已提交
8471
            if (virTimeMs(&info->timeElapsed) < 0)
8472
                goto cleanup;
8473
            info->timeElapsed -= priv->job.start;
8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492
        } 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;
}


8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509
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;
    }

8510 8511
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
8512

8513
    if (!virDomainObjIsActive(vm)) {
8514 8515
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8516
        goto endjob;
8517 8518
    }

8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532
    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");
8533
    qemuDomainObjEnterMonitor(driver, vm);
8534 8535 8536 8537 8538 8539
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
8540 8541 8542 8543 8544 8545 8546 8547

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


8548 8549 8550 8551 8552 8553 8554 8555 8556 8557
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;

8558
    virCheckFlags(0, -1);
8559 8560 8561

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8562
    qemuDriverUnlock(driver);
8563 8564 8565 8566 8567 8568

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

8572 8573 8574
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

8575 8576 8577
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8578
        goto endjob;
8579 8580 8581 8582
    }

    priv = vm->privateData;

8583
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
8584 8585
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not being migrated"));
8586
        goto endjob;
8587 8588
    }

8589
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
8590
    qemuDomainObjEnterMonitor(driver, vm);
8591 8592 8593 8594 8595 8596
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
8597 8598 8599 8600 8601 8602 8603

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

8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617
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);
8618
    qemuDriverUnlock(driver);
8619 8620 8621 8622 8623 8624

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

8628 8629 8630
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

8631 8632 8633
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8634
        goto endjob;
8635 8636 8637 8638
    }

    priv = vm->privateData;

8639
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
8640 8641
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not being migrated"));
8642
        goto endjob;
8643 8644
    }

8645
    VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
8646
    qemuDomainObjEnterMonitor(driver, vm);
8647 8648 8649 8650 8651 8652
    ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
8653 8654 8655 8656 8657 8658 8659

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

C
Chris Lalancette 已提交
8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672
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++) {
        if (vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
            (!vm->def->disks[i]->driverType ||
             STRNEQ(vm->def->disks[i]->driverType, "qcow2"))) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
8673 8674
                            _("Disk '%s' does not support snapshotting"),
                            vm->def->disks[i]->src);
C
Chris Lalancette 已提交
8675 8676 8677 8678 8679 8680 8681
            return 0;
        }
    }

    return 1;
}

8682 8683
/* The domain is expected to be locked and inactive. */
static int
E
Eric Blake 已提交
8684 8685
qemuDomainSnapshotCreateInactive(struct qemud_driver *driver,
                                 virDomainObjPtr vm,
8686 8687
                                 virDomainSnapshotObjPtr snap)
{
E
Eric Blake 已提交
8688
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
8689 8690
}

8691 8692
/* The domain is expected to be locked and active. */
static int
8693 8694
qemuDomainSnapshotCreateActive(virConnectPtr conn,
                               struct qemud_driver *driver,
8695 8696 8697 8698 8699
                               virDomainObjPtr *vmptr,
                               virDomainSnapshotObjPtr snap)
{
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
8700 8701
    bool resume = false;
    int ret = -1;
8702

8703
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
8704 8705
        return -1;

J
Jiri Denemark 已提交
8706
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
8707 8708 8709 8710
        /* 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.
         */
8711 8712
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
8713 8714 8715 8716 8717 8718 8719 8720 8721 8722
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto cleanup;
        }
    }

8723
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8724 8725 8726
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

8727 8728
cleanup:
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
8729
        qemuProcessStartCPUs(driver, vm, conn,
8730 8731
                             VIR_DOMAIN_RUNNING_UNPAUSED,
                             QEMU_ASYNC_JOB_NONE) < 0 &&
8732 8733 8734 8735 8736
        virGetLastError() == NULL) {
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("resuming after snapshot failed"));
    }

8737 8738 8739
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
8740
        *vmptr = NULL;
8741 8742
        ret = -1;
    }
8743 8744 8745 8746

    return ret;
}

C
Chris Lalancette 已提交
8747 8748
static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
                                                        const char *xmlDesc,
8749
                                                        unsigned int flags)
C
Chris Lalancette 已提交
8750 8751 8752 8753 8754 8755
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
8756
    virDomainSnapshotDefPtr def = NULL;
8757 8758
    bool update_current = true;
    unsigned int parse_flags = 0;
C
Chris Lalancette 已提交
8759

8760 8761 8762 8763 8764 8765 8766 8767 8768 8769
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);

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

C
Chris Lalancette 已提交
8771 8772 8773 8774 8775 8776 8777 8778 8779
    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;
    }

8780 8781 8782 8783 8784 8785
    if (qemuProcessAutoDestroyActive(driver, vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is marked for auto destroy"));
        goto cleanup;
    }

C
Chris Lalancette 已提交
8786 8787 8788 8789 8790 8791 8792 8793 8794 8795
    /* 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;

8796 8797 8798
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
8799 8800
        goto cleanup;

8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        virDomainSnapshotObjPtr other = NULL;

        /* 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 */
        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;
            }
            /* XXX Ensure ABI compatibility before replacing anything.  */
            if (other == vm->current_snapshot) {
                update_current = true;
                vm->current_snapshot = NULL;
            }
            virDomainSnapshotObjListRemove(&vm->snapshots, other);
        } else {
            /* XXX Should we do some feasibility checks, like parsing
             * qemu-img output to check that def->name matches at
             * least one qcow2 snapshot name?  */
        }
    }

C
Chris Lalancette 已提交
8862 8863
    if (!(snap = virDomainSnapshotAssignDef(&vm->snapshots, def)))
        goto cleanup;
8864
    def = NULL;
C
Chris Lalancette 已提交
8865

8866 8867 8868 8869
    if (update_current)
        snap->def->current = true;
    if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE))
        snap->def->state = virDomainObjGetState(vm, NULL);
8870
    if (vm->current_snapshot) {
8871 8872 8873 8874 8875 8876
        if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
            snap->def->parent = strdup(vm->current_snapshot->def->name);
            if (snap->def->parent == NULL) {
                virReportOOMError();
                goto cleanup;
            }
8877
        }
8878
        if (update_current) {
8879 8880 8881 8882 8883 8884
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                                driver->snapshotDir) < 0)
                goto cleanup;
            vm->current_snapshot = NULL;
        }
8885
    }
8886

C
Chris Lalancette 已提交
8887
    /* actually do the snapshot */
8888 8889 8890 8891 8892 8893 8894
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* XXX Should we validate that the redefined snapshot even
         * makes sense, such as checking whether the requested parent
         * snapshot exists and is not creating a loop, or that
         * qemu-img recognizes the snapshot name in at least one of
         * the domain's disks?  */
    } else if (!virDomainObjIsActive(vm)) {
E
Eric Blake 已提交
8895
        if (qemuDomainSnapshotCreateInactive(driver, vm, snap) < 0)
C
Chris Lalancette 已提交
8896
            goto cleanup;
E
Eric Blake 已提交
8897
    } else {
8898 8899
        if (qemuDomainSnapshotCreateActive(domain->conn, driver,
                                           &vm, snap) < 0)
8900
            goto cleanup;
C
Chris Lalancette 已提交
8901 8902
    }

8903
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
8904 8905 8906 8907 8908 8909
     * 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:
8910
    if (vm) {
8911
        if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
8912 8913 8914 8915
            if (qemuDomainSnapshotWriteMetadata(vm, snap,
                                                driver->snapshotDir) < 0)
                VIR_WARN("unable to save metadata for snapshot %s",
                         snap->def->name);
8916
            else if (update_current)
8917 8918
                vm->current_snapshot = snap;
        } else if (snap) {
8919
            virDomainSnapshotObjListRemove(&vm->snapshots, snap);
8920
        }
C
Chris Lalancette 已提交
8921
        virDomainObjUnlock(vm);
8922 8923
    }
    virDomainSnapshotDefFree(def);
C
Chris Lalancette 已提交
8924 8925 8926 8927 8928 8929
    qemuDriverUnlock(driver);
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
8930
                                       unsigned int flags)
C
Chris Lalancette 已提交
8931 8932 8933 8934 8935
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

8936 8937
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
8938

C
Chris Lalancette 已提交
8939 8940 8941 8942 8943 8944 8945 8946 8947 8948
    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;
    }

8949 8950
    n = virDomainSnapshotObjListGetNames(&vm->snapshots, names, nameslen,
                                         flags);
C
Chris Lalancette 已提交
8951 8952 8953 8954 8955 8956 8957 8958 8959

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

static int qemuDomainSnapshotNum(virDomainPtr domain,
8960
                                 unsigned int flags)
C
Chris Lalancette 已提交
8961 8962 8963 8964 8965
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

8966 8967
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
8968

C
Chris Lalancette 已提交
8969 8970 8971 8972 8973 8974 8975 8976 8977 8978
    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;
    }

8979 8980 8981 8982
    /* All qemu snapshots have libvirt metadata, so
     * VIR_DOMAIN_SNAPSHOT_LIST_METADATA makes no difference to our
     * answer.  */

8983
    n = virDomainSnapshotObjListNum(&vm->snapshots, flags);
C
Chris Lalancette 已提交
8984 8985 8986 8987 8988 8989 8990 8991 8992 8993

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

static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
8994
                                                           unsigned int flags)
C
Chris Lalancette 已提交
8995 8996 8997 8998 8999 9000
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

9001 9002
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029
    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,
9030
                                        unsigned int flags)
C
Chris Lalancette 已提交
9031 9032 9033 9034 9035
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

9036 9037
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057
    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;
}

static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
9058
                                                      unsigned int flags)
C
Chris Lalancette 已提交
9059 9060 9061 9062 9063
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

9064 9065
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090
    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;
}

9091 9092
static char *qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                                          unsigned int flags)
C
Chris Lalancette 已提交
9093 9094 9095 9096 9097 9098 9099
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

9100
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
9101

C
Chris Lalancette 已提交
9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118
    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;
    }

9119
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
9120 9121 9122 9123 9124 9125 9126 9127

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

9128 9129
/* The domain is expected to be locked and inactive. */
static int
E
Eric Blake 已提交
9130 9131
qemuDomainSnapshotRevertInactive(struct qemud_driver *driver,
                                 virDomainObjPtr vm,
9132 9133 9134
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
9135
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
9136 9137 9138
    return ret > 0 ? -1 : ret;
}

C
Chris Lalancette 已提交
9139
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
9140
                                      unsigned int flags)
C
Chris Lalancette 已提交
9141 9142 9143 9144 9145 9146 9147
{
    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;
9148
    virDomainEventPtr event2 = NULL;
9149
    int detail;
C
Chris Lalancette 已提交
9150 9151 9152
    qemuDomainObjPrivatePtr priv;
    int rc;

9153 9154
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED, -1);
9155

9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168
    /* 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
     * Also, several transitions occur even if we fail partway through.
     */

C
Chris Lalancette 已提交
9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185
    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;
    }

9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196
    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;
    }

9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207
    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?  */
    }

    snap->def->current = true;
C
Chris Lalancette 已提交
9208

9209
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
9210 9211 9212 9213
        goto cleanup;

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {
9214 9215 9216 9217 9218 9219 9220 9221 9222
        /* 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 已提交
9223
        if (virDomainObjIsActive(vm)) {
9224
            /* Transitions 5, 6, 8, 9 */
C
Chris Lalancette 已提交
9225
            priv = vm->privateData;
9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245
            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;
                }
            }
9246
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
9247 9248
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
9249 9250 9251
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
9252
                goto endjob;
9253
            }
E
Eric Blake 已提交
9254
        } else {
9255 9256
            /* Transitions 2, 3 */
            was_stopped = true;
9257
            rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
9258
                                  true, false, -1, NULL, snap,
9259
                                  VIR_VM_OP_CREATE);
9260
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
9261 9262 9263 9264
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
9265
            if (rc < 0)
9266
                goto endjob;
C
Chris Lalancette 已提交
9267 9268
        }

9269
        /* Touch up domain state.  */
9270 9271 9272
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292
            /* 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 已提交
9293
            if (rc < 0)
9294
                goto endjob;
9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309
            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 已提交
9310
        }
E
Eric Blake 已提交
9311
    } else {
9312
        /* Transitions 1, 4, 7 */
9313 9314 9315
        /* 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 已提交
9316 9317 9318
         */

        if (virDomainObjIsActive(vm)) {
9319
            /* Transitions 4, 7 */
J
Jiri Denemark 已提交
9320
            qemuProcessStop(driver, vm, 0, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT);
9321
            virDomainAuditStop(vm, "from-snapshot");
9322
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
C
Chris Lalancette 已提交
9323 9324
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
9325
                                             detail);
9326 9327
        }

E
Eric Blake 已提交
9328
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
9329
            if (!vm->persistent) {
9330
                if (qemuDomainObjEndJob(driver, vm) > 0)
9331 9332
                    virDomainRemoveInactive(&driver->domains, vm);
                vm = NULL;
9333
                goto cleanup;
9334
            }
9335
            goto endjob;
C
Chris Lalancette 已提交
9336
        }
9337

9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368
        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,
                                  paused, false, -1, NULL, NULL,
                                  VIR_VM_OP_CREATE);
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
                    if (qemuDomainObjEndJob(driver, vm) > 0)
                        virDomainRemoveInactive(&driver->domains, vm);
                    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 已提交
9369 9370 9371 9372
    }

    ret = 0;

9373
endjob:
9374
    if (vm && qemuDomainObjEndJob(driver, vm) == 0)
C
Chris Lalancette 已提交
9375 9376
        vm = NULL;

9377
cleanup:
9378 9379 9380 9381 9382 9383 9384 9385 9386
    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;
    }
9387
    if (event) {
C
Chris Lalancette 已提交
9388
        qemuDomainEventQueue(driver, event);
9389 9390 9391
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
9392 9393 9394 9395 9396 9397 9398
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    return ret;
}

9399 9400
struct snap_reparent {
    struct qemud_driver *driver;
9401
    const char *parent;
9402 9403 9404 9405 9406 9407
    virDomainObjPtr vm;
    int err;
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
9408
                                   const void *name ATTRIBUTE_UNUSED,
9409 9410 9411 9412 9413 9414 9415 9416 9417
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    struct snap_reparent *rep = data;

    if (rep->err < 0) {
        return;
    }

9418
    VIR_FREE(snap->def->parent);
9419

9420 9421
    if (rep->parent != NULL) {
        snap->def->parent = strdup(rep->parent);
9422

9423 9424 9425 9426
        if (snap->def->parent == NULL) {
            virReportOOMError();
            rep->err = -1;
            return;
9427 9428
        }
    }
9429 9430 9431

    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
                                               rep->driver->snapshotDir);
9432 9433
}

C
Chris Lalancette 已提交
9434 9435 9436 9437 9438 9439 9440 9441 9442
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];
    struct snap_remove rem;
9443
    struct snap_reparent rep;
9444
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
C
Chris Lalancette 已提交
9445

9446 9447
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
9448

C
Chris Lalancette 已提交
9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465
    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;
    }

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

C
Chris Lalancette 已提交
9469 9470 9471
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) {
        rem.driver = driver;
        rem.vm = vm;
9472
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
9473
        rem.err = 0;
9474
        rem.current = false;
9475 9476
        virDomainSnapshotForEachDescendant(&vm->snapshots,
                                           snap,
E
Eric Blake 已提交
9477
                                           qemuDomainSnapshotDiscardAll,
9478
                                           &rem);
C
Chris Lalancette 已提交
9479
        if (rem.err < 0)
9480
            goto endjob;
9481 9482
        if (rem.current)
            vm->current_snapshot = snap;
9483 9484
    } else {
        rep.driver = driver;
9485
        rep.parent = snap->def->parent;
9486 9487
        rep.vm = vm;
        rep.err = 0;
9488 9489 9490
        virDomainSnapshotForEachChild(&vm->snapshots, snap,
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
9491 9492
        if (rep.err < 0)
            goto endjob;
C
Chris Lalancette 已提交
9493 9494
    }

9495
    ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
C
Chris Lalancette 已提交
9496

9497
endjob:
9498
    if (qemuDomainObjEndJob(driver, vm) == 0)
9499 9500
        vm = NULL;

C
Chris Lalancette 已提交
9501 9502 9503 9504 9505 9506
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
9507

9508 9509 9510 9511 9512 9513 9514
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;
9515
    bool hmp;
9516

9517
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536

    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;

9537
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
9538

9539 9540
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

9541
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
9542
        goto cleanup;
9543
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9544
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
9545
    qemuDomainObjExitMonitorWithDriver(driver, vm);
9546
    if (qemuDomainObjEndJob(driver, vm) == 0) {
9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557
        vm = NULL;
        goto cleanup;
    }

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

9558

9559 9560 9561 9562 9563 9564 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 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613
static virDomainPtr qemuDomainAttach(virConnectPtr conn,
                                     unsigned int pid,
                                     unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
    char *pidfile;

    virCheckFlags(0, NULL);

    qemuDriverLock(driver);

    if (!(def = qemuParseCommandLinePid(driver->caps, pid,
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

    if (!monConfig) {
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("No monitor connection for pid %u"),
                        pid);
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Cannot connect to monitor connection of type '%s' for pid %u"),
                        virDomainChrTypeToString(monConfig->type), pid);
        goto cleanup;
    }

    if (!(def->name) &&
        virAsprintf(&def->name, "attach-pid-%u", pid) < 0) {
        virReportOOMError();
        goto cleanup;
    }

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

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

    if (qemuDomainAssignPCIAddresses(def) < 0)
        goto cleanup;

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, false)))
        goto cleanup;

    def = NULL;

9614
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628
        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:
9629
    if (qemuDomainObjEndJob(driver, vm) == 0) {
9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644
        vm = NULL;
        goto cleanup;
    }

cleanup:
    virDomainDefFree(def);
    virDomainChrSourceDefFree(monConfig);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    VIR_FREE(pidfile);
    return dom;
}


9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700
static int
qemuDomainOpenConsole(virDomainPtr dom,
                      const char *devname,
                      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;

    virCheckFlags(0, -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;
    }

    if (devname) {
        if (vm->def->console &&
            STREQ(devname, vm->def->console->info.alias))
            chr = vm->def->console;
        for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
            if (STREQ(devname, vm->def->serials[i]->info.alias))
                chr = vm->def->serials[i];
        }
        for (i = 0 ; !chr && i < vm->def->nparallels ; i++) {
            if (STREQ(devname, vm->def->parallels[i]->info.alias))
                chr = vm->def->parallels[i];
        }
    } else {
        if (vm->def->console)
            chr = vm->def->console;
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find character device %s"),
                        NULLSTR(devname));
        goto cleanup;
    }

9701
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
9702 9703 9704 9705 9706 9707
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("character device %s is not using a PTY"),
                        NULLSTR(devname));
        goto cleanup;
    }

9708
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
9709
                            0, 0, O_RDWR) < 0)
9710 9711 9712 9713 9714 9715 9716 9717 9718 9719
        goto cleanup;

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

9720 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 9773 9774 9775 9776 9777 9778 9779 9780 9781
static const char *
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path) {
    int i;
    char *ret = NULL;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];

        if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
            disk->type != VIR_DOMAIN_DISK_TYPE_FILE)
            continue;

        if (disk->src != NULL && STREQ(disk->src, path)) {
            if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0) {
                virReportOOMError();
                return NULL;
            }
            break;
        }
    }

    if (!ret) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("No device found for specified path"));
    }
    return ret;
}

static int
qemuDomainBlockJobImpl(virDomainPtr dom, const char *path,
                       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];
    const char *device = NULL;
    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;
    }

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

    device = qemuDiskPathToAlias(vm, path);
    if (!device) {
        goto cleanup;
    }

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;
9782
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
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 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825
    priv = vm->privateData;
    ret = qemuMonitorBlockJob(priv->mon, device, bandwidth, info, mode);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    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);
    return qemuDomainBlockJobImpl(dom, path, 0, NULL, BLOCK_JOB_ABORT);
}

static int
qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
                           virDomainBlockJobInfoPtr info, unsigned int flags)
{
    virCheckFlags(0, -1);
    return qemuDomainBlockJobImpl(dom, path, 0, info, BLOCK_JOB_INFO);
}

static int
qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
                           unsigned long bandwidth, unsigned int flags)
{
    virCheckFlags(0, -1);
    return qemuDomainBlockJobImpl(dom, path, bandwidth, NULL, BLOCK_JOB_SPEED);
}

static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
                    unsigned int flags)
{
9826 9827
    int ret;

9828
    virCheckFlags(0, -1);
9829 9830 9831 9832 9833
    ret = qemuDomainBlockJobImpl(dom, path, bandwidth, NULL, BLOCK_JOB_PULL);
    if (ret == 0 && bandwidth != 0)
        ret = qemuDomainBlockJobImpl(dom, path, bandwidth, NULL,
                                     BLOCK_JOB_SPEED);
    return ret;
9834
}
9835

9836
static virDriver qemuDriver = {
9837 9838
    .no = VIR_DRV_QEMU,
    .name = "QEMU",
9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856
    .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 */
9857 9858
    .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
    .domainReboot = qemuDomainReboot, /* 0.9.3 */
9859 9860
    .domainDestroy = qemuDomainDestroy, /* 0.2.0 */
    .domainDestroyFlags = qemuDomainDestroyFlags, /* 0.9.4 */
9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871
    .domainGetOSType = qemudDomainGetOSType, /* 0.2.2 */
    .domainGetMaxMemory = qemudDomainGetMaxMemory, /* 0.4.2 */
    .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 */
9872
    .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */
9873 9874
    .domainSave = qemuDomainSave, /* 0.2.0 */
    .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */
9875
    .domainRestore = qemuDomainRestore, /* 0.2.0 */
9876
    .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */
9877 9878
    .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */
    .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */
9879 9880
    .domainCoreDump = qemudDomainCoreDump, /* 0.7.0 */
    .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */
9881 9882
    .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */
    .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */
9883 9884
    .domainGetVcpusFlags = qemudDomainGetVcpusFlags, /* 0.8.5 */
    .domainPinVcpu = qemudDomainPinVcpu, /* 0.4.4 */
9885
    .domainPinVcpuFlags = qemudDomainPinVcpuFlags, /* 0.9.3 */
E
Eric Blake 已提交
9886
    .domainGetVcpuPinInfo = qemudDomainGetVcpuPinInfo, /* 0.9.3 */
9887 9888 9889 9890 9891 9892 9893 9894 9895
    .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 */
9896 9897
    .domainCreate = qemuDomainStart, /* 0.2.0 */
    .domainCreateWithFlags = qemuDomainStartWithFlags, /* 0.8.2 */
9898 9899
    .domainDefineXML = qemudDomainDefine, /* 0.2.0 */
    .domainUndefine = qemudDomainUndefine, /* 0.2.0 */
9900
    .domainUndefineFlags = qemuDomainUndefineFlags, /* 0.9.4 */
9901 9902 9903 9904 9905 9906 9907 9908 9909
    .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 */
9910
    .domainGetSchedulerParametersFlags = qemuGetSchedulerParametersFlags, /* 0.9.2 */
9911
    .domainSetSchedulerParameters = qemuSetSchedulerParameters, /* 0.7.0 */
9912
    .domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */
9913 9914 9915 9916 9917 9918 9919
    .domainMigratePerform = qemudDomainMigratePerform, /* 0.5.0 */
    .domainBlockStats = qemudDomainBlockStats, /* 0.4.1 */
    .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 */
9920
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
9921
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957
    .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 */
    .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 */
    .domainSnapshotLookupByName = qemuDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = qemuDomainHasCurrentSnapshot, /* 0.8.0 */
    .domainSnapshotCurrent = qemuDomainSnapshotCurrent, /* 0.8.0 */
    .domainRevertToSnapshot = qemuDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = qemuDomainSnapshotDelete, /* 0.8.0 */
    .qemuDomainMonitorCommand = qemuDomainMonitorCommand, /* 0.8.3 */
9958
    .qemuDomainAttach = qemuDomainAttach, /* 0.9.4 */
9959 9960
    .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */
    .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */
9961 9962 9963 9964 9965 9966
    .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 */
9967
    .domainSendKey = qemuDomainSendKey, /* 0.9.4 */
9968 9969 9970 9971
    .domainBlockJobAbort = qemuDomainBlockJobAbort, /* 0.9.4 */
    .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
    .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
    .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
9972 9973 9974
};


9975
static virStateDriver qemuStateDriver = {
9976
    .name = "QEMU",
9977 9978 9979 9980
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
9981
};
9982

9983
static void
9984
qemuVMDriverLock(void) {
9985 9986 9987 9988 9989
    qemuDriverLock(qemu_driver);
};


static void
9990
qemuVMDriverUnlock(void) {
9991 9992 9993 9994
    qemuDriverUnlock(qemu_driver);
};


9995 9996 9997 9998 9999 10000 10001 10002 10003
static int
qemuVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
                    virHashIterator iter, void *data)
{
    virHashForEach(qemu_driver->domains.objs, iter, data);

    return 0;
}

S
Stefan Berger 已提交
10004 10005
static virNWFilterCallbackDriver qemuCallbackDriver = {
    .name = "QEMU",
10006 10007 10008
    .vmFilterRebuild = qemuVMFilterRebuild,
    .vmDriverLock = qemuVMDriverLock,
    .vmDriverUnlock = qemuVMDriverUnlock,
S
Stefan Berger 已提交
10009 10010
};

10011
int qemuRegister(void) {
10012 10013
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
S
Stefan Berger 已提交
10014
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
10015 10016
    return 0;
}