qemu_driver.c 208.3 KB
Newer Older
D
Daniel P. Berrange 已提交
1 2 3
/*
 * driver.c: core driver methods for managing qemu guests
 *
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>
D
Daniel P. Berrange 已提交
46

47

48 49
#include "qemu_driver.h"
#include "qemu_conf.h"
50
#include "qemu_capabilities.h"
51
#include "qemu_command.h"
52
#include "qemu_cgroup.h"
53
#include "qemu_hostdev.h"
54
#include "qemu_hotplug.h"
55
#include "qemu_monitor.h"
56
#include "qemu_bridge_filter.h"
57
#include "qemu_audit.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 "event.h"
65
#include "buf.h"
66
#include "util.h"
67
#include "nodeinfo.h"
68
#include "stats_linux.h"
69
#include "capabilities.h"
70
#include "memory.h"
71
#include "uuid.h"
72
#include "domain_conf.h"
73 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"
85
#include "files.h"
86
#include "fdstream.h"
87
#include "configmake.h"
H
Hu Tao 已提交
88
#include "threadpool.h"
89

90 91
#define VIR_FROM_THIS VIR_FROM_QEMU

92 93
#define QEMU_NB_MEM_PARAM  3

94 95 96
#if HAVE_LINUX_KVM_H
# include <linux/kvm.h>
#endif
97

98 99
/* device for kvm ioctls */
#define KVM_DEVICE "/dev/kvm"
100

101 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


#define timeval_to_ms(tv)       (((tv).tv_sec * 1000ull) + ((tv).tv_usec / 1000))
H
Hu Tao 已提交
114 115 116

static void processWatchdogEvent(void *data, void *opaque);

117 118
static int qemudShutdown(void);

J
Jiri Denemark 已提交
119 120
static int qemudDomainObjStart(virConnectPtr conn,
                               struct qemud_driver *driver,
121 122
                               virDomainObjPtr vm,
                               bool start_paused);
J
Jiri Denemark 已提交
123

124
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
125

126
struct qemud_driver *qemu_driver = NULL;
127 128


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

134
static void
135
qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
136 137 138
{
    virDomainObjPtr vm = payload;
    struct qemuAutostartData *data = opaque;
139
    virErrorPtr err;
140 141

    virDomainObjLock(vm);
142 143 144 145 146 147 148 149 150
    virResetLastError();
    if (qemuDomainObjBeginJobWithDriver(data->driver, vm) < 0) {
        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) &&
151
            qemudDomainObjStart(data->conn, data->driver, vm, false) < 0) {
152
            err = virGetLastError();
153
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
154
                      vm->def->name,
155
                      err ? err->message : _("unknown error"));
156
        }
157 158 159

        if (qemuDomainObjEndJob(vm) == 0)
            vm = NULL;
160
    }
161 162 163

    if (vm)
        virDomainObjUnlock(vm);
164 165
}

166

167
static void
168 169
qemuAutostartDomains(struct qemud_driver *driver)
{
170 171 172 173 174
    /* 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
     */
175 176 177
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
178
    /* Ignoring NULL conn which is mostly harmless here */
179
    struct qemuAutostartData data = { driver, conn };
180

181
    qemuDriverLock(driver);
182
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
183
    qemuDriverUnlock(driver);
184

185 186
    if (conn)
        virConnectClose(conn);
187 188
}

189
static int
190
qemuSecurityInit(struct qemud_driver *driver)
191
{
192 193 194 195
    virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName,
                                                      driver->allowDiskFormatProbing);
    if (!mgr)
        goto error;
D
Daniel Veillard 已提交
196

197 198 199 200 201 202 203
    if (driver->privileged) {
        virSecurityManagerPtr dac = virSecurityManagerNewDAC(driver->user,
                                                             driver->group,
                                                             driver->allowDiskFormatProbing,
                                                             driver->dynamicOwnership);
        if (!dac)
            goto error;
204

205
        if (!(driver->securityManager = virSecurityManagerNewStack(mgr,
E
Eric Blake 已提交
206 207 208
                                                                   dac))) {

            virSecurityManagerFree(dac);
209
            goto error;
E
Eric Blake 已提交
210
        }
211 212 213
    } else {
        driver->securityManager = mgr;
    }
D
Daniel Veillard 已提交
214

215
    return 0;
216

217 218 219 220 221
error:
    VIR_ERROR0(_("Failed to initialize security drivers"));
    virSecurityManagerFree(mgr);
    return -1;
}
222

223

224 225 226 227 228
static virCapsPtr
qemuCreateCapabilities(virCapsPtr oldcaps,
                       struct qemud_driver *driver)
{
    virCapsPtr caps;
229

230 231 232 233
    /* Basic host arch / guest machine capabilities */
    if (!(caps = qemuCapsInit(oldcaps))) {
        virReportOOMError();
        return NULL;
234 235
    }

236 237 238 239 240 241
    if (driver->allowDiskFormatProbing) {
        caps->defaultDiskDriverName = NULL;
        caps->defaultDiskDriverType = NULL;
    } else {
        caps->defaultDiskDriverName = "qemu";
        caps->defaultDiskDriverType = "raw";
242 243
    }

244 245
    qemuDomainSetPrivateDataHooks(caps);
    qemuDomainSetNamespaceHooks(caps);
246

247 248 249 250
    if (virGetHostUUID(caps->host.host_uuid)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot get the host uuid"));
        goto err_exit;
251
    }
252

253 254
    /* Security driver data */
    const char *doi, *model;
255

256 257 258 259 260 261 262
    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;
263
    }
264

265 266
    VIR_DEBUG("Initialized caps for security driver \"%s\" with "
              "DOI \"%s\"", model, doi);
267

268
    return caps;
269

270 271 272 273
no_memory:
    virReportOOMError();
err_exit:
    virCapabilitiesFree(caps);
274 275 276
    return NULL;
}

277
static void qemuDomainSnapshotLoad(void *payload,
278
                                   const void *name ATTRIBUTE_UNUSED,
279
                                   void *data)
280
{
281 282 283 284 285 286 287 288 289 290
    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;
    char ebuf[1024];
291

292 293 294 295
    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);
296
        goto cleanup;
297 298
    }

299 300
    VIR_INFO("Scanning for snapshots for domain %s in %s", vm->def->name,
             snapDir);
301

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

310 311 312
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.')
            continue;
313

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

318 319 320 321
        if (virAsprintf(&fullpath, "%s/%s", snapDir, entry->d_name) < 0) {
            VIR_ERROR0(_("Failed to allocate memory for path"));
            continue;
        }
322

323 324 325 326 327 328 329 330
        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;
        }
331

332 333 334 335 336 337 338 339
        def = virDomainSnapshotDefParseString(xmlStr, 0);
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"), fullpath);
            VIR_FREE(fullpath);
            VIR_FREE(xmlStr);
            continue;
        }
340

341
        virDomainSnapshotAssignDef(&vm->snapshots, def);
342

343 344
        VIR_FREE(fullpath);
        VIR_FREE(xmlStr);
345 346
    }

347 348 349 350 351 352 353 354
    /* 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.
     */
355

356
    virResetLastError();
357

358 359 360 361
cleanup:
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
362 363 364
    virDomainObjUnlock(vm);
}

365 366 367 368 369
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
370
static int
371 372 373 374 375
qemudStartup(int privileged) {
    char *base = NULL;
    char *driverConf = NULL;
    int rc;
    virConnectPtr conn = NULL;
376

377 378
    if (VIR_ALLOC(qemu_driver) < 0)
        return -1;
379

380 381 382 383
    if (virMutexInit(&qemu_driver->lock) < 0) {
        VIR_ERROR0(_("cannot initialize mutex"));
        VIR_FREE(qemu_driver);
        return -1;
384
    }
385 386
    qemuDriverLock(qemu_driver);
    qemu_driver->privileged = privileged;
387

388 389
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;
390

391 392
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;
393

394 395 396 397 398
    /* Init callback list */
    if (VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
        goto out_of_memory;
    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
        goto out_of_memory;
399

400 401 402
    if ((qemu_driver->domainEventTimer =
         virEventAddTimeout(-1, qemuDomainEventFlush, qemu_driver, NULL)) < 0)
        goto error;
403

404 405 406 407
    /* Allocate bitmap for vnc port reservation */
    if ((qemu_driver->reservedVNCPorts =
         virBitmapAlloc(QEMU_VNC_PORT_MAX - QEMU_VNC_PORT_MIN)) == NULL)
        goto out_of_memory;
408

409 410 411
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();
412

413 414 415 416
    if (privileged) {
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
417

418 419
        if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL)
            goto out_of_memory;
420

421 422 423
        if (virAsprintf(&qemu_driver->stateDir,
                      "%s/run/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
424

425 426 427
        if (virAsprintf(&qemu_driver->libDir,
                      "%s/lib/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
428

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
        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;
446

447 448 449 450 451
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
            goto out_of_memory;
        }
452

453 454 455 456 457
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
            goto out_of_memory;
        }
        VIR_FREE(userdir);
458

459 460 461 462 463 464 465 466 467 468 469 470
        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;
471
    }
H
Hu Tao 已提交
472

473 474 475 476 477
    if (virFileMakePath(qemu_driver->stateDir) != 0) {
        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 已提交
478
    }
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
    if (virFileMakePath(qemu_driver->libDir) != 0) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
    if (virFileMakePath(qemu_driver->cacheDir) != 0) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
    if (virFileMakePath(qemu_driver->saveDir) != 0) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
                  qemu_driver->saveDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
    if (virFileMakePath(qemu_driver->snapshotDir) != 0) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
                  qemu_driver->snapshotDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
    if (virFileMakePath(qemu_driver->autoDumpPath) != 0) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
                  qemu_driver->autoDumpPath, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
508 509
    }

510 511 512 513 514 515 516
    /* 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;
517

518
    VIR_FREE(base);
519

520 521 522 523 524
    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)));
525 526
    }

527 528 529 530
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
        goto error;
    }
    VIR_FREE(driverConf);
531

532 533
    if (qemuSecurityInit(qemu_driver) < 0)
        goto error;
534

535 536 537
    if ((qemu_driver->caps = qemuCreateCapabilities(NULL,
                                                    qemu_driver)) == NULL)
        goto error;
538

539
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
540
        goto error;
541

542 543 544 545 546 547
    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;
548
        }
549
        if (chown(qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group) < 0) {
550
            virReportSystemError(errno,
551 552 553
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
554
        }
555 556 557 558 559 560 561 562 563 564 565
        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;
566
        }
567
    }
568

569 570 571 572 573 574
    /* 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
575
     */
576 577 578 579 580
    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;
581

582 583 584 585 586
        if ((rc = virFileMakePath(mempath)) != 0) {
            virReportSystemError(rc,
                                 _("unable to create hugepage path %s"), mempath);
            VIR_FREE(mempath);
            goto error;
587
        }
588 589 590 591 592 593 594
        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 已提交
595
        }
E
Eric Blake 已提交
596

597
        qemu_driver->hugepage_path = mempath;
598
    }
599

600 601 602 603 604 605 606
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
                                1, NULL, NULL) < 0)
        goto error;
607

608 609 610
    conn = virConnectOpen(qemu_driver->privileged ?
                          "qemu:///system" :
                          "qemu:///session");
611

612
    qemuProcessReconnectAll(conn, qemu_driver);
613

614 615 616 617 618 619 620
    /* Then inactive persistent configs */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->configDir,
                                qemu_driver->autostartDir,
                                0, NULL, NULL) < 0)
        goto error;
621

622

623 624
    virHashForEach(qemu_driver->domains.objs, qemuDomainSnapshotLoad,
                   qemu_driver->snapshotDir);
625

626
    qemuDriverUnlock(qemu_driver);
627

628
    qemuAutostartDomains(qemu_driver);
629

630 631 632
    qemu_driver->workerPool = virThreadPoolNew(0, 1, processWatchdogEvent, qemu_driver);
    if (!qemu_driver->workerPool)
        goto error;
633

634 635
    if (conn)
        virConnectClose(conn);
636

637
    return 0;
638

639 640 641 642 643 644 645 646 647 648
out_of_memory:
    virReportOOMError();
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
    if (conn)
        virConnectClose(conn);
    VIR_FREE(base);
    VIR_FREE(driverConf);
    qemudShutdown();
649
    return -1;
650 651
}

652 653 654
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;
655

656 657 658 659 660 661 662
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
E
Eric Blake 已提交
663
    }
664
}
E
Eric Blake 已提交
665

666 667 668 669 670 671 672 673 674 675
/**
 * 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;
676

677 678 679 680 681 682 683
    qemuDriverLock(qemu_driver);
    virDomainLoadAllConfigs(qemu_driver->caps,
                            &qemu_driver->domains,
                            qemu_driver->configDir,
                            qemu_driver->autostartDir,
                            0, qemudNotifyLoadDomain, qemu_driver);
    qemuDriverUnlock(qemu_driver);
684

685
    qemuAutostartDomains(qemu_driver);
686

687 688
    return 0;
}
S
Stefan Berger 已提交
689

690 691 692 693 694 695 696 697 698 699 700
/**
 * 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;
701

702 703
    if (!qemu_driver)
        return 0;
704

705 706 707 708 709 710
    /* 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;
}
711

712 713 714 715 716 717 718 719
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
    int i;
720

721 722
    if (!qemu_driver)
        return -1;
723

724 725 726
    qemuDriverLock(qemu_driver);
    pciDeviceListFree(qemu_driver->activePciHostdevs);
    virCapabilitiesFree(qemu_driver->caps);
727

728 729
    virDomainObjListDeinit(&qemu_driver->domains);
    virBitmapFree(qemu_driver->reservedVNCPorts);
730

731
    virSysinfoDefFree(qemu_driver->hostsysinfo);
732

733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
    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);
    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);
753

754
    virSecurityManagerFree(qemu_driver->securityManager);
755

756
    ebtablesContextFree(qemu_driver->ebtables);
757

758 759 760 761
    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 已提交
762 763
    }

764 765 766
    /* Free domain callback list */
    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
    virDomainEventQueueFree(qemu_driver->domainEventQueue);
767

768 769
    if (qemu_driver->domainEventTimer != -1)
        virEventRemoveTimeout(qemu_driver->domainEventTimer);
D
Daniel P. Berrange 已提交
770

771 772
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);
773

774
    virCgroupFree(&qemu_driver->cgroup);
775

776 777 778 779
    qemuDriverUnlock(qemu_driver);
    virMutexDestroy(&qemu_driver->lock);
    virThreadPoolFree(qemu_driver->workerPool);
    VIR_FREE(qemu_driver);
780

781
    return 0;
782 783
}

784 785 786 787 788 789 790

static int qemuDomainSnapshotSetCurrentActive(virDomainObjPtr vm,
                                              char *snapshotDir);
static int qemuDomainSnapshotSetCurrentInactive(virDomainObjPtr vm,
                                                char *snapshotDir);


791
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
792
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
793
                                  int flags ATTRIBUTE_UNUSED) {
794
    if (conn->uri == NULL) {
795 796 797
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

798
        conn->uri = xmlParseURI(qemu_driver->privileged ?
799 800
                                "qemu:///system" :
                                "qemu:///session");
801
        if (!conn->uri) {
802
            virReportOOMError();
803 804
            return VIR_DRV_OPEN_ERROR;
        }
805 806 807 808 809 810 811 812 813 814
    } 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;

815
        if (qemu_driver == NULL) {
816 817
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("qemu state driver is not active"));
818 819 820
            return VIR_DRV_OPEN_ERROR;
        }

821
        if (conn->uri->path == NULL) {
822 823 824 825 826
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no QEMU URI path given, try %s"),
                            qemu_driver->privileged
                            ? "qemu:///system"
                            : "qemu:///session");
827 828 829
                return VIR_DRV_OPEN_ERROR;
        }

830
        if (qemu_driver->privileged) {
831 832
            if (STRNEQ (conn->uri->path, "/system") &&
                STRNEQ (conn->uri->path, "/session")) {
833 834 835
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///system"),
                                conn->uri->path);
836 837 838 839
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
840 841 842
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///session"),
                                conn->uri->path);
843 844 845
                return VIR_DRV_OPEN_ERROR;
            }
        }
846 847 848 849 850 851 852
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
853
    struct qemud_driver *driver = conn->privateData;
854 855

    /* Get rid of callbacks registered for this conn */
856
    qemuDriverLock(driver);
857
    virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
858
    qemuDriverUnlock(driver);
859 860 861 862 863 864

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
865 866 867 868 869
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
870 871 872 873 874
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
875 876 877
    }
}

878
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
879
    return "QEMU";
880 881
}

882

883 884 885 886 887 888 889 890 891 892 893 894 895
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;
}


896 897 898 899
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
900

901 902
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
903
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
904
        return -1;
905 906 907 908 909 910
    }

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

911
    VIR_FORCE_CLOSE(fd);
912 913 914 915
    return maxvcpus;
}


E
Eric Blake 已提交
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
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, "");
}

932
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
933 934 935
    if (!type)
        return 16;

936
    if (STRCASEEQ(type, "qemu"))
937 938
        return 16;

939
    if (STRCASEEQ(type, "kvm"))
940
        return kvmGetMaxVCPUs();
941

942
    if (STRCASEEQ(type, "kqemu"))
943
        return 1;
944

945 946
    qemuReportError(VIR_ERR_INVALID_ARG,
                    _("unknown type '%s'"), type);
947 948 949
    return -1;
}

950

951
static char *qemudGetCapabilities(virConnectPtr conn) {
952
    struct qemud_driver *driver = conn->privateData;
953
    virCapsPtr caps = NULL;
954
    char *xml = NULL;
955

956
    qemuDriverLock(driver);
957

958
    if ((caps = qemuCreateCapabilities(qemu_driver->caps,
959
                                       qemu_driver)) == NULL) {
960 961 962
        virCapabilitiesFree(caps);
        goto cleanup;
    }
963

964
    virCapabilitiesFree(qemu_driver->caps);
965 966 967
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
968
        virReportOOMError();
969 970

cleanup:
971
    qemuDriverUnlock(driver);
972

973
    return xml;
974 975 976
}


977 978 979 980 981
static int
qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid,
                    int tid)
{
    char *proc;
D
Daniel P. Berrange 已提交
982
    FILE *pidinfo;
983
    unsigned long long usertime, systime;
984 985
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
986

987
    if (tid)
988
        ret = virAsprintf(&proc, "/proc/%d/task/%d/stat", pid, tid);
989
    else
990 991
        ret = virAsprintf(&proc, "/proc/%d/stat", pid);
    if (ret < 0)
D
Daniel P. Berrange 已提交
992 993 994 995
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
996 997 998 999
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
1000
        VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1001 1002
        return 0;
    }
1003
    VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1004

1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
    /* 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) {
1015
        VIR_FORCE_FCLOSE(pidinfo);
1016 1017
        VIR_WARN0("cannot parse process status data");
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
1018 1019 1020 1021 1022 1023 1024 1025
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
1026 1027 1028 1029 1030
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

D
Daniel P. Berrange 已提交
1031

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

1035
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
1036 1037 1038 1039 1040

    return 0;
}


1041
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
1042
                                          int id) {
1043 1044 1045 1046
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1047
    qemuDriverLock(driver);
1048
    vm  = virDomainFindByID(&driver->domains, id);
1049
    qemuDriverUnlock(driver);
1050 1051

    if (!vm) {
1052 1053
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching id %d"), id);
1054
        goto cleanup;
1055 1056
    }

1057
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1058
    if (dom) dom->id = vm->def->id;
1059 1060

cleanup:
1061 1062
    if (vm)
        virDomainObjUnlock(vm);
1063 1064
    return dom;
}
1065

1066
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
1067
                                            const unsigned char *uuid) {
1068 1069 1070
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1071

1072
    qemuDriverLock(driver);
1073
    vm = virDomainFindByUUID(&driver->domains, uuid);
1074 1075
    qemuDriverUnlock(driver);

1076
    if (!vm) {
1077 1078
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
1079 1080
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1081
        goto cleanup;
1082 1083
    }

1084
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1085
    if (dom) dom->id = vm->def->id;
1086 1087

cleanup:
1088 1089
    if (vm)
        virDomainObjUnlock(vm);
1090 1091
    return dom;
}
1092

1093
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
1094
                                            const char *name) {
1095 1096 1097
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1098

1099
    qemuDriverLock(driver);
1100
    vm = virDomainFindByName(&driver->domains, name);
1101 1102
    qemuDriverUnlock(driver);

1103
    if (!vm) {
1104 1105
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), name);
1106
        goto cleanup;
1107 1108
    }

1109
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1110
    if (dom) dom->id = vm->def->id;
1111 1112

cleanup:
1113 1114
    if (vm)
        virDomainObjUnlock(vm);
1115 1116 1117
    return dom;
}

1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128

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 已提交
1129 1130 1131 1132
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
        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 已提交
1153 1154 1155 1156
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
        goto cleanup;
    }
    ret = obj->persistent;

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

1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
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 已提交
1177 1178 1179 1180
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1181 1182 1183 1184 1185 1186 1187 1188 1189
        goto cleanup;
    }
    ret = obj->updated;

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

1191
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
1192 1193 1194
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

1195
    qemuDriverLock(driver);
1196
    if (qemuCapsExtractVersion(driver->caps, &driver->qemuVersion) < 0)
1197
        goto cleanup;
1198

1199
    *version = driver->qemuVersion;
1200 1201 1202
    ret = 0;

cleanup:
1203
    qemuDriverUnlock(driver);
1204
    return ret;
D
Daniel P. Berrange 已提交
1205 1206
}

1207
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
1208
    struct qemud_driver *driver = conn->privateData;
1209
    int n;
1210

1211
    qemuDriverLock(driver);
1212
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1213
    qemuDriverUnlock(driver);
1214

1215
    return n;
D
Daniel P. Berrange 已提交
1216
}
1217

1218
static int qemudNumDomains(virConnectPtr conn) {
1219
    struct qemud_driver *driver = conn->privateData;
1220
    int n;
1221

1222
    qemuDriverLock(driver);
1223
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1224
    qemuDriverUnlock(driver);
1225

1226
    return n;
D
Daniel P. Berrange 已提交
1227
}
1228

1229
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
1230
                                      unsigned int flags) {
1231
    struct qemud_driver *driver = conn->privateData;
1232
    virDomainDefPtr def;
1233
    virDomainObjPtr vm = NULL;
1234
    virDomainPtr dom = NULL;
1235
    virDomainEventPtr event = NULL;
D
Daniel P. Berrange 已提交
1236

1237
    virCheckFlags(VIR_DOMAIN_START_PAUSED, NULL);
1238

1239
    qemuDriverLock(driver);
1240
    if (!(def = virDomainDefParseString(driver->caps, xml,
1241
                                        VIR_DOMAIN_XML_INACTIVE)))
1242
        goto cleanup;
1243

1244
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1245 1246
        goto cleanup;

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

1250 1251 1252
    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

1253
    if (qemuDomainAssignPCIAddresses(def) < 0)
1254 1255
        goto cleanup;

1256
    if (!(vm = virDomainAssignDef(driver->caps,
1257
                                  &driver->domains,
1258
                                  def, false)))
1259 1260 1261
        goto cleanup;

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

1263 1264 1265
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup; /* XXXX free the 'vm' we created ? */

1266 1267 1268
    if (qemuProcessStart(conn, driver, vm, NULL,
                         (flags & VIR_DOMAIN_START_PAUSED) != 0,
                         -1, NULL, VIR_VM_OP_CREATE) < 0) {
1269
        qemuDomainStartAudit(vm, "booted", false);
1270 1271 1272
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
1273
        vm = NULL;
1274
        goto cleanup;
D
Daniel P. Berrange 已提交
1275
    }
1276 1277 1278 1279

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1280
    qemuDomainStartAudit(vm, "booted", true);
D
Daniel P. Berrange 已提交
1281

1282
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1283
    if (dom) dom->id = vm->def->id;
1284

1285 1286 1287
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
1288

1289 1290
cleanup:
    virDomainDefFree(def);
1291 1292
    if (vm)
        virDomainObjUnlock(vm);
1293 1294
    if (event)
        qemuDomainEventQueue(driver, event);
1295
    qemuDriverUnlock(driver);
1296
    return dom;
D
Daniel P. Berrange 已提交
1297 1298 1299
}


1300
static int qemudDomainSuspend(virDomainPtr dom) {
1301 1302 1303
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1304
    virDomainEventPtr event = NULL;
1305
    qemuDomainObjPrivatePtr priv;
1306

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

D
Daniel P. Berrange 已提交
1310
    if (!vm) {
1311 1312
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1313 1314
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1315
        goto cleanup;
D
Daniel P. Berrange 已提交
1316
    }
D
Daniel P. Berrange 已提交
1317
    if (!virDomainObjIsActive(vm)) {
1318 1319
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1320
        goto cleanup;
D
Daniel P. Berrange 已提交
1321
    }
1322 1323 1324

    priv = vm->privateData;

1325
    if (priv->jobActive == QEMU_JOB_MIGRATION_OUT) {
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339
        if (vm->state != VIR_DOMAIN_PAUSED) {
            VIR_DEBUG("Requesting domain pause on %s",
                      vm->def->name);
            priv->jobSignals |= QEMU_JOB_SIGNAL_SUSPEND;
        }
        ret = 0;
        goto cleanup;
    } else {
        if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
            goto cleanup;

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
1340
            goto endjob;
1341
        }
1342
        if (vm->state != VIR_DOMAIN_PAUSED) {
1343
            if (qemuProcessStopCPUs(driver, vm) < 0) {
1344
                goto endjob;
1345
            }
1346 1347 1348 1349 1350 1351 1352
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
        }
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            goto endjob;
        ret = 0;
D
Daniel P. Berrange 已提交
1353
    }
1354

1355
endjob:
1356 1357
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
1358

1359
cleanup:
1360 1361
    if (vm)
        virDomainObjUnlock(vm);
1362

1363
    if (event)
1364
        qemuDomainEventQueue(driver, event);
1365
    qemuDriverUnlock(driver);
1366
    return ret;
D
Daniel P. Berrange 已提交
1367 1368 1369
}


1370
static int qemudDomainResume(virDomainPtr dom) {
1371 1372 1373
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1374
    virDomainEventPtr event = NULL;
1375

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

D
Daniel P. Berrange 已提交
1379
    if (!vm) {
1380 1381
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1382 1383
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1384
        goto cleanup;
D
Daniel P. Berrange 已提交
1385
    }
1386 1387 1388 1389

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

D
Daniel P. Berrange 已提交
1390
    if (!virDomainObjIsActive(vm)) {
1391 1392
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1393
        goto endjob;
D
Daniel P. Berrange 已提交
1394
    }
1395
    if (vm->state == VIR_DOMAIN_PAUSED) {
1396
        if (qemuProcessStartCPUs(driver, vm, dom->conn) < 0) {
1397
            if (virGetLastError() == NULL)
1398 1399
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resume operation failed"));
1400
            goto endjob;
1401
        }
1402 1403 1404
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
1405
    }
1406
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
1407
        goto endjob;
1408 1409
    ret = 0;

1410
endjob:
1411 1412
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
1413

1414
cleanup:
1415 1416
    if (vm)
        virDomainObjUnlock(vm);
1417
    if (event)
1418
        qemuDomainEventQueue(driver, event);
1419
    qemuDriverUnlock(driver);
1420
    return ret;
D
Daniel P. Berrange 已提交
1421 1422 1423
}


1424
static int qemudDomainShutdown(virDomainPtr dom) {
1425 1426 1427
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1428

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

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

1441 1442 1443
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
1444
    if (!virDomainObjIsActive(vm)) {
1445 1446
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1447
        goto endjob;
1448 1449
    }

1450
    qemuDomainObjPrivatePtr priv = vm->privateData;
1451 1452 1453
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorSystemPowerdown(priv->mon);
    qemuDomainObjExitMonitor(vm);
1454

1455
endjob:
1456 1457
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
1458

1459
cleanup:
1460 1461
    if (vm)
        virDomainObjUnlock(vm);
1462
    return ret;
1463 1464 1465
}


1466
static int qemudDomainDestroy(virDomainPtr dom) {
1467 1468 1469
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1470
    virDomainEventPtr event = NULL;
1471

1472
    qemuDriverLock(driver);
1473
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
1474
    if (!vm) {
1475 1476
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1477 1478
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1479
        goto cleanup;
D
Daniel P. Berrange 已提交
1480
    }
1481 1482 1483 1484

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

D
Daniel P. Berrange 已提交
1485
    if (!virDomainObjIsActive(vm)) {
1486 1487
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
1488
        goto endjob;
1489
    }
1490

1491
    qemuProcessStop(driver, vm, 0);
1492 1493 1494
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1495 1496
    qemuDomainStopAudit(vm, "destroyed");

1497
    if (!vm->persistent) {
1498 1499 1500
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
1501 1502
        vm = NULL;
    }
1503 1504
    ret = 0;

1505
endjob:
1506 1507 1508
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
1509

1510
cleanup:
1511 1512
    if (vm)
        virDomainObjUnlock(vm);
1513 1514
    if (event)
        qemuDomainEventQueue(driver, event);
1515
    qemuDriverUnlock(driver);
1516
    return ret;
D
Daniel P. Berrange 已提交
1517 1518 1519
}


1520
static char *qemudDomainGetOSType(virDomainPtr dom) {
1521 1522 1523
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
1524

1525
    qemuDriverLock(driver);
1526
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1527
    qemuDriverUnlock(driver);
1528
    if (!vm) {
1529 1530
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1531 1532
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1533
        goto cleanup;
1534 1535
    }

1536
    if (!(type = strdup(vm->def->os.type)))
1537
        virReportOOMError();
1538 1539

cleanup:
1540 1541
    if (vm)
        virDomainObjUnlock(vm);
1542 1543 1544
    return type;
}

1545 1546
/* Returns max memory in kb, 0 if error */
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
1547 1548 1549
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
1550

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

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

1563
    ret = vm->def->mem.max_balloon;
1564 1565

cleanup:
1566 1567
    if (vm)
        virDomainObjUnlock(vm);
1568
    return ret;
1569 1570 1571
}

static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
1572
    struct qemud_driver *driver = dom->conn->privateData;
1573
    qemuDomainObjPrivatePtr priv;
1574
    virDomainObjPtr vm;
1575
    int ret = -1, r;
1576

1577
    qemuDriverLock(driver);
1578
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1579
    qemuDriverUnlock(driver);
1580
    if (!vm) {
1581 1582
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1583 1584
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1585
        goto cleanup;
1586 1587
    }

1588
    if (newmem > vm->def->mem.max_balloon) {
1589 1590
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("cannot set memory higher than max memory"));
1591
        goto cleanup;
1592 1593
    }

1594 1595 1596
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

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

1603 1604 1605 1606
    priv = vm->privateData;
    qemuDomainObjEnterMonitor(vm);
    r = qemuMonitorSetBalloon(priv->mon, newmem);
    qemuDomainObjExitMonitor(vm);
1607 1608
    qemuDomainMemoryAudit(vm, vm->def->mem.cur_balloon, newmem, "update",
                          r == 1);
1609 1610
    if (r < 0)
        goto endjob;
1611

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

1619
    ret = 0;
1620
endjob:
1621 1622
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
1623

1624
cleanup:
1625 1626
    if (vm)
        virDomainObjUnlock(vm);
1627
    return ret;
1628 1629
}

1630
static int qemudDomainGetInfo(virDomainPtr dom,
1631
                              virDomainInfoPtr info) {
1632 1633 1634
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1635 1636
    int err;
    unsigned long balloon;
1637

1638
    qemuDriverLock(driver);
1639
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1640
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
1641
    if (!vm) {
1642 1643
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1644 1645
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
1646
        goto cleanup;
D
Daniel P. Berrange 已提交
1647 1648
    }

1649
    info->state = vm->state;
D
Daniel P. Berrange 已提交
1650

D
Daniel P. Berrange 已提交
1651
    if (!virDomainObjIsActive(vm)) {
1652
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
1653
    } else {
1654
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
E
Eric Blake 已提交
1655 1656
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("cannot read cputime for domain"));
1657
            goto cleanup;
D
Daniel P. Berrange 已提交
1658 1659 1660
        }
    }

1661
    info->maxMem = vm->def->mem.max_balloon;
1662

D
Daniel P. Berrange 已提交
1663
    if (virDomainObjIsActive(vm)) {
1664
        qemuDomainObjPrivatePtr priv = vm->privateData;
1665 1666 1667

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
1668
            info->memory = vm->def->mem.max_balloon;
1669
        } else if (!priv->jobActive) {
1670 1671
            if (qemuDomainObjBeginJob(vm) < 0)
                goto cleanup;
1672 1673 1674 1675 1676 1677 1678 1679 1680
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
                qemuDomainObjEnterMonitor(vm);
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
                qemuDomainObjExitMonitor(vm);
            }
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
1681 1682 1683
                goto cleanup;
            }

1684 1685
            if (err < 0)
                goto cleanup;
1686 1687
            if (err == 0)
                /* Balloon not supported, so maxmem is always the allocation */
1688
                info->memory = vm->def->mem.max_balloon;
1689 1690 1691
            else
                info->memory = balloon;
        } else {
1692
            info->memory = vm->def->mem.cur_balloon;
1693
        }
1694
    } else {
1695
        info->memory = vm->def->mem.cur_balloon;
1696 1697
    }

1698
    info->nrVirtCpu = vm->def->vcpus;
1699 1700 1701
    ret = 0;

cleanup:
1702 1703
    if (vm)
        virDomainObjUnlock(vm);
1704
    return ret;
D
Daniel P. Berrange 已提交
1705 1706 1707
}


1708
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
1709 1710 1711
#define QEMUD_SAVE_VERSION 2

enum qemud_save_formats {
1712 1713 1714
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
1715 1716
    /*
     * Deprecated by xz and never used as part of a release
1717
     * QEMUD_SAVE_FORMAT_LZMA
1718 1719
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
1720
    QEMUD_SAVE_FORMAT_LZOP = 4,
1721 1722 1723
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
1724 1725

    QEMUD_SAVE_FORMAT_LAST
1726
};
1727

1728 1729 1730 1731 1732
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
1733 1734
              "xz",
              "lzop")
1735

1736 1737 1738 1739 1740
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
    int version;
    int xml_len;
    int was_running;
1741 1742
    int compressed;
    int unused[15];
1743 1744
};

1745 1746 1747 1748 1749 1750 1751
struct fileOpHookData {
    virDomainPtr dom;
    const char *path;
    char *xml;
    struct qemud_save_header *header;
};

1752
/* return -errno on failure, or 0 on success */
1753 1754 1755 1756 1757
static int qemudDomainSaveFileOpHook(int fd, void *data) {
    struct fileOpHookData *hdata = data;
    int ret = 0;

    if (safewrite(fd, hdata->header, sizeof(*hdata->header)) != sizeof(*hdata->header)) {
1758
        ret = -errno;
1759
        qemuReportError(VIR_ERR_OPERATION_FAILED,
1760 1761
                        _("failed to write header to domain save file '%s'"),
                        hdata->path);
1762 1763 1764 1765
        goto endjob;
    }

    if (safewrite(fd, hdata->xml, hdata->header->xml_len) != hdata->header->xml_len) {
1766
        ret = -errno;
1767 1768 1769 1770 1771 1772 1773 1774
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                         _("failed to write xml to '%s'"), hdata->path);
        goto endjob;
    }
endjob:
    return ret;
}

1775 1776 1777
/* This internal function expects the driver lock to already be held on
 * entry and the vm must be active.
 */
1778 1779
static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom,
                               virDomainObjPtr vm, const char *path,
1780
                               int compressed)
1781
{
1782
    char *xml = NULL;
1783
    struct qemud_save_header header;
1784 1785
    struct fileOpHookData hdata;
    int bypassSecurityDriver = 0;
1786
    int ret = -1;
1787
    int rc;
1788
    virDomainEventPtr event = NULL;
1789
    qemuDomainObjPrivatePtr priv;
1790 1791
    struct stat sb;
    int is_reg = 0;
1792
    unsigned long long offset;
1793
    virCgroupPtr cgroup = NULL;
1794 1795 1796 1797 1798

    memset(&header, 0, sizeof(header));
    memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
    header.version = QEMUD_SAVE_VERSION;

1799
    header.compressed = compressed;
1800

1801
    priv = vm->privateData;
1802

1803 1804 1805
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

O
Osier Yang 已提交
1806 1807
    priv->jobActive = QEMU_JOB_SAVE;

1808 1809 1810
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

1811 1812 1813
    /* Pause */
    if (vm->state == VIR_DOMAIN_RUNNING) {
        header.was_running = 1;
1814
        if (qemuProcessStopCPUs(driver, vm) < 0)
1815
            goto endjob;
1816 1817 1818 1819 1820 1821

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

    /* Get XML for the domain */
1825
    xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
1826
    if (!xml) {
1827 1828
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
1829
        goto endjob;
1830 1831 1832
    }
    header.xml_len = strlen(xml) + 1;

1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845
    /* 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 (stat(path, &sb) < 0) {
        /* Avoid throwing an error here, since it is possible
         * that with NFS we can't actually stat() the file.
         * The subsequent codepaths will still raise an error
         * if a truely fatal problem is hit */
        is_reg = 1;
    } else {
        is_reg = S_ISREG(sb.st_mode);
    }

1846 1847 1848 1849 1850
    offset = sizeof(header) + header.xml_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
1851 1852
     * it by padding the XML string with NULLs.
     */
1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
    if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
        unsigned long long pad =
            QEMU_MONITOR_MIGRATE_TO_FILE_BS -
            (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS);

        if (VIR_REALLOC_N(xml, header.xml_len + pad) < 0) {
            virReportOOMError();
            goto endjob;
        }
        memset(xml + header.xml_len, 0, pad);
        offset += pad;
        header.xml_len += pad;
    }
1866

1867 1868 1869 1870 1871 1872
    /* Setup hook data needed by virFileOperation hook function */
    hdata.dom = dom;
    hdata.path = path;
    hdata.xml = xml;
    hdata.header = &header;

1873 1874
    /* Write header to file, followed by XML */

1875
    /* First try creating the file as root */
1876 1877 1878 1879
    if (!is_reg) {
        int fd = open(path, O_WRONLY | O_TRUNC);
        if (fd < 0) {
            virReportSystemError(errno, _("unable to open %s"), path);
1880 1881
            goto endjob;
        }
1882
        if (qemudDomainSaveFileOpHook(fd, &hdata) < 0) {
1883
            VIR_FORCE_CLOSE(fd);
1884 1885
            goto endjob;
        }
1886
        if (VIR_CLOSE(fd) < 0) {
1887
            virReportSystemError(errno, _("unable to close %s"), path);
1888 1889
            goto endjob;
        }
1890 1891 1892 1893 1894
    } else {
        if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
                                  S_IRUSR|S_IWUSR,
                                  getuid(), getgid(),
                                  qemudDomainSaveFileOpHook, &hdata,
1895
                                  0)) < 0) {
1896
            /* If we failed as root, and the error was permission-denied
1897 1898
               (EACCES or EPERM), assume it's on a network-connected share
               where root access is restricted (eg, root-squashed NFS). If the
1899 1900 1901 1902
               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 */

1903
            if (((rc != -EACCES) && (rc != -EPERM)) ||
1904
                driver->user == getuid()) {
1905
                virReportSystemError(-rc, _("Failed to create domain save file '%s'"),
1906 1907 1908
                                     path);
                goto endjob;
            }
1909

1910
            /* On Linux we can also verify the FS-type of the directory. */
1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928
            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 domain save file "
                                          "'%s': couldn't determine fs type"),
                                        path);
                   goto endjob;
                   break;

                case 0:
                default:
                   /* local file - log the error returned by virFileOperation */
1929
                   virReportSystemError(-rc,
1930 1931 1932 1933
                                        _("Failed to create domain save file '%s'"),
                                        path);
                   goto endjob;
                   break;
1934 1935 1936

            }

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

1939 1940 1941 1942
            if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
                                       S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
                                       driver->user, driver->group,
                                       qemudDomainSaveFileOpHook, &hdata,
1943 1944
                                       VIR_FILE_OP_AS_UID)) < 0) {
                virReportSystemError(-rc, _("Error from child process creating '%s'"),
1945
                                 path);
1946 1947
                goto endjob;
            }
1948

1949 1950 1951
            /* 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 */
1952

1953 1954
            bypassSecurityDriver = 1;
        }
1955
    }
1956

1957

1958 1959 1960 1961
    if (!is_reg &&
        qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
1962
                            _("Unable to find cgroup for %s"),
1963 1964 1965 1966
                            vm->def->name);
            goto endjob;
        }
        rc = virCgroupAllowDevicePath(cgroup, path);
1967
        qemuAuditCgroupPath(vm, cgroup, "allow", path, rc);
1968
        if (rc < 0) {
1969 1970 1971 1972 1973 1974 1975
            virReportSystemError(-rc,
                                 _("Unable to allow device %s for %s"),
                                 path, vm->def->name);
            goto endjob;
        }
    }

1976
    if ((!bypassSecurityDriver) &&
1977 1978
        virSecurityManagerSetSavedStateLabel(driver->securityManager,
                                             vm, path) < 0)
1979 1980
        goto endjob;

1981 1982
    if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = { "cat", NULL };
M
Matthias Bolte 已提交
1983
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
1984 1985 1986
        rc = qemuMonitorMigrateToFile(priv->mon,
                                      QEMU_MONITOR_MIGRATE_BACKGROUND,
                                      args, path, offset);
M
Matthias Bolte 已提交
1987
        qemuDomainObjExitMonitorWithDriver(driver, vm);
1988
    } else {
1989
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
1990 1991 1992 1993 1994
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
M
Matthias Bolte 已提交
1995
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
1996 1997 1998
        rc = qemuMonitorMigrateToFile(priv->mon,
                                      QEMU_MONITOR_MIGRATE_BACKGROUND,
                                      args, path, offset);
M
Matthias Bolte 已提交
1999
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2000 2001
    }

2002 2003 2004
    if (rc < 0)
        goto endjob;

2005
    rc = qemuMigrationWaitForCompletion(driver, vm);
2006

2007
    if (rc < 0)
2008
        goto endjob;
2009

2010
    if ((!bypassSecurityDriver) &&
2011 2012
        virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
                                                 vm, path) < 0)
2013
        VIR_WARN("failed to restore save state label on %s", path);
2014

2015 2016
    if (cgroup != NULL) {
        rc = virCgroupDenyDevicePath(cgroup, path);
2017
        qemuAuditCgroupPath(vm, cgroup, "deny", path, rc);
2018
        if (rc < 0)
2019 2020
            VIR_WARN("Unable to deny device %s for %s %d",
                     path, vm->def->name, rc);
2021 2022
    }

2023 2024
    ret = 0;

2025
    /* Shut it down */
2026
    qemuProcessStop(driver, vm, 0);
2027
    qemuDomainStopAudit(vm, "saved");
2028 2029 2030
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
2031
    if (!vm->persistent) {
2032 2033 2034
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
2035 2036
        vm = NULL;
    }
2037

2038
endjob:
2039
    if (vm) {
2040
        if (ret != 0) {
2041
            if (header.was_running && virDomainObjIsActive(vm)) {
2042
                rc = qemuProcessStartCPUs(driver, vm, dom->conn);
2043 2044 2045
                if (rc < 0)
                    VIR_WARN0("Unable to resume guest CPUs after save failure");
            }
2046

2047 2048
            if (cgroup != NULL) {
                rc = virCgroupDenyDevicePath(cgroup, path);
2049
                qemuAuditCgroupPath(vm, cgroup, "deny", path, rc);
2050
                if (rc < 0)
2051 2052
                    VIR_WARN("Unable to deny device %s for %s: %d",
                             path, vm->def->name, rc);
2053
            }
2054 2055

            if ((!bypassSecurityDriver) &&
2056 2057
                virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
                                                         vm, path) < 0)
2058
                VIR_WARN("failed to restore save state label on %s", path);
2059 2060
        }

2061
        if (qemuDomainObjEndJob(vm) == 0)
2062
            vm = NULL;
2063
    }
2064

2065 2066
cleanup:
    VIR_FREE(xml);
2067
    if (ret != 0 && is_reg)
2068
        unlink(path);
2069 2070
    if (event)
        qemuDomainEventQueue(driver, event);
2071
    virCgroupFree(&cgroup);
2072
    return ret;
D
Daniel P. Berrange 已提交
2073 2074
}

2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090
/* 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;
}

2091 2092 2093 2094
static int qemudDomainSave(virDomainPtr dom, const char *path)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int compressed;
2095 2096 2097 2098
    int ret = -1;
    virDomainObjPtr vm = NULL;

    qemuDriverLock(driver);
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109

    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"));
            return -1;
        }
2110 2111 2112 2113 2114 2115
        if (!qemudCompressProgramAvailable(compressed)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Compression program for image format "
                                    "in configuration file isn't available"));
            return -1;
        }
2116 2117
    }

2118 2119 2120 2121 2122 2123 2124 2125 2126
    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;
    }

2127 2128 2129 2130 2131 2132
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2133 2134 2135 2136 2137 2138 2139 2140
    ret = qemudDomainSaveFlag(driver, dom, vm, path, compressed);

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

    return ret;
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163
}

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;

2164
    virCheckFlags(0, -1);
2165 2166 2167 2168 2169 2170 2171 2172

    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);
2173
        goto cleanup;
2174 2175
    }

2176 2177 2178 2179 2180 2181
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

2182 2183
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
2184
        goto cleanup;
2185 2186 2187 2188

    VIR_DEBUG("Saving state to %s", name);

    compressed = QEMUD_SAVE_FORMAT_RAW;
2189
    ret = qemudDomainSaveFlag(driver, dom, vm, name, compressed);
2190 2191 2192 2193 2194

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
2195 2196 2197
    VIR_FREE(name);

    return ret;
2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
}

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

2208
    virCheckFlags(0, -1);
2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241

    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;

2242
    virCheckFlags(0, -1);
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266

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

H
Hu Tao 已提交
2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292
static int doCoreDump(struct qemud_driver *driver,
                      virDomainObjPtr vm,
                      const char *path,
                      enum qemud_save_formats compress)
{
    int fd = -1;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    priv = vm->privateData;

    /* Create an empty file with appropriate ownership.  */
    if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("failed to create '%s'"), path);
        goto cleanup;
    }

    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
                             _("unable to save file %s"),
                             path);
        goto cleanup;
    }

2293 2294
    if (virSecurityManagerSetSavedStateLabel(driver->securityManager,
                                             vm, path) < 0)
H
Hu Tao 已提交
2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320
        goto cleanup;

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    if (compress == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = {
            "cat",
            NULL,
        };
        ret = qemuMonitorMigrateToFile(priv->mon,
                                       QEMU_MONITOR_MIGRATE_BACKGROUND,
                                       args, path, 0);
    } else {
        const char *prog = qemudSaveCompressionTypeToString(compress);
        const char *args[] = {
            prog,
            "-c",
            NULL,
        };
        ret = qemuMonitorMigrateToFile(priv->mon,
                                       QEMU_MONITOR_MIGRATE_BACKGROUND,
                                       args, path, 0);
    }
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    if (ret < 0)
        goto cleanup;

2321
    ret = qemuMigrationWaitForCompletion(driver, vm);
H
Hu Tao 已提交
2322 2323 2324 2325

    if (ret < 0)
        goto cleanup;

2326 2327
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
                                                 vm, path) < 0)
H
Hu Tao 已提交
2328 2329 2330 2331 2332 2333 2334 2335
        goto cleanup;

cleanup:
    if (ret != 0)
        unlink(path);
    return ret;
}

2336 2337 2338 2339 2340
static enum qemud_save_formats
getCompressionType(struct qemud_driver *driver)
{
    int compress = QEMUD_SAVE_FORMAT_RAW;

2341 2342 2343 2344 2345 2346 2347
    /*
     * 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);
        if (compress < 0) {
2348 2349 2350 2351
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("Invalid dump image format specified in "
                              "configuration file, using raw"));
            return QEMUD_SAVE_FORMAT_RAW;
2352
        }
2353 2354 2355
        if (!qemudCompressProgramAvailable(compress)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Compression program for dump image format "
2356 2357 2358
                                    "in configuration file isn't available, "
                                    "using raw"));
            return QEMUD_SAVE_FORMAT_RAW;
2359
        }
2360
    }
2361 2362 2363 2364 2365 2366 2367 2368 2369
    return compress;
}

static int qemudDomainCoreDump(virDomainPtr dom,
                               const char *path,
                               int flags ATTRIBUTE_UNUSED) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int resume = 0, paused = 0;
H
Hu Tao 已提交
2370
    int ret = -1;
2371 2372 2373
    virDomainEventPtr event = NULL;
    qemuDomainObjPrivatePtr priv;

P
Paolo Bonzini 已提交
2374 2375 2376 2377 2378 2379
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2380 2381
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
2382 2383
        goto cleanup;
    }
2384
    priv = vm->privateData;
P
Paolo Bonzini 已提交
2385

2386
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
2387 2388
        goto cleanup;

D
Daniel P. Berrange 已提交
2389
    if (!virDomainObjIsActive(vm)) {
2390 2391
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
2392
        goto endjob;
P
Paolo Bonzini 已提交
2393 2394
    }

O
Osier Yang 已提交
2395 2396
    priv->jobActive = QEMU_JOB_DUMP;

P
Paolo Bonzini 已提交
2397 2398
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
P
Paolo Bonzini 已提交
2399 2400 2401
    resume = (vm->state == VIR_DOMAIN_RUNNING);

    /* Pause domain for non-live dump */
P
Paolo Bonzini 已提交
2402
    if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
2403
        if (qemuProcessStopCPUs(driver, vm) < 0)
2404
            goto endjob;
P
Paolo Bonzini 已提交
2405
        paused = 1;
2406 2407 2408 2409 2410 2411

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

H
Hu Tao 已提交
2414
    ret = doCoreDump(driver, vm, path, getCompressionType(driver));
2415 2416 2417 2418
    if (ret < 0)
        goto endjob;

    paused = 1;
2419 2420

endjob:
2421
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
2422
        qemuProcessStop(driver, vm, 0);
2423
        qemuDomainStopAudit(vm, "crashed");
2424 2425 2426 2427 2428
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
2429 2430 2431
    /* 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.  */
2432
    else if (resume && paused && virDomainObjIsActive(vm)) {
2433
        if (qemuProcessStartCPUs(driver, vm, dom->conn) < 0) {
2434
            if (virGetLastError() == NULL)
2435 2436
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
2437 2438
        }
    }
2439

2440 2441
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
2442
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
2443 2444 2445 2446
        virDomainRemoveInactive(&driver->domains,
                                vm);
        vm = NULL;
    }
2447 2448

cleanup:
P
Paolo Bonzini 已提交
2449 2450
    if (vm)
        virDomainObjUnlock(vm);
2451 2452
    if (event)
        qemuDomainEventQueue(driver, event);
2453
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
2454 2455 2456
    return ret;
}

H
Hu Tao 已提交
2457 2458 2459
static void processWatchdogEvent(void *data, void *opaque)
{
    int ret;
2460
    struct qemuDomainWatchdogEvent *wdEvent = data;
H
Hu Tao 已提交
2461 2462 2463 2464 2465 2466 2467
    struct qemud_driver *driver = opaque;

    switch (wdEvent->action) {
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;

E
Eric Blake 已提交
2468
            if (virAsprintf(&dumpfile, "%s/%s-%u",
H
Hu Tao 已提交
2469 2470
                            driver->autoDumpPath,
                            wdEvent->vm->def->name,
E
Eric Blake 已提交
2471 2472 2473 2474
                            (unsigned int)time(NULL)) < 0) {
                virReportOOMError();
                break;
            }
H
Hu Tao 已提交
2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495

            qemuDriverLock(driver);
            virDomainObjLock(wdEvent->vm);

            if (qemuDomainObjBeginJobWithDriver(driver, wdEvent->vm) < 0)
                break;

            if (!virDomainObjIsActive(wdEvent->vm)) {
                qemuReportError(VIR_ERR_OPERATION_INVALID,
                                "%s", _("domain is not running"));
                break;
            }

            ret = doCoreDump(driver,
                             wdEvent->vm,
                             dumpfile,
                             getCompressionType(driver));
            if (ret < 0)
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("Dump failed"));

2496
            ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL);
H
Hu Tao 已提交
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513

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

            if (qemuDomainObjEndJob(wdEvent->vm) > 0)
                virDomainObjUnlock(wdEvent->vm);

            qemuDriverUnlock(driver);

            VIR_FREE(dumpfile);
        }
        break;
    }

    VIR_FREE(wdEvent);
}
P
Paolo Bonzini 已提交
2514

2515 2516 2517
static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2518
    int i, rc = 1;
2519
    int ret = -1;
2520
    int oldvcpus = vm->def->vcpus;
2521

2522 2523
    qemuDomainObjEnterMonitor(vm);

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
    /* 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 */
    if (nvcpus > vm->def->vcpus) {
        for (i = vm->def->vcpus ; i < nvcpus ; i++) {
            /* Online new CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

            vm->def->vcpus++;
        }
    } else {
        for (i = vm->def->vcpus - 1 ; i >= nvcpus ; i--) {
            /* Offline old CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

            vm->def->vcpus--;
        }
    }

    ret = 0;

cleanup:
2554
    qemuDomainObjExitMonitor(vm);
2555
    qemuDomainVcpuAudit(vm, oldvcpus, nvcpus, "update", rc == 1);
2556 2557 2558 2559 2560 2561 2562 2563 2564
    return ret;

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


2565 2566 2567 2568
static int
qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                         unsigned int flags)
{
2569 2570
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2571
    virDomainDefPtr persistentDef;
2572 2573
    const char * type;
    int max;
2574
    int ret = -1;
2575

2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    /* At least one of LIVE or CONFIG must be set.  MAXIMUM cannot be
     * mixed with LIVE.  */
    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 ||
        (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
         (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid flag combination: (0x%x)"), flags);
        return -1;
    }
    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("argument out of range: %d"), nvcpus);
2592 2593 2594
        return -1;
    }

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

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

2607 2608 2609
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

2610
    if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_LIVE)) {
2611 2612
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
2613
        goto endjob;
2614 2615
    }

2616 2617 2618 2619 2620 2621
    if (!vm->persistent && (flags & VIR_DOMAIN_VCPU_CONFIG)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot change persistent config of a transient domain"));
        goto endjob;
    }

2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634
    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;
    }

C
Cole Robinson 已提交
2635
    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM) && vm->def->maxvcpus < max) {
2636 2637 2638
        max = vm->def->maxvcpus;
    }

2639 2640 2641 2642 2643 2644 2645
    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;
    }

2646 2647 2648
    if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
        goto endjob;

2649 2650
    switch (flags) {
    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG:
2651 2652 2653
        persistentDef->maxvcpus = nvcpus;
        if (nvcpus < persistentDef->vcpus)
            persistentDef->vcpus = nvcpus;
2654 2655 2656 2657
        ret = 0;
        break;

    case VIR_DOMAIN_VCPU_CONFIG:
2658
        persistentDef->vcpus = nvcpus;
2659 2660 2661 2662 2663 2664 2665 2666 2667
        ret = 0;
        break;

    case VIR_DOMAIN_VCPU_LIVE:
        ret = qemudDomainHotplugVcpus(vm, nvcpus);
        break;

    case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG:
        ret = qemudDomainHotplugVcpus(vm, nvcpus);
2668 2669 2670
        if (ret == 0) {
            persistentDef->vcpus = nvcpus;
        }
2671 2672
        break;
    }
2673

2674 2675 2676 2677
    /* Save the persistent config to disk */
    if (flags & VIR_DOMAIN_VCPU_CONFIG)
        ret = virDomainSaveConfig(driver->configDir, persistentDef);

2678 2679 2680
endjob:
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
2681

2682
cleanup:
2683 2684
    if (vm)
        virDomainObjUnlock(vm);
2685
    return ret;
2686 2687
}

2688 2689 2690 2691 2692 2693
static int
qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
    return qemudDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

2694 2695 2696 2697 2698 2699

static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
2700 2701
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2702
    int maxcpu, hostcpus;
2703
    virNodeInfo nodeinfo;
2704
    int ret = -1;
2705
    qemuDomainObjPrivatePtr priv;
2706

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

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

D
Daniel P. Berrange 已提交
2719
    if (!virDomainObjIsActive(vm)) {
2720 2721
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",_("cannot pin vcpus on an inactive domain"));
2722
        goto cleanup;
2723 2724
    }

2725 2726 2727
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
2728 2729 2730
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("vcpu number out of range %d > %d"),
                        vcpu, priv->nvcpupids);
2731
        goto cleanup;
2732 2733
    }

2734
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
2735
        goto cleanup;
2736

2737
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
2738
    maxcpu = maplen * 8;
2739 2740
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
2741

2742 2743
    if (priv->vcpupids != NULL) {
        if (virProcessInfoSetAffinity(priv->vcpupids[vcpu],
2744
                                      cpumap, maplen, maxcpu) < 0)
2745
            goto cleanup;
2746
    } else {
2747 2748
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cpu affinity is not supported"));
2749
        goto cleanup;
2750
    }
2751
    ret = 0;
2752

2753
cleanup:
2754 2755
    if (vm)
        virDomainObjUnlock(vm);
2756
    return ret;
2757 2758 2759 2760 2761 2762 2763 2764
}

static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
2765 2766
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2767
    virNodeInfo nodeinfo;
2768
    int i, v, maxcpu, hostcpus;
2769
    int ret = -1;
2770
    qemuDomainObjPrivatePtr priv;
2771

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

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

D
Daniel P. Berrange 已提交
2784
    if (!virDomainObjIsActive(vm)) {
2785 2786 2787
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",
                        _("cannot list vcpu pinning for an inactive domain"));
2788
        goto cleanup;
2789 2790
    }

2791 2792
    priv = vm->privateData;

2793
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
2794
        goto cleanup;
2795

2796
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
2797
    maxcpu = maplen * 8;
2798 2799
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
2800 2801

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

2805 2806 2807 2808 2809 2810
    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;
2811

2812
                if (priv->vcpupids != NULL &&
2813 2814 2815
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
                                        vm->pid,
2816
                                        priv->vcpupids[i]) < 0) {
2817
                    virReportSystemError(errno, "%s",
2818 2819 2820
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
2821
            }
2822 2823
        }

2824 2825
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
2826
            if (priv->vcpupids != NULL) {
2827 2828 2829
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);

2830
                    if (virProcessInfoGetAffinity(priv->vcpupids[v],
2831
                                                  cpumap, maplen, maxcpu) < 0)
2832
                        goto cleanup;
2833
                }
2834
            } else {
2835 2836
                qemuReportError(VIR_ERR_NO_SUPPORT,
                                "%s", _("cpu affinity is not available"));
2837
                goto cleanup;
2838 2839 2840
            }
        }
    }
2841
    ret = maxinfo;
2842

2843
cleanup:
2844 2845
    if (vm)
        virDomainObjUnlock(vm);
2846
    return ret;
2847 2848 2849
}


2850 2851 2852
static int
qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
2853 2854
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2855
    virDomainDefPtr def;
2856
    int ret = -1;
2857

2858 2859 2860 2861 2862 2863 2864 2865
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    /* Exactly one of LIVE or CONFIG must be set.  */
    if (!(flags & VIR_DOMAIN_VCPU_LIVE) == !(flags & VIR_DOMAIN_VCPU_CONFIG)) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid flag combination: (0x%x)"), flags);
2866 2867 2868
        return -1;
    }

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

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

2881 2882 2883 2884 2885 2886 2887 2888 2889
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("domain not active"));
            goto cleanup;
        }
        def = vm->def;
    } else {
        def = vm->newDef ? vm->newDef : vm->def;
2890 2891
    }

2892
    ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
2893

2894
cleanup:
2895 2896
    if (vm)
        virDomainObjUnlock(vm);
2897 2898 2899
    return ret;
}

2900 2901 2902 2903 2904 2905 2906
static int
qemudDomainGetMaxVcpus(virDomainPtr dom)
{
    return qemudDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                          VIR_DOMAIN_VCPU_MAXIMUM));
}

2907 2908 2909 2910 2911 2912 2913 2914 2915
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);

2916 2917
    memset(seclabel, 0, sizeof(*seclabel));

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

2926
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
2927 2928 2929
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946
        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 已提交
2947
    if (virDomainObjIsActive(vm)) {
2948 2949
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
                                              vm, seclabel) < 0) {
2950 2951 2952
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Failed to get security label"));
            goto cleanup;
2953 2954 2955 2956 2957 2958 2959 2960
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
2961
    qemuDriverUnlock(driver);
2962 2963 2964
    return ret;
}

2965 2966
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
2967 2968 2969
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
2970
    int ret = 0;
2971

2972
    qemuDriverLock(driver);
2973 2974 2975 2976 2977
    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)
2978
        goto cleanup;
2979

2980 2981
    p = driver->caps->host.secModel.model;
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
2982 2983 2984
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security model string exceeds max %d bytes"),
                        VIR_SECURITY_MODEL_BUFLEN-1);
2985 2986
        ret = -1;
        goto cleanup;
2987 2988 2989 2990 2991
    }
    strcpy(secmodel->model, p);

    p = driver->caps->host.secModel.doi;
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
2992 2993 2994
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security DOI string exceeds max %d bytes"),
                        VIR_SECURITY_DOI_BUFLEN-1);
2995 2996
        ret = -1;
        goto cleanup;
2997 2998
    }
    strcpy(secmodel->doi, p);
2999 3000 3001 3002

cleanup:
    qemuDriverUnlock(driver);
    return ret;
3003 3004
}

3005 3006 3007 3008 3009 3010
/* qemudOpenAsUID() - pipe/fork/setuid/open a file, and return the
   pipe fd to caller, so that it can read from the file. Also return
   the pid of the child process, so the caller can wait for it to exit
   after it's finished reading (to avoid a zombie, if nothing
   else). */

3011 3012 3013
static int
qemudOpenAsUID(const char *path, uid_t uid, gid_t gid, pid_t *child_pid)
{
3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040
    int pipefd[2];
    int fd = -1;

    *child_pid = -1;

    if (pipe(pipefd) < 0) {
        virReportSystemError(errno,
                             _("failed to create pipe to read '%s'"),
                             path);
        pipefd[0] = pipefd[1] = -1;
        goto parent_cleanup;
    }

    int forkRet = virFork(child_pid);

    if (*child_pid < 0) {
        virReportSystemError(errno,
                             _("failed to fork child to read '%s'"),
                             path);
        goto parent_cleanup;
    }

    if (*child_pid > 0) {

        /* parent */

        /* parent doesn't need the write side of the pipe */
3041
        VIR_FORCE_CLOSE(pipefd[1]);
3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052

        if (forkRet < 0) {
            virReportSystemError(errno,
                                 _("failed in parent after forking child to read '%s'"),
                                 path);
            goto parent_cleanup;
        }
        /* caller gets the read side of the pipe */
        fd = pipefd[0];
        pipefd[0] = -1;
parent_cleanup:
3053 3054
        VIR_FORCE_CLOSE(pipefd[0]);
        VIR_FORCE_CLOSE(pipefd[1]);
3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078
        if ((fd < 0) && (*child_pid > 0)) {
            /* a child process was started and subsequently an error
               occurred in the parent, so we need to wait for it to
               exit, but its status is inconsequential. */
            while ((waitpid(*child_pid, NULL, 0) == -1)
                   && (errno == EINTR)) {
                /* empty */
            }
            *child_pid = -1;
        }
        return fd;
    }

    /* child */

    /* setuid to the qemu user, then open the file, read it,
       and stuff it into the pipe for the parent process to
       read */
    int exit_code;
    char *buf = NULL;
    size_t bufsize = 1024 * 1024;
    int bytesread;

    /* child doesn't need the read side of the pipe */
3079
    VIR_FORCE_CLOSE(pipefd[0]);
3080 3081 3082 3083 3084 3085 3086 3087 3088

    if (forkRet < 0) {
        exit_code = errno;
        virReportSystemError(errno,
                             _("failed in child after forking to read '%s'"),
                             path);
        goto child_cleanup;
    }

3089 3090 3091
    if (virSetUIDGID(uid, gid) < 0) {
       exit_code = errno;
       goto child_cleanup;
3092 3093
    }

3094 3095 3096 3097 3098 3099 3100 3101
    if ((fd = open(path, O_RDONLY)) < 0) {
        exit_code = errno;
        virReportSystemError(errno,
                             _("cannot open '%s' as uid %d"),
                             path, uid);
        goto child_cleanup;
    }

3102 3103 3104 3105 3106 3107
    if (VIR_ALLOC_N(buf, bufsize) < 0) {
        exit_code = ENOMEM;
        virReportOOMError();
        goto child_cleanup;
    }

3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127
    /* read from fd and write to pipefd[1] until EOF */
    do {
        if ((bytesread = saferead(fd, buf, bufsize)) < 0) {
            exit_code = errno;
            virReportSystemError(errno,
                                 _("child failed reading from '%s'"),
                                 path);
            goto child_cleanup;
        }
        if (safewrite(pipefd[1], buf, bytesread) != bytesread) {
            exit_code = errno;
            virReportSystemError(errno, "%s",
                                 _("child failed writing to pipe"));
            goto child_cleanup;
        }
    } while (bytesread > 0);
    exit_code = 0;

child_cleanup:
    VIR_FREE(buf);
3128 3129
    VIR_FORCE_CLOSE(fd);
    VIR_FORCE_CLOSE(pipefd[1]);
3130 3131 3132
    _exit(exit_code);
}

J
Jiri Denemark 已提交
3133 3134 3135 3136
static int qemudDomainSaveImageClose(int fd, pid_t read_pid, int *status)
{
    int ret = 0;

3137 3138 3139 3140
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, "%s",
                             _("cannot close file"));
    }
J
Jiri Denemark 已提交
3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156

    if (read_pid != -1) {
        /* reap the process that read the file */
        while ((ret = waitpid(read_pid, status, 0)) == -1
               && errno == EINTR) {
            /* empty */
        }
    } else if (status) {
        *status = 0;
    }

    return ret;
}

static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5)
qemudDomainSaveImageOpen(struct qemud_driver *driver,
3157 3158 3159 3160
                         const char *path,
                         virDomainDefPtr *ret_def,
                         struct qemud_save_header *ret_header,
                         pid_t *ret_read_pid)
J
Jiri Denemark 已提交
3161 3162
{
    int fd;
3163
    pid_t read_pid = -1;
3164
    struct qemud_save_header header;
J
Jiri Denemark 已提交
3165 3166
    char *xml = NULL;
    virDomainDefPtr def = NULL;
3167 3168

    if ((fd = open(path, O_RDONLY)) < 0) {
3169 3170 3171
        if ((driver->user == 0) || (getuid() != 0)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("cannot read domain image"));
J
Jiri Denemark 已提交
3172
            goto error;
3173 3174 3175 3176 3177 3178
        }

        /* Opening as root failed, but qemu runs as a different user
           that might have better luck. Create a pipe, then fork a
           child process to run as the qemu user, which will hopefully
           have the necessary authority to read the file. */
3179 3180
        if ((fd = qemudOpenAsUID(path,
                                 driver->user, driver->group, &read_pid)) < 0) {
3181
            /* error already reported */
J
Jiri Denemark 已提交
3182
            goto error;
3183
        }
3184 3185 3186
    }

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
3187 3188
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
3189
        goto error;
3190 3191 3192
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
3193 3194
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("image magic is incorrect"));
J
Jiri Denemark 已提交
3195
        goto error;
3196 3197 3198
    }

    if (header.version > QEMUD_SAVE_VERSION) {
3199 3200 3201
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("image version is not supported (%d > %d)"),
                        header.version, QEMUD_SAVE_VERSION);
J
Jiri Denemark 已提交
3202
        goto error;
3203 3204
    }

3205 3206 3207
    if (header.xml_len <= 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
3208
        goto error;
3209 3210
    }

3211 3212
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
J
Jiri Denemark 已提交
3213
        goto error;
3214 3215 3216
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
3217 3218
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
3219
        goto error;
3220 3221 3222
    }

    /* Create a domain from this XML */
3223
    if (!(def = virDomainDefParseString(driver->caps, xml,
3224
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
3225
        goto error;
3226

J
Jiri Denemark 已提交
3227
    VIR_FREE(xml);
3228

J
Jiri Denemark 已提交
3229 3230 3231
    *ret_def = def;
    *ret_header = header;
    *ret_read_pid = read_pid;
3232

J
Jiri Denemark 已提交
3233
    return fd;
3234

J
Jiri Denemark 已提交
3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
    qemudDomainSaveImageClose(fd, read_pid, NULL);

    return -1;
}

static int ATTRIBUTE_NONNULL(6)
qemudDomainSaveImageStartVM(virConnectPtr conn,
                            struct qemud_driver *driver,
                            virDomainObjPtr vm,
3247 3248
                            int *fd,
                            pid_t *read_pid,
J
Jiri Denemark 已提交
3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260
                            const struct qemud_save_header *header,
                            const char *path)
{
    int ret = -1;
    virDomainEventPtr event;
    int intermediatefd = -1;
    pid_t intermediate_pid = -1;
    int childstat;
    int wait_ret;
    int status;

    if (header->version == 2) {
3261
        const char *intermediate_argv[3] = { NULL, "-dc", NULL };
J
Jiri Denemark 已提交
3262
        const char *prog = qemudSaveCompressionTypeToString(header->compressed);
3263
        if (prog == NULL) {
3264 3265
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("Invalid compressed save format %d"),
J
Jiri Denemark 已提交
3266 3267
                            header->compressed);
            goto out;
3268
        }
3269

J
Jiri Denemark 已提交
3270
        if (header->compressed != QEMUD_SAVE_FORMAT_RAW) {
3271
            intermediate_argv[0] = prog;
3272 3273
            intermediatefd = *fd;
            *fd = -1;
3274
            if (virExec(intermediate_argv, NULL, NULL,
3275
                        &intermediate_pid, intermediatefd, fd, NULL, 0) < 0) {
3276 3277 3278
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Failed to start decompression binary %s"),
                                intermediate_argv[0]);
3279
                *fd = intermediatefd;
J
Jiri Denemark 已提交
3280
                goto out;
3281 3282 3283
            }
        }
    }
J
Jiri Denemark 已提交
3284

3285
    /* Set the migration source and start it up. */
3286
    ret = qemuProcessStart(conn, driver, vm, "stdio", true, *fd, path,
3287
                           VIR_VM_OP_RESTORE);
J
Jiri Denemark 已提交
3288

3289
    if (intermediate_pid != -1) {
3290 3291 3292 3293 3294
        if (ret < 0) {
            /* if there was an error setting up qemu, the intermediate process will
             * wait forever to write to stdout, so we must manually kill it.
             */
            VIR_FORCE_CLOSE(intermediatefd);
3295
            VIR_FORCE_CLOSE(*fd);
3296 3297 3298
            kill(intermediate_pid, SIGTERM);
        }

3299 3300
        /* Wait for intermediate process to exit */
        while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
J
Jiri Denemark 已提交
3301 3302 3303
               errno == EINTR) {
            /* empty */
        }
3304
    }
3305
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
3306

3307 3308 3309
    wait_ret = qemudDomainSaveImageClose(*fd, *read_pid, &status);
    *fd = -1;
    if (*read_pid != -1) {
3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329
        if (wait_ret == -1) {
            virReportSystemError(errno,
                                 _("failed to wait for process reading '%s'"),
                                 path);
            ret = -1;
        } else if (!WIFEXITED(status)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("child process exited abnormally reading '%s'"),
                            path);
            ret = -1;
        } else {
            int exit_status = WEXITSTATUS(status);
            if (exit_status != 0) {
                virReportSystemError(exit_status,
                                     _("child process returned error reading '%s'"),
                                     path);
                ret = -1;
            }
        }
    }
3330
    *read_pid = -1;
J
Jiri Denemark 已提交
3331

3332 3333
    if (ret < 0) {
        qemuDomainStartAudit(vm, "restored", false);
J
Jiri Denemark 已提交
3334
        goto out;
3335
    }
3336

3337 3338 3339
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
3340
    qemuDomainStartAudit(vm, "restored", true);
J
Jiri Denemark 已提交
3341 3342 3343
    if (event)
        qemuDomainEventQueue(driver, event);

3344

3345
    /* If it was running before, resume it now. */
J
Jiri Denemark 已提交
3346
    if (header->was_running) {
3347
        if (qemuProcessStartCPUs(driver, vm, conn) < 0) {
3348
            if (virGetLastError() == NULL)
3349 3350
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("failed to resume domain"));
J
Jiri Denemark 已提交
3351
            goto out;
3352
        }
3353 3354
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
J
Jiri Denemark 已提交
3355
            goto out;
3356
        }
3357
    }
J
Jiri Denemark 已提交
3358

3359
    ret = 0;
3360

J
Jiri Denemark 已提交
3361
out:
3362 3363
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
                                                 vm, path) < 0)
3364 3365
        VIR_WARN("failed to restore save state label on %s", path);

J
Jiri Denemark 已提交
3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390
    return ret;
}

static int qemudDomainRestore(virConnectPtr conn,
                              const char *path) {
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    pid_t read_pid = -1;
    int ret = -1;
    struct qemud_save_header header;

    qemuDriverLock(driver);

    fd = qemudDomainSaveImageOpen(driver, path, &def, &header, &read_pid);
    if (fd < 0)
        goto cleanup;

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

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, true))) {
3391
        /* virDomainAssignDef already set the error */
J
Jiri Denemark 已提交
3392 3393 3394 3395 3396 3397 3398
        goto cleanup;
    }
    def = NULL;

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

3399 3400
    ret = qemudDomainSaveImageStartVM(conn, driver, vm, &fd,
                                      &read_pid, &header, path);
J
Jiri Denemark 已提交
3401 3402

    if (qemuDomainObjEndJob(vm) == 0)
3403
        vm = NULL;
J
Jiri Denemark 已提交
3404 3405 3406 3407
    else if (ret < 0 && !vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
3408

3409 3410
cleanup:
    virDomainDefFree(def);
J
Jiri Denemark 已提交
3411
    qemudDomainSaveImageClose(fd, read_pid, NULL);
3412 3413 3414
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
3415
    return ret;
D
Daniel P. Berrange 已提交
3416 3417
}

J
Jiri Denemark 已提交
3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449
static int qemudDomainObjRestore(virConnectPtr conn,
                                 struct qemud_driver *driver,
                                 virDomainObjPtr vm,
                                 const char *path)
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    pid_t read_pid = -1;
    int ret = -1;
    struct qemud_save_header header;

    fd = qemudDomainSaveImageOpen(driver, path, &def, &header, &read_pid);
    if (fd < 0)
        goto cleanup;

    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;

3450 3451
    ret = qemudDomainSaveImageStartVM(conn, driver, vm, &fd,
                                      &read_pid, &header, path);
J
Jiri Denemark 已提交
3452 3453 3454 3455 3456 3457 3458

cleanup:
    virDomainDefFree(def);
    qemudDomainSaveImageClose(fd, read_pid, NULL);
    return ret;
}

D
Daniel P. Berrange 已提交
3459

3460
static char *qemudDomainDumpXML(virDomainPtr dom,
3461
                                int flags) {
3462 3463 3464
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
3465 3466
    unsigned long balloon;
    int err;
3467

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

D
Daniel P. Berrange 已提交
3471
    if (!vm) {
3472 3473
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3474 3475
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
3476
        goto cleanup;
D
Daniel P. Berrange 已提交
3477 3478
    }

3479 3480 3481 3482
    /* 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))) {
3483
        qemuDomainObjPrivatePtr priv = vm->privateData;
3484 3485 3486
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
        if (!priv->jobActive) {
3487
            if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
3488 3489
                goto cleanup;

3490
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
3491
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
3492
            qemuDomainObjExitMonitorWithDriver(driver, vm);
3493 3494 3495 3496
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
                goto cleanup;
            }
3497 3498 3499
            if (err < 0)
                goto cleanup;
            if (err > 0)
3500
                vm->def->mem.cur_balloon = balloon;
3501 3502
            /* err == 0 indicates no balloon support, so ignore it */
        }
3503
    }
3504

3505
    ret = qemuDomainFormatXML(driver, vm, flags);
3506 3507

cleanup:
3508 3509
    if (vm)
        virDomainObjUnlock(vm);
3510
    qemuDriverUnlock(driver);
3511
    return ret;
D
Daniel P. Berrange 已提交
3512 3513 3514
}


3515 3516 3517 3518
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
                                     unsigned int flags ATTRIBUTE_UNUSED) {
3519
    struct qemud_driver *driver = conn->privateData;
3520 3521 3522 3523
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
3524 3525
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
3526 3527 3528
        goto cleanup;
    }

3529
    qemuDriverLock(driver);
3530
    def = qemuParseCommandLineString(driver->caps, config);
3531
    qemuDriverUnlock(driver);
3532 3533 3534
    if (!def)
        goto cleanup;

3535
    xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
3536 3537 3538 3539 3540 3541

cleanup:
    virDomainDefFree(def);
    return xml;
}

3542 3543 3544 3545 3546 3547
static char *qemuDomainXMLToNative(virConnectPtr conn,
                                   const char *format,
                                   const char *xmlData,
                                   unsigned int flags ATTRIBUTE_UNUSED) {
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
3548
    virDomainChrSourceDef monConfig;
3549
    virBitmapPtr qemuCaps = NULL;
E
Eric Blake 已提交
3550
    virCommandPtr cmd = NULL;
3551 3552 3553
    char *ret = NULL;
    int i;

3554 3555
    qemuDriverLock(driver);

3556
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
3557 3558
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
3559 3560 3561
        goto cleanup;
    }

3562
    def = virDomainDefParseString(driver->caps, xmlData, 0);
3563 3564 3565
    if (!def)
        goto cleanup;

3566 3567
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
3568 3569 3570 3571 3572
     * 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];
3573
        int bootIndex = net->bootIndex;
3574 3575
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
            net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595
            VIR_FREE(net->data.network.name);

            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;
        }
3596
        net->bootIndex = bootIndex;
3597 3598 3599 3600
    }
    for (i = 0 ; i < def->ngraphics ; i++) {
        if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
            def->graphics[i]->data.vnc.autoport)
3601
            def->graphics[i]->data.vnc.port = QEMU_VNC_PORT_MIN;
3602 3603
    }

3604
    if (qemuCapsExtractVersionInfo(def->emulator, def->os.arch,
3605
                                   NULL,
3606
                                   &qemuCaps) < 0)
3607 3608
        goto cleanup;

3609
    if (qemuProcessPrepareMonitorChr(driver, &monConfig, def->name) < 0)
3610
        goto cleanup;
3611

3612
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
3613
                                     &monConfig, false, qemuCaps,
3614
                                     NULL, -1, NULL, VIR_VM_OP_NO_OP)))
3615 3616
        goto cleanup;

E
Eric Blake 已提交
3617
    ret = virCommandToString(cmd);
3618 3619

cleanup:
3620
    qemuDriverUnlock(driver);
3621

3622
    qemuCapsFree(qemuCaps);
E
Eric Blake 已提交
3623
    virCommandFree(cmd);
3624 3625 3626 3627 3628
    virDomainDefFree(def);
    return ret;
}


3629
static int qemudListDefinedDomains(virConnectPtr conn,
3630
                            char **const names, int nnames) {
3631
    struct qemud_driver *driver = conn->privateData;
3632
    int n;
3633

3634
    qemuDriverLock(driver);
3635
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
3636
    qemuDriverUnlock(driver);
3637
    return n;
D
Daniel P. Berrange 已提交
3638 3639
}

3640
static int qemudNumDefinedDomains(virConnectPtr conn) {
3641
    struct qemud_driver *driver = conn->privateData;
3642
    int n;
3643

3644
    qemuDriverLock(driver);
3645
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
3646
    qemuDriverUnlock(driver);
3647

3648
    return n;
D
Daniel P. Berrange 已提交
3649 3650 3651
}


J
Jiri Denemark 已提交
3652 3653
static int qemudDomainObjStart(virConnectPtr conn,
                               struct qemud_driver *driver,
3654 3655
                               virDomainObjPtr vm,
                               bool start_paused)
J
Jiri Denemark 已提交
3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675
{
    int ret = -1;
    char *managed_save;

    /*
     * If there is a managed saved state restore it instead of starting
     * from scratch. In any case the old state is removed.
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
    if ((managed_save) && (virFileExists(managed_save))) {
        ret = qemudDomainObjRestore(conn, driver, vm, managed_save);

        if (unlink(managed_save) < 0) {
            VIR_WARN("Failed to remove the managed state %s", managed_save);
        }

        if (ret == 0)
            goto cleanup;
    }

3676 3677
    ret = qemuProcessStart(conn, driver, vm, NULL, start_paused, -1, NULL,
                           VIR_VM_OP_CREATE);
3678 3679
    qemuDomainStartAudit(vm, "booted", ret >= 0);
    if (ret >= 0) {
J
Jiri Denemark 已提交
3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

3693 3694 3695
static int
qemudDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
{
3696 3697 3698
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
3699

3700
    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);
3701

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

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

3713 3714 3715 3716
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
3717 3718
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is already running"));
3719 3720 3721
        goto endjob;
    }

3722 3723
    ret = qemudDomainObjStart(dom->conn, driver, vm,
                              (flags & VIR_DOMAIN_START_PAUSED) != 0);
3724

3725
endjob:
3726 3727
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
3728

3729
cleanup:
3730 3731
    if (vm)
        virDomainObjUnlock(vm);
3732
    qemuDriverUnlock(driver);
3733
    return ret;
D
Daniel P. Berrange 已提交
3734 3735
}

3736 3737 3738 3739 3740 3741
static int
qemudDomainStart(virDomainPtr dom)
{
    return qemudDomainStartWithFlags(dom, 0);
}

3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756
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;

3757
        if (STRNEQ(def->os.machine, machine->name))
3758 3759 3760
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
3761
            virReportOOMError();
3762 3763 3764 3765 3766 3767 3768 3769 3770
            return -1;
        }

        break;
    }

    return 0;
}

3771 3772 3773 3774 3775 3776
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
    int i, nmachines = 0;

3777
    if (qemuCapsProbeMachineTypes(def->emulator, &machines, &nmachines) < 0)
3778 3779 3780 3781 3782 3783
        return -1;

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

3784
        if (STRNEQ(def->os.machine, machines[i]->name))
3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

3797 3798
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
3799 3800 3801 3802 3803 3804
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
3805
        virCapsGuestDomainInfoPtr info;
3806 3807 3808
        int j;

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

3811 3812 3813 3814 3815 3816 3817 3818 3819
            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;
3820 3821
        }

3822 3823 3824 3825
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
3826 3827 3828 3829
                return -1;
            goto out;
        }
    }
3830 3831 3832 3833

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

3834 3835 3836 3837 3838 3839 3840
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
3841

3842
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
3843
    struct qemud_driver *driver = conn->privateData;
3844
    virDomainDefPtr def;
3845
    virDomainObjPtr vm = NULL;
3846
    virDomainPtr dom = NULL;
3847
    virDomainEventPtr event = NULL;
3848
    int dupVM;
3849

3850
    qemuDriverLock(driver);
3851
    if (!(def = virDomainDefParseString(driver->caps, xml,
3852
                                        VIR_DOMAIN_XML_INACTIVE)))
3853
        goto cleanup;
3854

3855
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
3856 3857
        goto cleanup;

3858 3859
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
3860

3861
    if (qemudCanonicalizeMachine(driver, def) < 0)
3862 3863
        goto cleanup;

3864
    if (qemuDomainAssignPCIAddresses(def) < 0)
3865 3866
        goto cleanup;

3867
    if (!(vm = virDomainAssignDef(driver->caps,
3868
                                  &driver->domains,
3869
                                  def, false))) {
3870
        goto cleanup;
3871
    }
3872
    def = NULL;
3873
    vm->persistent = 1;
3874

3875
    if (virDomainSaveConfig(driver->configDir,
3876
                            vm->newDef ? vm->newDef : vm->def) < 0) {
3877 3878
        virDomainRemoveInactive(&driver->domains,
                                vm);
3879
        vm = NULL;
3880
        goto cleanup;
3881 3882
    }

3883 3884
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
3885
                                     !dupVM ?
3886 3887
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
3888

3889
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
3890
    if (dom) dom->id = vm->def->id;
3891 3892

cleanup:
3893
    virDomainDefFree(def);
3894 3895
    if (vm)
        virDomainObjUnlock(vm);
3896 3897
    if (event)
        qemuDomainEventQueue(driver, event);
3898
    qemuDriverUnlock(driver);
3899
    return dom;
D
Daniel P. Berrange 已提交
3900 3901
}

3902
static int qemudDomainUndefine(virDomainPtr dom) {
3903 3904
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3905
    virDomainEventPtr event = NULL;
3906
    int ret = -1;
D
Daniel P. Berrange 已提交
3907

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

D
Daniel P. Berrange 已提交
3911
    if (!vm) {
3912 3913
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3914 3915
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
3916
        goto cleanup;
D
Daniel P. Berrange 已提交
3917 3918
    }

D
Daniel P. Berrange 已提交
3919
    if (virDomainObjIsActive(vm)) {
3920 3921
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot delete active domain"));
3922
        goto cleanup;
D
Daniel P. Berrange 已提交
3923 3924
    }

3925
    if (!vm->persistent) {
3926
        qemuReportError(VIR_ERR_OPERATION_INVALID,
3927
                        "%s", _("cannot undefine transient domain"));
3928
        goto cleanup;
3929 3930
    }

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

3934 3935 3936
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
3937

3938 3939
    virDomainRemoveInactive(&driver->domains,
                            vm);
3940
    vm = NULL;
3941
    ret = 0;
D
Daniel P. Berrange 已提交
3942

3943
cleanup:
3944 3945
    if (vm)
        virDomainObjUnlock(vm);
3946 3947
    if (event)
        qemuDomainEventQueue(driver, event);
3948
    qemuDriverUnlock(driver);
3949
    return ret;
D
Daniel P. Berrange 已提交
3950 3951
}

3952

3953 3954
static int qemudDomainAttachDevice(virDomainPtr dom,
                                   const char *xml)
3955
{
3956 3957 3958
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
3959
    virBitmapPtr qemuCaps = NULL;
3960
    virCgroupPtr cgroup = NULL;
3961
    int ret = -1;
3962

3963 3964 3965 3966 3967 3968 3969
    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);
3970 3971 3972
        goto cleanup;
    }

3973 3974
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
3975

3976 3977 3978 3979 3980
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot attach device on inactive domain"));
        goto endjob;
    }
3981

3982 3983 3984 3985
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto endjob;
3986

3987
    if (qemuCapsExtractVersionInfo(vm->def->emulator, vm->def->os.arch,
3988
                                   NULL,
3989
                                   &qemuCaps) < 0)
3990
        goto endjob;
3991

3992 3993 3994 3995
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
3996
                                _("Unable to find cgroup for %s"),
3997 3998 3999
                                vm->def->name);
                goto endjob;
            }
4000
            if (qemuSetupDiskCgroup(driver, vm, cgroup, dev->data.disk) < 0)
4001
                goto endjob;
4002 4003
        }

4004 4005 4006 4007 4008
        switch (dev->data.disk->device) {
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
            ret = qemuDomainChangeEjectableMedia(driver, vm,
                                                 dev->data.disk,
4009
                                                 qemuCaps,
4010 4011 4012 4013
                                                 false);
            if (ret == 0)
                dev->data.disk = NULL;
            break;
4014

4015 4016 4017
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
                ret = qemuDomainAttachUsbMassstorageDevice(driver, vm,
4018
                                                           dev->data.disk, qemuCaps);
4019 4020 4021 4022
                if (ret == 0)
                    dev->data.disk = NULL;
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
                ret = qemuDomainAttachPciDiskDevice(driver, vm,
4023
                                                    dev->data.disk, qemuCaps);
4024 4025 4026 4027
                if (ret == 0)
                    dev->data.disk = NULL;
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
                ret = qemuDomainAttachSCSIDisk(driver, vm,
4028
                                               dev->data.disk, qemuCaps);
4029 4030 4031 4032 4033 4034 4035 4036 4037
                if (ret == 0)
                    dev->data.disk = NULL;
            } else {
                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                _("disk bus '%s' cannot be hotplugged."),
                                virDomainDiskBusTypeToString(dev->data.disk->bus));
                /* fallthrough */
            }
            break;
4038

4039 4040 4041 4042 4043
        default:
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                            _("disk device type '%s' cannot be hotplugged"),
                            virDomainDiskDeviceTypeToString(dev->data.disk->device));
            /* Fallthrough */
4044
        }
4045
        if (ret != 0 && cgroup) {
4046
            if (qemuTeardownDiskCgroup(driver, vm, cgroup, dev->data.disk) < 0)
4047 4048
                VIR_WARN("Failed to teardown cgroup for disk path %s",
                         NULLSTR(dev->data.disk->src));
4049
        }
4050 4051 4052
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
            ret = qemuDomainAttachPciControllerDevice(driver, vm,
4053
                                                      dev->data.controller, qemuCaps);
4054 4055 4056 4057 4058 4059 4060
            if (ret == 0)
                dev->data.controller = NULL;
        } else {
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                            _("disk controller bus '%s' cannot be hotplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
            /* fallthrough */
4061
        }
4062 4063
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
4064
                                        dev->data.net, qemuCaps);
4065 4066 4067 4068
        if (ret == 0)
            dev->data.net = NULL;
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        ret = qemuDomainAttachHostDevice(driver, vm,
4069
                                         dev->data.hostdev, qemuCaps);
4070 4071
        if (ret == 0)
            dev->data.hostdev = NULL;
4072
    } else {
4073 4074 4075 4076
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("device type '%s' cannot be attached"),
                        virDomainDeviceTypeToString(dev->type));
        goto endjob;
4077 4078
    }

4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        ret = -1;

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

cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);

4090
    qemuCapsFree(qemuCaps);
4091 4092 4093 4094
    virDomainDeviceDefFree(dev);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
4095 4096 4097
    return ret;
}

4098 4099 4100 4101 4102 4103 4104 4105
static int qemudDomainAttachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
        return -1;
    }
4106

4107 4108
    return qemudDomainAttachDevice(dom, xml);
}
4109

4110

4111 4112 4113 4114 4115 4116 4117
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
4118
    virBitmapPtr qemuCaps = NULL;
4119 4120 4121
    virCgroupPtr cgroup = NULL;
    int ret = -1;
    bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
4122

4123 4124 4125 4126
    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_CURRENT |
                  VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG |
                  VIR_DOMAIN_DEVICE_MODIFY_FORCE, -1);
4127

4128 4129 4130
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
4131 4132 4133
        return -1;
    }

4134 4135 4136 4137 4138 4139 4140 4141
    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;
4142 4143
    }

4144 4145 4146 4147 4148 4149 4150
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot attach device on inactive domain"));
        goto endjob;
4151 4152
    }

4153 4154 4155 4156 4157
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto endjob;

4158
    if (qemuCapsExtractVersionInfo(vm->def->emulator, vm->def->os.arch,
4159
                                   NULL,
4160
                                   &qemuCaps) < 0)
4161
        goto endjob;
4162

4163 4164 4165 4166 4167
    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
4168
                                _("Unable to find cgroup for %s"),
4169 4170 4171
                                vm->def->name);
                goto endjob;
            }
4172
            if (qemuSetupDiskCgroup(driver, vm, cgroup, dev->data.disk) < 0)
4173
                goto endjob;
4174 4175
        }

4176 4177 4178 4179 4180
        switch (dev->data.disk->device) {
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
            ret = qemuDomainChangeEjectableMedia(driver, vm,
                                                 dev->data.disk,
4181
                                                 qemuCaps,
4182 4183 4184 4185
                                                 force);
            if (ret == 0)
                dev->data.disk = NULL;
            break;
4186

4187

4188 4189 4190 4191 4192 4193
        default:
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                            _("disk bus '%s' cannot be updated."),
                            virDomainDiskBusTypeToString(dev->data.disk->bus));
            break;
        }
4194

4195
        if (ret != 0 && cgroup) {
4196
            if (qemuTeardownDiskCgroup(driver, vm, cgroup, dev->data.disk) < 0)
4197 4198 4199
                VIR_WARN("Failed to teardown cgroup for disk path %s",
                         NULLSTR(dev->data.disk->src));
        }
4200
        break;
4201 4202 4203

    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
4204
        break;
4205

4206
    default:
4207
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4208 4209
                        _("device type '%s' cannot be updated"),
                        virDomainDeviceTypeToString(dev->type));
4210
        break;
4211 4212
    }

4213 4214 4215 4216 4217 4218 4219 4220 4221 4222
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        ret = -1;

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

cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);
4223

4224
    qemuCapsFree(qemuCaps);
4225 4226 4227 4228
    virDomainDeviceDefFree(dev);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
4229 4230 4231
    return ret;
}

4232

4233 4234
static int qemudDomainDetachDevice(virDomainPtr dom,
                                   const char *xml) {
4235 4236
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4237
    virBitmapPtr qemuCaps = NULL;
4238 4239
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;
4240

4241
    qemuDriverLock(driver);
4242
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4243
    if (!vm) {
4244 4245
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4246 4247
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4248
        goto cleanup;
4249 4250
    }

4251 4252 4253
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
4254
    if (!virDomainObjIsActive(vm)) {
4255 4256
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot detach device on inactive domain"));
4257
        goto endjob;
4258 4259
    }

4260
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
4261
                                  VIR_DOMAIN_XML_INACTIVE);
4262
    if (dev == NULL)
4263
        goto endjob;
4264

4265
    if (qemuCapsExtractVersionInfo(vm->def->emulator, vm->def->os.arch,
4266
                                   NULL,
4267
                                   &qemuCaps) < 0)
4268
        goto endjob;
4269 4270

    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
4271 4272
        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
        if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
4273
            ret = qemuDomainDetachPciDiskDevice(driver, vm, dev, qemuCaps);
4274 4275
        }
        else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
4276
            ret = qemuDomainDetachDiskDevice(driver, vm, dev, qemuCaps);
W
Wen Congyang 已提交
4277 4278
        } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
            ret = qemuDomainDetachDiskDevice(driver, vm, dev, qemuCaps);
4279 4280
        }
        else {
4281
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
4282 4283
                            _("This type of disk cannot be hot unplugged"));
        }
4284
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
4285
        ret = qemuDomainDetachNetDevice(driver, vm, dev, qemuCaps);
4286 4287
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
4288
            ret = qemuDomainDetachPciControllerDevice(driver, vm, dev,
4289
                                                      qemuCaps);
4290
        } else {
4291
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4292 4293
                            _("disk controller bus '%s' cannot be hotunplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
4294 4295
            /* fallthrough */
        }
4296
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
4297
        ret = qemuDomainDetachHostDevice(driver, vm, dev, qemuCaps);
4298
    } else {
4299
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4300
                        "%s", _("This type of device cannot be hot unplugged"));
4301
    }
4302

4303
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
4304 4305
        ret = -1;

4306
endjob:
4307 4308
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4309

4310
cleanup:
4311
    qemuCapsFree(qemuCaps);
4312
    virDomainDeviceDefFree(dev);
4313 4314
    if (vm)
        virDomainObjUnlock(vm);
4315
    qemuDriverUnlock(driver);
4316 4317 4318
    return ret;
}

4319 4320 4321 4322
static int qemudDomainDetachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
4323 4324
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
4325 4326 4327 4328 4329 4330
        return -1;
    }

    return qemudDomainDetachDevice(dom, xml);
}

4331
static int qemudDomainGetAutostart(virDomainPtr dom,
4332
                                   int *autostart) {
4333 4334 4335
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4336

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

4341
    if (!vm) {
4342 4343
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4344 4345
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4346
        goto cleanup;
4347 4348 4349
    }

    *autostart = vm->autostart;
4350
    ret = 0;
4351

4352
cleanup:
4353 4354
    if (vm)
        virDomainObjUnlock(vm);
4355
    return ret;
4356 4357
}

4358
static int qemudDomainSetAutostart(virDomainPtr dom,
4359
                                   int autostart) {
4360 4361
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4362 4363
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
4364

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

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

4376
    if (!vm->persistent) {
4377
        qemuReportError(VIR_ERR_OPERATION_INVALID,
4378
                        "%s", _("cannot set autostart for transient domain"));
4379
        goto cleanup;
4380 4381
    }

4382 4383
    autostart = (autostart != 0);

4384
    if (vm->autostart != autostart) {
4385
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
4386
            goto cleanup;
4387
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
4388
            goto cleanup;
4389

4390 4391
        if (autostart) {
            int err;
4392

4393
            if ((err = virFileMakePath(driver->autostartDir))) {
4394
                virReportSystemError(err,
4395 4396
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
4397 4398
                goto cleanup;
            }
4399

4400
            if (symlink(configFile, autostartLink) < 0) {
4401
                virReportSystemError(errno,
4402 4403
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
4404 4405 4406 4407
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4408
                virReportSystemError(errno,
4409 4410
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
4411 4412
                goto cleanup;
            }
4413 4414
        }

4415
        vm->autostart = autostart;
4416
    }
4417
    ret = 0;
4418

4419 4420 4421
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4422 4423
    if (vm)
        virDomainObjUnlock(vm);
4424
    qemuDriverUnlock(driver);
4425
    return ret;
4426 4427
}

4428 4429 4430 4431 4432

static char *qemuGetSchedulerType(virDomainPtr dom,
                                  int *nparams)
{
    struct qemud_driver *driver = dom->conn->privateData;
4433
    char *ret = NULL;
4434

4435
    qemuDriverLock(driver);
4436
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
4437 4438
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup CPU controller is not mounted"));
4439
        goto cleanup;
4440 4441 4442 4443 4444 4445 4446
    }

    if (nparams)
        *nparams = 1;

    ret = strdup("posix");
    if (!ret)
4447
        virReportOOMError();
4448 4449 4450

cleanup:
    qemuDriverUnlock(driver);
4451 4452 4453
    return ret;
}

4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467

static int qemuDomainSetMemoryParameters(virDomainPtr dom,
                                         virMemoryParameterPtr params,
                                         int nparams,
                                         unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

    qemuDriverLock(driver);
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
4468 4469
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup memory controller is not mounted"));
4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520
        goto cleanup;
    }

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

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

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

    ret = 0;
    for (i = 0; i < nparams; i++) {
        virMemoryParameterPtr param = &params[i];

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

            rc = virCgroupSetMemoryHardLimit(group, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory hard_limit tunable"));
                ret = -1;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
            int rc;
            if (param->type != VIR_DOMAIN_MEMORY_PARAM_ULLONG) {
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for memory soft_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

            rc = virCgroupSetMemorySoftLimit(group, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory soft_limit tunable"));
                ret = -1;
            }
4521
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554
            int rc;
            if (param->type != VIR_DOMAIN_MEMORY_PARAM_ULLONG) {
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for swap_hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

            rc = virCgroupSetSwapHardLimit(group, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set swap_hard_limit tunable"));
                ret = -1;
            }
        } 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;
        }
    }

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

4555 4556 4557 4558 4559 4560 4561 4562 4563
static int qemuDomainGetMemoryParameters(virDomainPtr dom,
                                         virMemoryParameterPtr params,
                                         int *nparams,
                                         unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
4564
    unsigned long long val;
4565 4566 4567 4568 4569 4570
    int ret = -1;
    int rc;

    qemuDriverLock(driver);

    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
4571 4572
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup memory controller is not mounted"));
4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614
        goto cleanup;
    }

    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 memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

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

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

    for (i = 0; i < *nparams; i++) {
        virMemoryParameterPtr param = &params[i];
        val = 0;
        param->value.ul = 0;
        param->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG;

        switch(i) {
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
4615
                goto cleanup;
4616 4617 4618 4619
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field memory hard limit too long for destination"));
4620
                goto cleanup;
4621 4622 4623 4624 4625 4626 4627 4628 4629
            }
            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"));
4630
                goto cleanup;
4631 4632 4633 4634
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field memory soft limit too long for destination"));
4635
                goto cleanup;
4636 4637 4638 4639 4640 4641 4642 4643 4644
            }
            param->value.ul = val;
            break;

        case 2: /* fill swap hard limit here */
            rc = virCgroupGetSwapHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
4645
                goto cleanup;
4646
            }
4647
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT) == NULL) {
4648 4649
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field swap hard limit too long for destination"));
4650
                goto cleanup;
4651 4652 4653 4654 4655 4656 4657 4658 4659 4660
            }
            param->value.ul = val;
            break;

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

4661 4662
    ret = 0;

4663 4664 4665 4666 4667 4668 4669 4670 4671
cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

4672 4673 4674 4675 4676 4677 4678 4679 4680 4681
static int qemuSetSchedulerParameters(virDomainPtr dom,
                                      virSchedParameterPtr params,
                                      int nparams)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

4682
    qemuDriverLock(driver);
4683
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
4684 4685
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup CPU controller is not mounted"));
4686
        goto cleanup;
4687 4688 4689 4690 4691
    }

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

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

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
4698 4699
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
4700 4701 4702 4703 4704 4705 4706 4707 4708
        goto cleanup;
    }

    for (i = 0; i < nparams; i++) {
        virSchedParameterPtr param = &params[i];

        if (STREQ(param->field, "cpu_shares")) {
            int rc;
            if (param->type != VIR_DOMAIN_SCHED_FIELD_ULLONG) {
4709 4710
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for cpu_shares tunable, expected a 'ullong'"));
4711 4712 4713 4714 4715
                goto cleanup;
            }

            rc = virCgroupSetCpuShares(group, params[i].value.ul);
            if (rc != 0) {
4716
                virReportSystemError(-rc, "%s",
4717 4718 4719 4720
                                     _("unable to set cpu shares tunable"));
                goto cleanup;
            }
        } else {
4721 4722
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Invalid parameter `%s'"), param->field);
4723 4724 4725 4726 4727 4728 4729 4730 4731
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
4732
    qemuDriverUnlock(driver);
4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746
    return ret;
}

static int qemuGetSchedulerParameters(virDomainPtr dom,
                                      virSchedParameterPtr params,
                                      int *nparams)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    unsigned long long val;
    int ret = -1;
    int rc;

4747
    qemuDriverLock(driver);
4748
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
4749 4750
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cgroup CPU controller is not mounted"));
4751
        goto cleanup;
4752 4753 4754
    }

    if ((*nparams) != 1) {
4755 4756
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
4757
        goto cleanup;
4758 4759 4760 4761 4762
    }

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

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

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

    rc = virCgroupGetCpuShares(group, &val);
    if (rc != 0) {
4776
        virReportSystemError(-rc, "%s",
4777 4778 4779 4780 4781
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
    params[0].value.ul = val;
    params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
C
Chris Lalancette 已提交
4782
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
4783 4784
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Field cpu_shares too long for destination"));
C
Chris Lalancette 已提交
4785 4786
        goto cleanup;
    }
4787 4788 4789 4790 4791 4792 4793

    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
4794
    qemuDriverUnlock(driver);
4795 4796 4797 4798
    return ret;
}


4799 4800 4801 4802 4803 4804 4805 4806 4807
/* 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)
{
4808
    struct qemud_driver *driver = dom->conn->privateData;
4809
    int i, ret = -1;
4810
    virDomainObjPtr vm;
4811
    virDomainDiskDefPtr disk = NULL;
4812

4813
    qemuDriverLock(driver);
4814
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4815
    qemuDriverUnlock(driver);
4816
    if (!vm) {
4817 4818
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4819 4820
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4821
        goto cleanup;
4822
    }
4823 4824 4825 4826

    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
4827
    if (!virDomainObjIsActive (vm)) {
4828 4829
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4830
        goto endjob;
4831 4832
    }

4833 4834 4835 4836 4837 4838 4839 4840
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
4841 4842
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path: %s"), path);
4843
        goto endjob;
4844 4845
    }

4846
    if (!disk->info.alias) {
4847 4848
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), disk->dst);
4849
        goto endjob;
4850
    }
4851

4852
    qemuDomainObjPrivatePtr priv = vm->privateData;
4853 4854
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
4855
                                       disk->info.alias,
4856 4857 4858 4859 4860 4861
                                       &stats->rd_req,
                                       &stats->rd_bytes,
                                       &stats->wr_req,
                                       &stats->wr_bytes,
                                       &stats->errs);
    qemuDomainObjExitMonitor(vm);
4862

4863
endjob:
4864 4865
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4866

4867
cleanup:
4868 4869
    if (vm)
        virDomainObjUnlock(vm);
4870
    return ret;
4871 4872
}

4873
#ifdef __linux__
4874 4875 4876 4877 4878
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
4879 4880
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4881
    int i;
4882
    int ret = -1;
4883

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

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

D
Daniel P. Berrange 已提交
4896
    if (!virDomainObjIsActive(vm)) {
4897 4898
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4899
        goto cleanup;
4900 4901 4902
    }

    /* Check the path is one of the domain's network interfaces. */
4903 4904
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
4905 4906 4907 4908
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
4909 4910
    }

4911
    if (ret == 0)
4912
        ret = linuxDomainInterfaceStats(path, stats);
4913
    else
4914 4915
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path, '%s' is not a known interface"), path);
4916

4917
cleanup:
4918 4919
    if (vm)
        virDomainObjUnlock(vm);
4920 4921
    return ret;
}
4922
#else
4923 4924 4925 4926
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
4927 4928
    qemuReportError(VIR_ERR_NO_SUPPORT,
                    "%s", __FUNCTION__);
4929 4930
    return -1;
}
4931
#endif
4932

4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948
static int
qemudDomainMemoryStats (virDomainPtr dom,
                        struct _virDomainMemoryStat *stats,
                        unsigned int nr_stats)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned int ret = -1;

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

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

4954 4955 4956
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

4957 4958 4959
    if (virDomainObjIsActive(vm)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        qemuDomainObjEnterMonitor(vm);
4960
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
4961 4962
        qemuDomainObjExitMonitor(vm);
    } else {
4963 4964
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4965 4966
    }

4967 4968 4969
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

4970 4971 4972 4973 4974 4975
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

4976 4977 4978 4979 4980 4981 4982
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
4983 4984 4985
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
4986

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

4991
    if (!vm) {
4992 4993
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4994 4995
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4996
        goto cleanup;
4997 4998 4999
    }

    if (!path || path[0] == '\0') {
5000 5001
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("NULL or empty path"));
5002
        goto cleanup;
5003 5004 5005
    }

    /* Check the path belongs to this domain. */
5006 5007
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
5008 5009 5010 5011
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
5012 5013
    }

5014 5015 5016 5017 5018
    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) {
5019 5020
            virReportSystemError(errno,
                                 _("%s: failed to open"), path);
5021 5022
            goto cleanup;
        }
5023

5024 5025 5026 5027 5028 5029
        /* 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) {
5030 5031
            virReportSystemError(errno,
                                 _("%s: failed to seek or read"), path);
5032 5033 5034 5035 5036
            goto cleanup;
        }

        ret = 0;
    } else {
5037 5038
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("invalid path"));
5039 5040
    }

5041
cleanup:
5042
    VIR_FORCE_CLOSE(fd);
5043 5044
    if (vm)
        virDomainObjUnlock(vm);
5045 5046 5047
    return ret;
}

R
Richard W.M. Jones 已提交
5048 5049 5050 5051 5052 5053
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
5054 5055
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5056
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
5057 5058
    int fd = -1, ret = -1;

5059
    qemuDriverLock(driver);
5060
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5061
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
5062 5063

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

5071
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
5072 5073
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
5074
        goto cleanup;
R
Richard W.M. Jones 已提交
5075 5076
    }

5077 5078 5079
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
5080
    if (!virDomainObjIsActive(vm)) {
5081 5082
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
5083
        goto endjob;
R
Richard W.M. Jones 已提交
5084 5085
    }

5086
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", driver->cacheDir) < 0) {
5087
        virReportOOMError();
5088
        goto endjob;
5089 5090
    }

R
Richard W.M. Jones 已提交
5091 5092
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
5093 5094
        virReportSystemError(errno,
                             _("mkstemp(\"%s\") failed"), tmp);
5095
        goto endjob;
R
Richard W.M. Jones 已提交
5096 5097
    }

5098
    qemuDomainObjPrivatePtr priv = vm->privateData;
5099
    qemuDomainObjEnterMonitor(vm);
5100
    if (flags == VIR_MEMORY_VIRTUAL) {
5101 5102
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
5103
            goto endjob;
5104
        }
5105
    } else {
5106 5107
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
5108
            goto endjob;
5109
        }
R
Richard W.M. Jones 已提交
5110
    }
5111
    qemuDomainObjExitMonitor(vm);
R
Richard W.M. Jones 已提交
5112 5113 5114

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
5115 5116 5117
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
5118
        goto endjob;
R
Richard W.M. Jones 已提交
5119 5120 5121
    }

    ret = 0;
5122

5123
endjob:
5124 5125
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5126

5127
cleanup:
5128
    VIR_FREE(tmp);
5129
    VIR_FORCE_CLOSE(fd);
R
Richard W.M. Jones 已提交
5130
    unlink (tmp);
5131 5132
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
5133 5134 5135
    return ret;
}

5136

5137 5138 5139 5140 5141 5142 5143 5144 5145 5146
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;
    virStorageFileMetadata meta;
5147
    virDomainDiskDefPtr disk = NULL;
5148 5149
    struct stat sb;
    int i;
5150
    int format;
5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174

    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)) {
5175
            disk = vm->def->disks[i];
5176 5177 5178 5179
            break;
        }
    }

5180
    if (!disk) {
5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194
        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 */
5195 5196 5197 5198 5199 5200 5201 5202
    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 {
5203 5204 5205 5206 5207 5208 5209
        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);
5210
            goto cleanup;
5211
        }
5212 5213 5214 5215 5216
    }

    if (virStorageFileGetMetadataFromFD(path, fd,
                                        format,
                                        &meta) < 0)
5217 5218 5219 5220 5221 5222 5223 5224 5225 5226
        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)) {
5227
#ifndef WIN32
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 5253 5254 5255
        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 */
    if (meta.capacity)
        info->capacity = meta.capacity;

5256
    /* Set default value .. */
5257 5258
    info->allocation = info->physical;

5259 5260 5261
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
5262
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
5263
        format != VIR_STORAGE_FILE_RAW &&
5264 5265 5266 5267
        S_ISBLK(sb.st_mode)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        if (qemuDomainObjBeginJob(vm) < 0)
            goto cleanup;
5268 5269 5270 5271 5272 5273 5274 5275 5276
        if (!virDomainObjIsActive(vm))
            ret = 0;
        else {
            qemuDomainObjEnterMonitor(vm);
            ret = qemuMonitorGetBlockExtent(priv->mon,
                                            disk->info.alias,
                                            &info->allocation);
            qemuDomainObjExitMonitor(vm);
        }
5277 5278 5279 5280 5281 5282

        if (qemuDomainObjEndJob(vm) == 0)
            vm = NULL;
    } else {
        ret = 0;
    }
5283 5284

cleanup:
5285
    VIR_FORCE_CLOSE(fd);
5286 5287 5288 5289 5290 5291
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


5292
static int
5293 5294 5295 5296
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
5297
{
5298 5299 5300
    struct qemud_driver *driver = conn->privateData;
    int ret;

5301
    qemuDriverLock(driver);
5302 5303
    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
                                        callback, opaque, freecb);
5304
    qemuDriverUnlock(driver);
5305

5306
    return ret;
5307 5308
}

5309

5310
static int
5311 5312
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
5313
{
5314 5315 5316
    struct qemud_driver *driver = conn->privateData;
    int ret;

5317
    qemuDriverLock(driver);
5318 5319 5320 5321 5322 5323
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
                                               callback);
5324
    qemuDriverUnlock(driver);
5325

5326
    return ret;
5327 5328
}

5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371

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,
                                          driver->domainEventCallbacks,
                                          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);
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDeleteID(conn, driver->domainEventCallbacks,
                                                     callbackID);
    else
        ret = virDomainEventCallbackListRemoveID(conn, driver->domainEventCallbacks,
                                                 callbackID);
    qemuDriverUnlock(driver);

    return ret;
}


D
Daniel Veillard 已提交
5372 5373
/* Migration support. */

C
Chris Lalancette 已提交
5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388
/* 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;
5389

C
Chris Lalancette 已提交
5390
    if (!dom_xml) {
5391 5392
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
5393 5394 5395
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
5396
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
5397 5398 5399 5400
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
5401 5402
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
5403 5404 5405
        goto cleanup;
    }

5406 5407 5408 5409
    qemuDriverLock(driver);
    ret = qemuMigrationPrepareTunnel(driver, dconn, st,
                                     dname, dom_xml);
    qemuDriverUnlock(driver);
5410

C
Chris Lalancette 已提交
5411 5412 5413 5414
cleanup:
    return ret;
}

D
Daniel Veillard 已提交
5415 5416 5417 5418
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
5419
static int ATTRIBUTE_NONNULL (5)
D
Daniel Veillard 已提交
5420 5421 5422 5423 5424
qemudDomainMigratePrepare2 (virConnectPtr dconn,
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
5425
                            unsigned long flags,
D
Daniel Veillard 已提交
5426 5427 5428 5429
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
5430
    struct qemud_driver *driver = dconn->privateData;
5431
    int ret = -1;
5432

C
Chris Lalancette 已提交
5433 5434 5435 5436 5437 5438 5439 5440 5441
    virCheckFlags(VIR_MIGRATE_LIVE |
                  VIR_MIGRATE_PEER2PEER |
                  VIR_MIGRATE_TUNNELLED |
                  VIR_MIGRATE_PERSIST_DEST |
                  VIR_MIGRATE_UNDEFINE_SOURCE |
                  VIR_MIGRATE_PAUSED |
                  VIR_MIGRATE_NON_SHARED_DISK |
                  VIR_MIGRATE_NON_SHARED_INC, -1);

5442
    *uri_out = NULL;
D
Daniel Veillard 已提交
5443

5444
    qemuDriverLock(driver);
C
Chris Lalancette 已提交
5445 5446 5447 5448
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
5449 5450
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
5451 5452 5453
        goto cleanup;
    }

D
Daniel Veillard 已提交
5454
    if (!dom_xml) {
5455 5456
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
5457
        goto cleanup;
D
Daniel Veillard 已提交
5458 5459
    }

5460 5461 5462
    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     uri_in, uri_out,
                                     dname, dom_xml);
D
Daniel Veillard 已提交
5463

5464 5465 5466 5467
cleanup:
    qemuDriverUnlock(driver);
    return ret;
}
C
Chris Lalancette 已提交
5468

D
Daniel Veillard 已提交
5469

5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482
/* Perform is the second step, and it runs on the source host. */
static int
qemudDomainMigratePerform (virDomainPtr dom,
                           const char *cookie ATTRIBUTE_UNUSED,
                           int cookielen ATTRIBUTE_UNUSED,
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5483

5484 5485 5486 5487 5488 5489 5490 5491
    virCheckFlags(VIR_MIGRATE_LIVE |
                  VIR_MIGRATE_PEER2PEER |
                  VIR_MIGRATE_TUNNELLED |
                  VIR_MIGRATE_PERSIST_DEST |
                  VIR_MIGRATE_UNDEFINE_SOURCE |
                  VIR_MIGRATE_PAUSED |
                  VIR_MIGRATE_NON_SHARED_DISK |
                  VIR_MIGRATE_NON_SHARED_INC, -1);
C
Chris Lalancette 已提交
5492

5493
    qemuDriverLock(driver);
5494
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
5495
    if (!vm) {
5496 5497
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5498 5499
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5500
        goto cleanup;
D
Daniel Veillard 已提交
5501 5502
    }

5503 5504 5505
    ret = qemuMigrationPerform(driver, dom->conn, vm,
                               uri, flags,
                               dname, resource);
5506

5507
cleanup:
5508
    qemuDriverUnlock(driver);
5509
    return ret;
D
Daniel Veillard 已提交
5510 5511
}

5512

D
Daniel Veillard 已提交
5513 5514 5515 5516 5517 5518 5519
/* 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 已提交
5520
                           unsigned long flags,
D
Daniel Veillard 已提交
5521 5522
                           int retcode)
{
5523 5524 5525
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
5526
    virErrorPtr orig_err;
D
Daniel Veillard 已提交
5527

C
Chris Lalancette 已提交
5528 5529 5530 5531 5532 5533 5534 5535 5536
    virCheckFlags(VIR_MIGRATE_LIVE |
                  VIR_MIGRATE_PEER2PEER |
                  VIR_MIGRATE_TUNNELLED |
                  VIR_MIGRATE_PERSIST_DEST |
                  VIR_MIGRATE_UNDEFINE_SOURCE |
                  VIR_MIGRATE_PAUSED |
                  VIR_MIGRATE_NON_SHARED_DISK |
                  VIR_MIGRATE_NON_SHARED_INC, NULL);

5537 5538 5539
    /* Migration failed. Save the current error so nothing squashes it */
    orig_err = virSaveLastError();

5540
    qemuDriverLock(driver);
5541
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
5542
    if (!vm) {
5543 5544
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
5545
        goto cleanup;
D
Daniel Veillard 已提交
5546 5547
    }

5548
    dom = qemuMigrationFinish(driver, dconn, vm, flags, retcode);
5549

5550
cleanup:
5551 5552 5553 5554
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
5555
    qemuDriverUnlock(driver);
5556
    return dom;
D
Daniel Veillard 已提交
5557 5558
}

5559

5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575
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;

5576
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE);
5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593
    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) {
5594 5595
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("device %s is not a PCI device"), dev->name);
5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
qemudNodeDeviceDettach (virNodeDevicePtr dev)
{
5609
    struct qemud_driver *driver = dev->conn->privateData;
5610 5611 5612 5613 5614 5615 5616
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

5617
    pci = pciGetDevice(domain, bus, slot, function);
5618 5619 5620
    if (!pci)
        return -1;

5621 5622
    qemuDriverLock(driver);
    if (pciDettachDevice(pci, driver->activePciHostdevs) < 0)
5623 5624 5625 5626
        goto out;

    ret = 0;
out:
5627
    qemuDriverUnlock(driver);
5628
    pciFreeDevice(pci);
5629 5630 5631 5632 5633 5634
    return ret;
}

static int
qemudNodeDeviceReAttach (virNodeDevicePtr dev)
{
5635
    struct qemud_driver *driver = dev->conn->privateData;
5636 5637 5638 5639 5640 5641 5642
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

5643
    pci = pciGetDevice(domain, bus, slot, function);
5644 5645 5646
    if (!pci)
        return -1;

5647 5648
    qemuDriverLock(driver);
    if (pciReAttachDevice(pci, driver->activePciHostdevs) < 0)
5649 5650 5651 5652
        goto out;

    ret = 0;
out:
5653
    qemuDriverUnlock(driver);
5654
    pciFreeDevice(pci);
5655 5656 5657 5658 5659 5660
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
5661
    struct qemud_driver *driver = dev->conn->privateData;
5662 5663 5664 5665 5666 5667 5668
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

5669
    pci = pciGetDevice(domain, bus, slot, function);
5670 5671 5672
    if (!pci)
        return -1;

5673 5674
    qemuDriverLock(driver);

5675
    if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
5676 5677 5678 5679
        goto out;

    ret = 0;
out:
5680
    qemuDriverUnlock(driver);
5681
    pciFreeDevice(pci);
5682 5683 5684
    return ret;
}

5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695
static int
qemuCPUCompare(virConnectPtr conn,
               const char *xmlDesc,
               unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = conn->privateData;
    int ret = VIR_CPU_COMPARE_ERROR;

    qemuDriverLock(driver);

    if (!driver->caps || !driver->caps->host.cpu) {
5696 5697
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cannot get host CPU capabilities"));
5698 5699
    }
    else
5700
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
5701 5702 5703 5704 5705 5706

    qemuDriverUnlock(driver);

    return ret;
}

5707

5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720
static char *
qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED,
                const char **xmlCPUs,
                unsigned int ncpus,
                unsigned int flags ATTRIBUTE_UNUSED)
{
    char *cpu;

    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0);

    return cpu;
}

5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743

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)) {
        if (priv->jobActive) {
5744 5745
            struct timeval now;

5746
            memcpy(info, &priv->jobInfo, sizeof(*info));
5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757

            /* Refresh elapsed time again just to ensure it
             * is fully updated. This is primarily for benefit
             * of incoming migration which we don't currently
             * monitor actively in the background thread
             */
            if (gettimeofday(&now, NULL) < 0) {
                virReportSystemError(errno, "%s",
                                     _("cannot get time of day"));
                goto cleanup;
            }
5758
            info->timeElapsed = timeval_to_ms(now) - priv->jobStart;
5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777
        } 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;
}


5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799
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;
    }

    priv = vm->privateData;

    if (virDomainObjIsActive(vm)) {
        if (priv->jobActive) {
            VIR_DEBUG("Requesting cancellation of job on vm %s", vm->def->name);
5800
            priv->jobSignals |= QEMU_JOB_SIGNAL_CANCEL;
5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820
        } else {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("no job is active on the domain"));
            goto cleanup;
        }
    } else {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

    ret = 0;

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


5821 5822 5823 5824 5825 5826 5827 5828 5829 5830
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;

5831
    virCheckFlags(0, -1);
5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851

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

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

    priv = vm->privateData;

5852
    if (priv->jobActive != QEMU_JOB_MIGRATION_OUT) {
5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not being migrated"));
        goto cleanup;
    }

    VIR_DEBUG("Requesting migration downtime change to %llums", downtime);
    priv->jobSignals |= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME;
    priv->jobSignalsData.migrateDowntime = downtime;
    ret = 0;

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

C
Chris Lalancette 已提交
5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883
static char *qemuFindQemuImgBinary(void)
{
    char *ret;

    ret = virFindFileInPath("kvm-img");
    if (ret == NULL)
        ret = virFindFileInPath("qemu-img");
    if (ret == NULL)
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("unable to find kvm-img or qemu-img"));

    return ret;
}

5884 5885 5886
static int qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
                                           virDomainSnapshotObjPtr snapshot,
                                           char *snapshotDir)
C
Chris Lalancette 已提交
5887 5888 5889 5890 5891 5892 5893 5894 5895 5896
{
    int fd = -1;
    char *newxml = NULL;
    int ret = -1;
    char *snapDir = NULL;
    char *snapFile = NULL;
    int err;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    virUUIDFormat(vm->def->uuid, uuidstr);
5897
    newxml = virDomainSnapshotDefFormat(uuidstr, snapshot->def, 1);
C
Chris Lalancette 已提交
5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913
    if (newxml == NULL) {
        virReportOOMError();
        return -1;
    }

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

5914
    if (virAsprintf(&snapFile, "%s/%s.xml", snapDir, snapshot->def->name) < 0) {
C
Chris Lalancette 已提交
5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935
        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;
    }
    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);
5936
    VIR_FORCE_CLOSE(fd);
C
Chris Lalancette 已提交
5937 5938 5939
    return ret;
}

5940 5941
static int qemuDomainSnapshotSetCurrentActive(virDomainObjPtr vm,
                                              char *snapshotDir)
C
Chris Lalancette 已提交
5942 5943 5944 5945
{
    if (vm->current_snapshot) {
        vm->current_snapshot->def->active = 1;

5946 5947
        return qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                               snapshotDir);
C
Chris Lalancette 已提交
5948 5949 5950 5951 5952
    }

    return 0;
}

5953 5954
static int qemuDomainSnapshotSetCurrentInactive(virDomainObjPtr vm,
                                                char *snapshotDir)
C
Chris Lalancette 已提交
5955 5956 5957 5958
{
    if (vm->current_snapshot) {
        vm->current_snapshot->def->active = 0;

5959 5960
        return qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                               snapshotDir);
C
Chris Lalancette 已提交
5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979
    }

    return 0;
}


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,
5980 5981
                            _("Disk '%s' does not support snapshotting"),
                            vm->def->disks[i]->src);
C
Chris Lalancette 已提交
5982 5983 5984 5985 5986 5987 5988 5989 5990
            return 0;
        }
    }

    return 1;
}

static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
                                                        const char *xmlDesc,
5991
                                                        unsigned int flags)
C
Chris Lalancette 已提交
5992 5993 5994 5995 5996 5997 5998 5999 6000 6001
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainSnapshotDefPtr def;
    const char *qemuimgarg[] = { NULL, "snapshot", "-c", NULL, NULL, NULL };
    int i;

6002 6003
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060
    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;
    }

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

    if (!(def = virDomainSnapshotDefParseString(xmlDesc, 1)))
        goto cleanup;

    if (!(snap = virDomainSnapshotAssignDef(&vm->snapshots, def)))
        goto cleanup;

    /* actually do the snapshot */
    if (!virDomainObjIsActive(vm)) {
        qemuimgarg[0] = qemuFindQemuImgBinary();
        if (qemuimgarg[0] == NULL)
            /* qemuFindQemuImgBinary set the error */
            goto cleanup;

        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")) {
                    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) {
                    goto cleanup;
                }
            }
        }
    }
    else {
6061 6062 6063 6064 6065
        qemuDomainObjPrivatePtr priv;
        int ret;

        if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
            goto cleanup;
C
Chris Lalancette 已提交
6066 6067
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
6068
        ret = qemuMonitorCreateSnapshot(priv->mon, def->name);
C
Chris Lalancette 已提交
6069
        qemuDomainObjExitMonitorWithDriver(driver, vm);
6070
        if (qemuDomainObjEndJob(vm) == 0) {
6071
            vm = NULL;
6072 6073
            goto cleanup;
        }
6074 6075
        if (ret < 0)
            goto cleanup;
C
Chris Lalancette 已提交
6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095
    }

    snap->def->state = vm->state;

    /* FIXME: if we fail after this point, there's not a whole lot we can
     * do; we've successfully taken the snapshot, and we are now running
     * on it, so we have to go forward the best we can
     */

    if (vm->current_snapshot) {
        def->parent = strdup(vm->current_snapshot->def->name);
        if (def->parent == NULL) {
            virReportOOMError();
            goto cleanup;
        }
    }

    /* Now we set the new current_snapshot for the domain */
    vm->current_snapshot = snap;

6096 6097 6098
    if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                        driver->snapshotDir) < 0)
        /* qemuDomainSnapshotWriteMetadata set the error */
C
Chris Lalancette 已提交
6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112
        goto cleanup;

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
    VIR_FREE(qemuimgarg[0]);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
6113
                                       unsigned int flags)
C
Chris Lalancette 已提交
6114 6115 6116 6117 6118
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

6119 6120
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140
    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;
    }

    n = virDomainSnapshotObjListGetNames(&vm->snapshots, names, nameslen);

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

static int qemuDomainSnapshotNum(virDomainPtr domain,
6141
                                 unsigned int flags)
C
Chris Lalancette 已提交
6142 6143 6144 6145 6146
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

6147 6148
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169
    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;
    }

    n = virDomainSnapshotObjListNum(&vm->snapshots);

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

static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
6170
                                                           unsigned int flags)
C
Chris Lalancette 已提交
6171 6172 6173 6174 6175 6176
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

6177 6178
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205
    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,
6206
                                        unsigned int flags)
C
Chris Lalancette 已提交
6207 6208 6209 6210 6211
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

6212 6213
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233
    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,
6234
                                                      unsigned int flags)
C
Chris Lalancette 已提交
6235 6236 6237 6238 6239
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

6240 6241
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267
    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;
}

static char *qemuDomainSnapshotDumpXML(virDomainSnapshotPtr snapshot,
6268
                                       unsigned int flags)
C
Chris Lalancette 已提交
6269 6270 6271 6272 6273 6274 6275
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

6276 6277
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304
    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;
    }

    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, 0);

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

static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
6305
                                      unsigned int flags)
C
Chris Lalancette 已提交
6306 6307 6308 6309 6310 6311 6312 6313 6314 6315
{
    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;
    qemuDomainObjPrivatePtr priv;
    int rc;

6316 6317
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348
    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;
    }

    vm->current_snapshot = snap;

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

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {

        if (virDomainObjIsActive(vm)) {
            priv = vm->privateData;
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (rc < 0)
6349
                goto endjob;
C
Chris Lalancette 已提交
6350 6351
        }
        else {
6352
            if (qemuDomainSnapshotSetCurrentActive(vm, driver->snapshotDir) < 0)
6353
                goto endjob;
C
Chris Lalancette 已提交
6354

6355 6356
            rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
                                  false, -1, NULL, VIR_VM_OP_CREATE);
6357
            qemuDomainStartAudit(vm, "from-snapshot", rc >= 0);
6358
            if (qemuDomainSnapshotSetCurrentInactive(vm, driver->snapshotDir) < 0)
6359
                goto endjob;
C
Chris Lalancette 已提交
6360
            if (rc < 0)
6361
                goto endjob;
C
Chris Lalancette 已提交
6362 6363 6364 6365 6366 6367
        }

        if (snap->def->state == VIR_DOMAIN_PAUSED) {
            /* qemu unconditionally starts the domain running again after
             * loadvm, so let's pause it to keep consistency
             */
6368
            rc = qemuProcessStopCPUs(driver, vm);
H
Hu Tao 已提交
6369
            if (rc < 0)
6370
                goto endjob;
C
Chris Lalancette 已提交
6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388
        }

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT);
    }
    else {
        /* qemu is a little funny with running guests and the restoration
         * of snapshots.  If the snapshot was taken online,
         * then after a "loadvm" monitor command, the VM is set running
         * again.  If the snapshot was taken offline, then after a "loadvm"
         * monitor command the VM is left paused.  Unpausing it leads to
         * the memory state *before* the loadvm with the disk *after* the
         * loadvm, which obviously is bound to corrupt something.
         * Therefore we destroy the domain and set it to "off" in this case.
         */

        if (virDomainObjIsActive(vm)) {
6389
            qemuProcessStop(driver, vm, 0);
6390
            qemuDomainStopAudit(vm, "from-snapshot");
C
Chris Lalancette 已提交
6391 6392 6393
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
                                             VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
6394 6395 6396 6397
            if (!vm->persistent) {
                if (qemuDomainObjEndJob(vm) > 0)
                    virDomainRemoveInactive(&driver->domains, vm);
                vm = NULL;
6398
                goto cleanup;
6399
            }
C
Chris Lalancette 已提交
6400 6401
        }

6402
        if (qemuDomainSnapshotSetCurrentActive(vm, driver->snapshotDir) < 0)
6403
            goto endjob;
C
Chris Lalancette 已提交
6404 6405 6406 6407 6408 6409
    }

    vm->state = snap->def->state;

    ret = 0;

6410
endjob:
C
Chris Lalancette 已提交
6411 6412 6413
    if (vm && qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

6414
cleanup:
C
Chris Lalancette 已提交
6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516
    if (event)
        qemuDomainEventQueue(driver, event);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    return ret;
}

static int qemuDomainSnapshotDiscard(struct qemud_driver *driver,
                                     virDomainObjPtr vm,
                                     virDomainSnapshotObjPtr snap)
{
    const char *qemuimgarg[] = { NULL, "snapshot", "-d", NULL, NULL, NULL };
    char *snapFile = NULL;
    int ret = -1;
    int i;
    qemuDomainObjPrivatePtr priv;
    virDomainSnapshotObjPtr parentsnap;

    if (!virDomainObjIsActive(vm)) {
        qemuimgarg[0] = qemuFindQemuImgBinary();
        if (qemuimgarg[0] == NULL)
            /* qemuFindQemuImgBinary set the error */
            goto cleanup;

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

        for (i = 0; i < vm->def->ndisks; i++) {
            /* FIXME: we also need to handle LVM here */
            if (vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                if (!vm->def->disks[i]->driverType ||
                    STRNEQ(vm->def->disks[i]->driverType, "qcow2")) {
                    /* we continue on even in the face of error, since other
                     * disks in this VM may have this snapshot in place
                     */
                    continue;
                }

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

                if (virRun(qemuimgarg, NULL) < 0) {
                    /* we continue on even in the face of error, since other
                     * disks in this VM may have this snapshot in place
                     */
                    continue;
                }
            }
        }
    }
    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 (snap == vm->current_snapshot) {
        if (snap->def->parent) {
            parentsnap = virDomainSnapshotFindByName(&vm->snapshots,
                                                     snap->def->parent);
            if (!parentsnap) {
                qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                                _("no domain snapshot parent with matching name '%s'"),
                                snap->def->parent);
                goto cleanup;
            }

            /* Now we set the new current_snapshot for the domain */
            vm->current_snapshot = parentsnap;
        }
        else
            vm->current_snapshot = NULL;
    }

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

    virDomainSnapshotObjListRemove(&vm->snapshots, snap);

    ret = 0;

cleanup:
    VIR_FREE(snapFile);
    VIR_FREE(qemuimgarg[0]);

    return ret;
}

struct snap_remove {
    struct qemud_driver *driver;
    virDomainObjPtr vm;
    char *parent;
    int err;
};

static void qemuDomainSnapshotDiscardChildren(void *payload,
6517
                                              const void *name ATTRIBUTE_UNUSED,
C
Chris Lalancette 已提交
6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538
                                              void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    struct snap_remove *curr = data;
    struct snap_remove this;

    if (snap->def->parent && STREQ(snap->def->parent, curr->parent)) {
        this.driver = curr->driver;
        this.vm = curr->vm;
        this.parent = snap->def->name;
        this.err = 0;
        virHashForEach(curr->vm->snapshots.objs,
                       qemuDomainSnapshotDiscardChildren, &this);

        if (this.err)
            curr->err = this.err;
        else
            this.err = qemuDomainSnapshotDiscard(curr->driver, curr->vm, snap);
    }
}

6539 6540 6541 6542 6543 6544 6545 6546 6547
struct snap_reparent {
    struct qemud_driver *driver;
    virDomainSnapshotObjPtr snap;
    virDomainObjPtr vm;
    int err;
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
6548
                                   const void *name ATTRIBUTE_UNUSED,
6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    struct snap_reparent *rep = data;

    if (rep->err < 0) {
        return;
    }

    if (snap->def->parent && STREQ(snap->def->parent, rep->snap->def->name)) {
        VIR_FREE(snap->def->parent);

        if (rep->snap->def->parent != NULL) {
            snap->def->parent = strdup(rep->snap->def->parent);

            if (snap->def->parent == NULL) {
                virReportOOMError();
                rep->err = -1;
                return;
            }
        }

        rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
                                                   rep->driver->snapshotDir);
    }
}

C
Chris Lalancette 已提交
6576 6577 6578 6579 6580 6581 6582 6583 6584
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;
6585
    struct snap_reparent rep;
C
Chris Lalancette 已提交
6586

6587 6588
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);

C
Chris Lalancette 已提交
6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605
    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;
    }

6606 6607 6608
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

C
Chris Lalancette 已提交
6609 6610 6611 6612 6613 6614 6615 6616
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) {
        rem.driver = driver;
        rem.vm = vm;
        rem.parent = snap->def->name;
        rem.err = 0;
        virHashForEach(vm->snapshots.objs, qemuDomainSnapshotDiscardChildren,
                       &rem);
        if (rem.err < 0)
6617
            goto endjob;
6618 6619 6620 6621 6622 6623 6624 6625 6626
    } else {
        rep.driver = driver;
        rep.snap = snap;
        rep.vm = vm;
        rep.err = 0;
        virHashForEach(vm->snapshots.objs, qemuDomainSnapshotReparentChildren,
                       &rep);
        if (rep.err < 0)
            goto endjob;
C
Chris Lalancette 已提交
6627 6628 6629 6630
    }

    ret = qemuDomainSnapshotDiscard(driver, vm, snap);

6631 6632 6633 6634
endjob:
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

C
Chris Lalancette 已提交
6635 6636 6637 6638 6639 6640
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
6641

6642 6643 6644 6645 6646 6647 6648
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;
6649
    bool hmp;
6650

6651
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676

    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;

    if (!priv->monitor_warned) {
        VIR_INFO("Qemu monitor command '%s' executed; libvirt results may be unpredictable!",
                 cmd);
        priv->monitor_warned = 1;
    }

6677 6678
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

6679 6680 6681
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6682
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    if (qemuDomainObjEndJob(vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

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

6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752

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

6753
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
6754 6755 6756 6757 6758 6759
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("character device %s is not using a PTY"),
                        NULLSTR(devname));
        goto cleanup;
    }

6760
    if (virFDStreamOpenFile(st, chr->source.data.file.path, O_RDWR) < 0)
6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771
        goto cleanup;

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


6772 6773 6774 6775 6776
static virDriver qemuDriver = {
    VIR_DRV_QEMU,
    "QEMU",
    qemudOpen, /* open */
    qemudClose, /* close */
D
Daniel Veillard 已提交
6777
    qemudSupportsFeature, /* supports_feature */
6778 6779
    qemudGetType, /* type */
    qemudGetVersion, /* version */
6780
    NULL, /* libvirtVersion (impl. in libvirt.c) */
6781
    virGetHostname, /* getHostname */
E
Eric Blake 已提交
6782
    qemuGetSysinfo, /* getSysinfo */
6783
    qemudGetMaxVCPUs, /* getMaxVcpus */
6784
    nodeGetInfo, /* nodeGetInfo */
6785 6786 6787
    qemudGetCapabilities, /* getCapabilities */
    qemudListDomains, /* listDomains */
    qemudNumDomains, /* numOfDomains */
6788
    qemudDomainCreate, /* domainCreateXML */
6789 6790 6791 6792 6793
    qemudDomainLookupByID, /* domainLookupByID */
    qemudDomainLookupByUUID, /* domainLookupByUUID */
    qemudDomainLookupByName, /* domainLookupByName */
    qemudDomainSuspend, /* domainSuspend */
    qemudDomainResume, /* domainResume */
6794
    qemudDomainShutdown, /* domainShutdown */
6795 6796 6797
    NULL, /* domainReboot */
    qemudDomainDestroy, /* domainDestroy */
    qemudDomainGetOSType, /* domainGetOSType */
6798
    qemudDomainGetMaxMemory, /* domainGetMaxMemory */
6799
    NULL, /* domainSetMaxMemory */
6800
    qemudDomainSetMemory, /* domainSetMemory */
6801 6802 6803
    qemudDomainGetInfo, /* domainGetInfo */
    qemudDomainSave, /* domainSave */
    qemudDomainRestore, /* domainRestore */
P
Paolo Bonzini 已提交
6804
    qemudDomainCoreDump, /* domainCoreDump */
6805
    qemudDomainSetVcpus, /* domainSetVcpus */
6806 6807
    qemudDomainSetVcpusFlags, /* domainSetVcpusFlags */
    qemudDomainGetVcpusFlags, /* domainGetVcpusFlags */
6808 6809
    qemudDomainPinVcpu, /* domainPinVcpu */
    qemudDomainGetVcpus, /* domainGetVcpus */
6810
    qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
6811 6812
    qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
    qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
6813
    qemudDomainDumpXML, /* domainDumpXML */
6814
    qemuDomainXMLFromNative, /* domainXmlFromNative */
6815
    qemuDomainXMLToNative, /* domainXMLToNative */
6816 6817
    qemudListDefinedDomains, /* listDefinedDomains */
    qemudNumDefinedDomains, /* numOfDefinedDomains */
6818
    qemudDomainStart, /* domainCreate */
6819
    qemudDomainStartWithFlags, /* domainCreateWithFlags */
6820 6821
    qemudDomainDefine, /* domainDefineXML */
    qemudDomainUndefine, /* domainUndefine */
6822
    qemudDomainAttachDevice, /* domainAttachDevice */
6823
    qemudDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
6824
    qemudDomainDetachDevice, /* domainDetachDevice */
6825
    qemudDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
6826
    qemuDomainUpdateDeviceFlags, /* domainUpdateDeviceFlags */
6827 6828
    qemudDomainGetAutostart, /* domainGetAutostart */
    qemudDomainSetAutostart, /* domainSetAutostart */
6829 6830 6831
    qemuGetSchedulerType, /* domainGetSchedulerType */
    qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
    qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
6832 6833
    NULL, /* domainMigratePrepare (v1) */
    qemudDomainMigratePerform, /* domainMigratePerform */
6834
    NULL, /* domainMigrateFinish */
6835
    qemudDomainBlockStats, /* domainBlockStats */
6836
    qemudDomainInterfaceStats, /* domainInterfaceStats */
6837
    qemudDomainMemoryStats, /* domainMemoryStats */
6838
    qemudDomainBlockPeek, /* domainBlockPeek */
R
Richard W.M. Jones 已提交
6839
    qemudDomainMemoryPeek, /* domainMemoryPeek */
6840
    qemuDomainGetBlockInfo, /* domainGetBlockInfo */
6841 6842
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
6843 6844
    qemuDomainEventRegister, /* domainEventRegister */
    qemuDomainEventDeregister, /* domainEventDeregister */
D
Daniel Veillard 已提交
6845 6846
    qemudDomainMigratePrepare2, /* domainMigratePrepare2 */
    qemudDomainMigrateFinish2, /* domainMigrateFinish2 */
6847 6848 6849
    qemudNodeDeviceDettach, /* nodeDeviceDettach */
    qemudNodeDeviceReAttach, /* nodeDeviceReAttach */
    qemudNodeDeviceReset, /* nodeDeviceReset */
C
Chris Lalancette 已提交
6850
    qemudDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
6851 6852 6853 6854
    qemuIsEncrypted, /* isEncrypted */
    qemuIsSecure, /* isSecure */
    qemuDomainIsActive, /* domainIsActive */
    qemuDomainIsPersistent, /* domainIsPersistent */
6855
    qemuDomainIsUpdated, /* domainIsUpdated */
6856
    qemuCPUCompare, /* cpuCompare */
6857
    qemuCPUBaseline, /* cpuBaseline */
6858
    qemuDomainGetJobInfo, /* domainGetJobInfo */
6859
    qemuDomainAbortJob, /* domainAbortJob */
6860
    qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
6861 6862
    qemuDomainEventRegisterAny, /* domainEventRegisterAny */
    qemuDomainEventDeregisterAny, /* domainEventDeregisterAny */
6863 6864 6865
    qemuDomainManagedSave, /* domainManagedSave */
    qemuDomainHasManagedSaveImage, /* domainHasManagedSaveImage */
    qemuDomainManagedSaveRemove, /* domainManagedSaveRemove */
C
Chris Lalancette 已提交
6866 6867 6868 6869 6870 6871 6872 6873 6874
    qemuDomainSnapshotCreateXML, /* domainSnapshotCreateXML */
    qemuDomainSnapshotDumpXML, /* domainSnapshotDumpXML */
    qemuDomainSnapshotNum, /* domainSnapshotNum */
    qemuDomainSnapshotListNames, /* domainSnapshotListNames */
    qemuDomainSnapshotLookupByName, /* domainSnapshotLookupByName */
    qemuDomainHasCurrentSnapshot, /* domainHasCurrentSnapshot */
    qemuDomainSnapshotCurrent, /* domainSnapshotCurrent */
    qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */
    qemuDomainSnapshotDelete, /* domainSnapshotDelete */
6875
    qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
6876
    qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */
6877
    qemuDomainGetMemoryParameters, /* domainGetMemoryParameters */
6878
    qemuDomainOpenConsole, /* domainOpenConsole */
6879 6880 6881
};


6882
static virStateDriver qemuStateDriver = {
6883
    .name = "QEMU",
6884 6885 6886 6887
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
6888
};
6889

6890
static void
6891
qemuVMDriverLock(void) {
6892 6893 6894 6895 6896
    qemuDriverLock(qemu_driver);
};


static void
6897
qemuVMDriverUnlock(void) {
6898 6899 6900 6901
    qemuDriverUnlock(qemu_driver);
};


6902 6903 6904 6905 6906 6907 6908 6909 6910
static int
qemuVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
                    virHashIterator iter, void *data)
{
    virHashForEach(qemu_driver->domains.objs, iter, data);

    return 0;
}

S
Stefan Berger 已提交
6911 6912
static virNWFilterCallbackDriver qemuCallbackDriver = {
    .name = "QEMU",
6913 6914 6915
    .vmFilterRebuild = qemuVMFilterRebuild,
    .vmDriverLock = qemuVMDriverLock,
    .vmDriverUnlock = qemuVMDriverUnlock,
S
Stefan Berger 已提交
6916 6917
};

6918
int qemuRegister(void) {
6919 6920
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
S
Stefan Berger 已提交
6921
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
6922 6923
    return 0;
}