qemu_driver.c 219.0 KB
Newer Older
D
Daniel P. Berrange 已提交
1 2 3
/*
 * driver.c: core driver methods for managing qemu guests
 *
4
 * Copyright (C) 2006, 2007, 2008, 2009 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 28 29 30
#include <sys/types.h>
#include <sys/poll.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
31
#include <stdbool.h>
D
Daniel P. Berrange 已提交
32 33 34 35 36 37
#include <stdio.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
38
#include <sys/utsname.h>
39 40 41 42
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
43 44
#include <pwd.h>
#include <stdio.h>
45
#include <sys/wait.h>
46
#include <sys/ioctl.h>
47
#include <sys/un.h>
D
Daniel P. Berrange 已提交
48

49 50 51 52
#if HAVE_SCHED_H
#include <sched.h>
#endif

53
#include "virterror_internal.h"
54
#include "logging.h"
55
#include "datatypes.h"
56 57
#include "qemu_driver.h"
#include "qemu_conf.h"
58
#include "qemu_monitor_text.h"
J
Jim Meyering 已提交
59
#include "c-ctype.h"
60
#include "event.h"
61
#include "buf.h"
62
#include "util.h"
63
#include "nodeinfo.h"
64
#include "stats_linux.h"
65
#include "capabilities.h"
66
#include "memory.h"
67
#include "uuid.h"
68
#include "domain_conf.h"
69 70
#include "node_device_conf.h"
#include "pci.h"
71
#include "hostusb.h"
72
#include "security/security_driver.h"
73
#include "cgroup.h"
C
Chris Lalancette 已提交
74
#include "libvirt_internal.h"
75

76

77 78
#define VIR_FROM_THIS VIR_FROM_QEMU

79 80
static int qemudShutdown(void);

81 82
static void qemuDriverLock(struct qemud_driver *driver)
{
83
    virMutexLock(&driver->lock);
84 85 86
}
static void qemuDriverUnlock(struct qemud_driver *driver)
{
87
    virMutexUnlock(&driver->lock);
88 89
}

90 91 92
static void qemuDomainEventFlush(int timer, void *opaque);
static void qemuDomainEventQueue(struct qemud_driver *driver,
                                 virDomainEventPtr event);
93

94 95
static void qemudDispatchVMEvent(int watch,
                                 int fd,
96 97 98
                                 int events,
                                 void *opaque);

99 100
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
101
                              virDomainObjPtr vm,
102 103
                              const char *migrateFrom,
                              int stdin_fd);
104

105 106
static void qemudShutdownVMDaemon(virConnectPtr conn,
                                  struct qemud_driver *driver,
107
                                  virDomainObjPtr vm);
108

109
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
110

111 112
static int qemuDetectVcpuPIDs(virConnectPtr conn,
                              virDomainObjPtr vm);
113

114 115 116
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                                       virDomainDefPtr def);

J
Jim Meyering 已提交
117
static struct qemud_driver *qemu_driver = NULL;
118

119 120 121 122 123 124 125 126 127
static int qemuCgroupControllerActive(struct qemud_driver *driver,
                                      int controller)
{
    if (driver->cgroup == NULL)
        return 0;
    if (driver->cgroupControllers & (1 << controller))
        return 1;
    return 0;
}
128

129
static int
130
qemudLogFD(virConnectPtr conn, struct qemud_driver *driver, const char* name)
131 132 133
{
    char logfile[PATH_MAX];
    mode_t logmode;
G
Guido Günther 已提交
134
    int ret, fd = -1;
135

136 137
    if ((ret = snprintf(logfile, sizeof(logfile), "%s/%s.log",
                        driver->logDir, name))
G
Guido Günther 已提交
138
        < 0 || ret >= sizeof(logfile)) {
139
        virReportOOMError(conn);
140 141 142 143
        return -1;
    }

    logmode = O_CREAT | O_WRONLY;
144 145
    /* Only logrotate files in /var/log, so only append if running privileged */
    if (driver->privileged)
146
        logmode |= O_APPEND;
147 148 149
    else
        logmode |= O_TRUNC;

150
    if ((fd = open(logfile, logmode, S_IRUSR | S_IWUSR)) < 0) {
151 152 153
        virReportSystemError(conn, errno,
                             _("failed to create logfile %s"),
                             logfile);
154 155
        return -1;
    }
156
    if (virSetCloseExec(fd) < 0) {
157 158
        virReportSystemError(conn, errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
159 160 161 162 163 164 165
        close(fd);
        return -1;
    }
    return fd;
}


166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
static int
qemudLogReadFD(virConnectPtr conn, const char* logDir, const char* name, off_t pos)
{
    char logfile[PATH_MAX];
    mode_t logmode = O_RDONLY;
    int ret, fd = -1;

    if ((ret = snprintf(logfile, sizeof(logfile), "%s/%s.log", logDir, name))
        < 0 || ret >= sizeof(logfile)) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("failed to build logfile name %s/%s.log"),
                         logDir, name);
        return -1;
    }


    if ((fd = open(logfile, logmode)) < 0) {
183 184 185
        virReportSystemError(conn, errno,
                             _("failed to create logfile %s"),
                             logfile);
186 187
        return -1;
    }
188
    if (virSetCloseExec(fd) < 0) {
189 190
        virReportSystemError(conn, errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
191 192 193 194
        close(fd);
        return -1;
    }
    if (lseek(fd, pos, SEEK_SET) < 0) {
195 196 197
        virReportSystemError(conn, errno,
                             _("Unable to seek to %lld in %s"),
                             (long long) pos, logfile);
198 199 200 201 202 203
        close(fd);
    }
    return fd;
}


204 205 206 207 208 209 210 211 212 213 214 215
struct qemuAutostartData {
    struct qemud_driver *driver;
    virConnectPtr conn;
};
static void
qemuAutostartDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
{
    virDomainObjPtr vm = payload;
    struct qemuAutostartData *data = opaque;

    virDomainObjLock(vm);
    if (vm->autostart &&
D
Daniel P. Berrange 已提交
216
        !virDomainObjIsActive(vm)) {
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
        int ret;

        virResetLastError();
        ret = qemudStartVMDaemon(data->conn, data->driver, vm, NULL, -1);
        if (ret < 0) {
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to autostart VM '%s': %s\n"),
                      vm->def->name,
                      err ? err->message : "");
        } else {
            virDomainEventPtr event =
                virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
            if (event)
                qemuDomainEventQueue(data->driver, event);
        }
    }
    virDomainObjUnlock(vm);
}

238 239
static void
qemudAutostartConfigs(struct qemud_driver *driver) {
240 241 242 243 244
    /* 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
     */
245 246 247
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
248
    /* Ignoring NULL conn which is mostly harmless here */
249
    struct qemuAutostartData data = { driver, conn };
250

251
    qemuDriverLock(driver);
252
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
253
    qemuDriverUnlock(driver);
254

255 256
    if (conn)
        virConnectClose(conn);
257 258
}

259 260 261 262 263 264 265 266 267 268 269 270 271

/**
 * qemudRemoveDomainStatus
 *
 * remove all state files of a domain from statedir
 *
 * Returns 0 on success
 */
static int
qemudRemoveDomainStatus(virConnectPtr conn,
                        struct qemud_driver *driver,
                        virDomainObjPtr vm)
{
272
    char ebuf[1024];
273 274 275
    char *file = NULL;

    if (virAsprintf(&file, "%s/%s.xml", driver->stateDir, vm->def->name) < 0) {
276
        virReportOOMError(conn);
D
Daniel Veillard 已提交
277
        return(-1);
278 279
    }

280 281
    if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR)
        VIR_WARN(_("Failed to remove domain XML for %s: %s"),
D
Daniel Veillard 已提交
282 283 284
                 vm->def->name, virStrerror(errno, ebuf, sizeof(ebuf)));
    VIR_FREE(file);

285 286 287
    if (virFileDeletePid(driver->stateDir, vm->def->name) != 0)
        VIR_WARN(_("Failed to remove PID file for %s: %s"),
                 vm->def->name, virStrerror(errno, ebuf, sizeof(ebuf)));
288

D
Daniel Veillard 已提交
289

290
    return 0;
291 292 293
}


294 295 296 297
static int qemudOpenMonitor(virConnectPtr conn,
                            virDomainObjPtr vm,
                            int reconnect);

298 299 300 301

/*
 * Open an existing VM's monitor, re-detect VCPU threads
 * and re-reserve the security labels in use
302
 */
303 304
static void
qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
305
{
306
    int rc;
307 308 309 310
    virDomainObjPtr obj = payload;
    struct qemud_driver *driver = opaque;

    virDomainObjLock(obj);
311

312
    if ((rc = qemudOpenMonitor(NULL, obj, 1)) != 0) {
313 314 315 316
        VIR_ERROR(_("Failed to reconnect monitor for %s: %d\n"),
                  obj->def->name, rc);
        goto error;
    }
317

318 319 320 321
    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
        goto error;
    }

322 323 324 325
    if (obj->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        driver->securityDriver &&
        driver->securityDriver->domainReserveSecurityLabel &&
        driver->securityDriver->domainReserveSecurityLabel(NULL, obj) < 0)
326
        goto error;
327

328 329
    if (obj->def->id >= driver->nextvmid)
        driver->nextvmid = obj->def->id + 1;
330

331 332
    virDomainObjUnlock(obj);
    return;
333

334
error:
335 336 337 338 339
    /* We can't get the monitor back, so must kill the VM
     * to remove danger of it ending up running twice if
     * user tries to start it again later */
    qemudShutdownVMDaemon(NULL, driver, obj);
    virDomainObjUnlock(obj);
340
}
341

342 343 344 345 346 347 348 349 350
/**
 * qemudReconnectVMs
 *
 * Try to re-open the resources for live VMs that we care
 * about.
 */
static void
qemuReconnectDomains(struct qemud_driver *driver)
{
351
    virHashForEach(driver->domains.objs, qemuReconnectDomain, driver);
352 353
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386

static int
qemudSecurityCapsInit(virSecurityDriverPtr secdrv,
                      virCapsPtr caps)
{
    const char *doi, *model;

    doi = virSecurityDriverGetDOI(secdrv);
    model = virSecurityDriverGetModel(secdrv);

    caps->host.secModel.model = strdup(model);
    if (!caps->host.secModel.model) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to copy secModel model: %s"),
                  virStrerror(errno, ebuf, sizeof ebuf));
        return -1;
    }

    caps->host.secModel.doi = strdup(doi);
    if (!caps->host.secModel.doi) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to copy secModel DOI: %s"),
                  virStrerror(errno, ebuf, sizeof ebuf));
        return -1;
    }

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

    return 0;
}


387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
static int
qemudSecurityInit(struct qemud_driver *qemud_drv)
{
    int ret;
    virSecurityDriverPtr security_drv;

    ret = virSecurityDriverStartup(&security_drv,
                                   qemud_drv->securityDriverName);
    if (ret == -1) {
        VIR_ERROR0(_("Failed to start security driver"));
        return -1;
    }
    /* No security driver wanted to be enabled: just return */
    if (ret == -2) {
        VIR_INFO0(_("No security driver available"));
        return 0;
    }

    qemud_drv->securityDriver = security_drv;

407
    VIR_INFO("Initialized security driver %s", security_drv->name);
408 409 410 411 412

    /*
     * Add security policy host caps now that the security driver is
     * initialized.
     */
413 414
    return qemudSecurityCapsInit(security_drv, qemud_drv->caps);
}
415 416


417

418 419 420 421 422 423
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
424
qemudStartup(int privileged) {
425
    char *base = NULL;
D
Daniel P. Berrange 已提交
426
    char driverConf[PATH_MAX];
427
    int rc;
428

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

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

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

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

446
    /* Init callback list */
447
    if (VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
448
        goto out_of_memory;
449 450 451 452 453 454
    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
        goto out_of_memory;

    if ((qemu_driver->domainEventTimer =
         virEventAddTimeout(-1, qemuDomainEventFlush, qemu_driver, NULL)) < 0)
        goto error;
455

456
    if (privileged) {
457 458
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1)
459
            goto out_of_memory;
460

D
Daniel P. Berrange 已提交
461
        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
462
            goto out_of_memory;
463 464

        if (virAsprintf(&qemu_driver->stateDir,
465
                      "%s/run/libvirt/qemu", LOCAL_STATE_DIR) == -1)
466
            goto out_of_memory;
467 468 469 470 471 472 473 474

        if (virAsprintf(&qemu_driver->libDir,
                      "%s/lib/libvirt/qemu", LOCAL_STATE_DIR) == -1)
            goto out_of_memory;

        if (virAsprintf(&qemu_driver->cacheDir,
                      "%s/cache/libvirt/qemu", LOCAL_STATE_DIR) == -1)
            goto out_of_memory;
475
    } else {
476
        uid_t uid = geteuid();
477 478
        char *userdir = virGetUserDirectory(NULL, uid);
        if (!userdir)
479
            goto error;
480

481
        if (virAsprintf(&qemu_driver->logDir,
482 483
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
484
            goto out_of_memory;
485
        }
486

487 488
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
489
            goto out_of_memory;
490 491
        }
        VIR_FREE(userdir);
492 493 494

        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
            goto out_of_memory;
495 496 497 498
        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;
499 500 501
    }

    if (virFileMakePath(qemu_driver->stateDir) < 0) {
502
        char ebuf[1024];
503 504
        VIR_ERROR(_("Failed to create state dir '%s': %s\n"),
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
505
        goto error;
506
    }
507 508 509 510 511 512 513 514 515 516 517 518
    if (virFileMakePath(qemu_driver->libDir) < 0) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to create lib dir '%s': %s\n"),
                  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\n"),
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
519 520 521 522

    /* Configuration paths are either ~/.libvirt/qemu/... (session) or
     * /etc/libvirt/qemu/... (system).
     */
D
Daniel P. Berrange 已提交
523
    if (snprintf (driverConf, sizeof(driverConf), "%s/qemu.conf", base) == -1)
524
        goto out_of_memory;
D
Daniel P. Berrange 已提交
525
    driverConf[sizeof(driverConf)-1] = '\0';
526

527
    if (virAsprintf(&qemu_driver->configDir, "%s/qemu", base) == -1)
528 529
        goto out_of_memory;

530
    if (virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1)
531 532
        goto out_of_memory;

533
    VIR_FREE(base);
534

535 536 537 538 539 540 541
    rc = virCgroupForDriver("qemu", &qemu_driver->cgroup, privileged, 1);
    if (rc < 0) {
        char buf[1024];
        VIR_WARN("Unable to create cgroup for driver: %s",
                 virStrerror(-rc, buf, sizeof(buf)));
    }

542
    if ((qemu_driver->caps = qemudCapsInit(NULL)) == NULL)
543
        goto out_of_memory;
D
Daniel P. Berrange 已提交
544

545 546 547
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew(NULL)) == NULL)
        goto error;

548
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
549 550 551
        goto error;
    }

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
    if (privileged) {
        if (chown(qemu_driver->libDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(NULL, errno,
                                 _("unable to set ownership of '%s' to user %d:%d"),
                                 qemu_driver->libDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
        if (chown(qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(NULL, errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
    }

567
    if (qemudSecurityInit(qemu_driver) < 0) {
568
        goto error;
D
Daniel P. Berrange 已提交
569 570
    }

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
    /* 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
     */
    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;

        if ((rc = virFileMakePath(mempath)) != 0) {
            virReportSystemError(NULL, rc,
                                 _("unable to create hugepage path %s"), mempath);
            VIR_FREE(mempath);
            goto error;
        }
        if (qemu_driver->privileged &&
            chown(mempath, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(NULL, errno,
                                 _("unable to set ownership on %s to %d:%d"),
                                 mempath, qemu_driver->user, qemu_driver->group);
            VIR_FREE(mempath);
            goto error;
        }

        qemu_driver->hugepage_path = mempath;
    }

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

    qemuReconnectDomains(qemu_driver);

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

623 624
    qemudAutostartConfigs(qemu_driver);

625

626 627
    return 0;

628
out_of_memory:
629
    virReportOOMError(NULL);
630 631 632
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
633
    VIR_FREE(base);
634
    qemudShutdown();
635 636 637
    return -1;
}

638 639 640 641
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;

642 643 644 645 646 647 648 649
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }
650 651
}

652 653 654 655 656 657 658 659
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
660 661 662
    if (!qemu_driver)
        return 0;

663
    qemuDriverLock(qemu_driver);
664 665 666 667
    virDomainLoadAllConfigs(NULL,
                            qemu_driver->caps,
                            &qemu_driver->domains,
                            qemu_driver->configDir,
668
                            qemu_driver->autostartDir,
669
                            0, qemudNotifyLoadDomain, qemu_driver);
670
    qemuDriverUnlock(qemu_driver);
671

672
    qemudAutostartConfigs(qemu_driver);
673 674

    return 0;
675 676
}

677 678 679 680 681 682 683 684 685 686
/**
 * 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) {
687
    int active = 0;
688

689 690 691
    if (!qemu_driver)
        return 0;

692
    /* XXX having to iterate here is not great because it requires many locks */
693
    qemuDriverLock(qemu_driver);
694
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
695 696
    qemuDriverUnlock(qemu_driver);
    return active;
697 698
}

699 700 701 702 703 704 705
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
706

707
    if (!qemu_driver)
708
        return -1;
709

710
    qemuDriverLock(qemu_driver);
711
    pciDeviceListFree(NULL, qemu_driver->activePciHostdevs);
712 713
    virCapabilitiesFree(qemu_driver->caps);

714
    virDomainObjListDeinit(&qemu_driver->domains);
715

716
    VIR_FREE(qemu_driver->securityDriverName);
717
    VIR_FREE(qemu_driver->logDir);
718 719
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
720
    VIR_FREE(qemu_driver->stateDir);
721 722
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
723
    VIR_FREE(qemu_driver->vncTLSx509certdir);
J
Jim Meyering 已提交
724
    VIR_FREE(qemu_driver->vncListen);
725
    VIR_FREE(qemu_driver->vncPassword);
726
    VIR_FREE(qemu_driver->vncSASLdir);
727
    VIR_FREE(qemu_driver->saveImageFormat);
728 729
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
D
Daniel P. Berrange 已提交
730

731 732
    /* Free domain callback list */
    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
733 734 735 736
    virDomainEventQueueFree(qemu_driver->domainEventQueue);

    if (qemu_driver->domainEventTimer != -1)
        virEventRemoveTimeout(qemu_driver->domainEventTimer);
737

738 739 740
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);

741 742
    virCgroupFree(&qemu_driver->cgroup);

743
    qemuDriverUnlock(qemu_driver);
744
    virMutexDestroy(&qemu_driver->lock);
745
    VIR_FREE(qemu_driver);
746 747

    return 0;
748 749 750
}

/* Return -1 for error, 1 to continue reading and 0 for success */
751
typedef int qemudHandlerMonitorOutput(virConnectPtr conn,
752
                                      virDomainObjPtr vm,
753 754 755
                                      const char *output,
                                      int fd);

756 757 758
/*
 * Returns -1 for error, 0 on end-of-file, 1 for success
 */
759
static int
760
qemudReadMonitorOutput(virConnectPtr conn,
761
                       virDomainObjPtr vm,
762 763
                       int fd,
                       char *buf,
G
Guido Günther 已提交
764
                       size_t buflen,
765
                       qemudHandlerMonitorOutput func,
766 767
                       const char *what,
                       int timeout)
768
{
G
Guido Günther 已提交
769
    size_t got = 0;
770
    buf[0] = '\0';
771
    timeout *= 1000; /* poll wants milli seconds */
772

773
    /* Consume & discard the initial greeting */
774
    while (got < (buflen-1)) {
G
Guido Günther 已提交
775
        ssize_t ret;
776 777

        ret = read(fd, buf+got, buflen-got-1);
778

779 780 781 782 783 784
        if (ret < 0) {
            struct pollfd pfd = { .fd = fd, .events = POLLIN };
            if (errno == EINTR)
                continue;

            if (errno != EAGAIN) {
785 786 787
                virReportSystemError(conn, errno,
                                     _("Failure while reading %s startup output"),
                                     what);
788 789 790
                return -1;
            }

791
            ret = poll(&pfd, 1, timeout);
792
            if (ret == 0) {
793
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
794
                                 _("Timed out while reading %s startup output"), what);
795 796 797
                return -1;
            } else if (ret == -1) {
                if (errno != EINTR) {
798 799 800
                    virReportSystemError(conn, errno,
                                         _("Failure while reading %s startup output"),
                                         what);
801 802 803 804 805 806 807 808
                    return -1;
                }
            } else {
                /* Make sure we continue loop & read any further data
                   available before dealing with EOF */
                if (pfd.revents & (POLLIN | POLLHUP))
                    continue;

809
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
810
                                 _("Failure while reading %s startup output"), what);
811 812
                return -1;
            }
813 814
        } else if (ret == 0) {
            return 0;
815 816 817
        } else {
            got += ret;
            buf[got] = '\0';
818 819 820 821 822 823
            ret = func(conn, vm, buf, fd);
            if (ret == -1)
                return -1;
            if (ret == 1)
                continue;
            return 1;
824 825 826
        }
    }

827
    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
828
                     _("Out of space while reading %s startup output"), what);
829 830 831 832
    return -1;

}

833 834 835 836 837 838 839 840 841

/*
 * Returns -1 for error, 0 on success
 */
static int
qemudReadLogOutput(virConnectPtr conn,
                   virDomainObjPtr vm,
                   int fd,
                   char *buf,
G
Guido Günther 已提交
842
                   size_t buflen,
843 844 845 846
                   qemudHandlerMonitorOutput func,
                   const char *what,
                   int timeout)
{
847
    int retries = (timeout*10);
848
    int got = 0;
849 850 851
    buf[0] = '\0';

    while (retries) {
852
        ssize_t func_ret, ret;
853
        int isdead = 0;
G
Guido Günther 已提交
854

855 856
        func_ret = func(conn, vm, buf, fd);

857 858
        if (kill(vm->pid, 0) == -1 && errno == ESRCH)
            isdead = 1;
859

860 861
        /* Any failures should be detected before we read the log, so we
         * always have something useful to report on failure. */
862 863
        ret = saferead(fd, buf+got, buflen-got-1);
        if (ret < 0) {
864 865 866 867 868 869
            virReportSystemError(conn, errno,
                                 _("Failure while reading %s log output"),
                                 what);
            return -1;
        }

870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
        got += ret;
        buf[got] = '\0';
        if (got == buflen-1) {
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             _("Out of space while reading %s log output"),
                             what);
            return -1;
        }

        if (isdead) {
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                             _("Process exited while reading %s log output"),
                             what);
            return -1;
        }

886 887
        if (func_ret <= 0)
            return func_ret;
888 889 890 891 892 893 894 895 896 897

        usleep(100*1000);
        retries--;
    }
    if (retries == 0)
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Timed out while reading %s log output"), what);
    return -1;
}

898
static int
899
qemudCheckMonitorPrompt(virConnectPtr conn ATTRIBUTE_UNUSED,
900
                        virDomainObjPtr vm,
901 902 903 904 905 906 907 908 909 910 911
                        const char *output,
                        int fd)
{
    if (strstr(output, "(qemu) ") == NULL)
        return 1; /* keep reading */

    vm->monitor = fd;

    return 0;
}

912
static int
913 914 915 916
qemudOpenMonitorCommon(virConnectPtr conn,
                       virDomainObjPtr vm,
                       int monfd,
                       int reconnect)
917
{
918
    char buf[1024];
919
    int ret;
920

921
    if (virSetCloseExec(monfd) < 0) {
922
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
923
                         "%s", _("Unable to set monitor close-on-exec flag"));
924
        return -1;
925
    }
926
    if (virSetNonBlock(monfd) < 0) {
927
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
928
                         "%s", _("Unable to put monitor into non-blocking mode"));
929
        return -1;
930 931
    }

932
    if (!reconnect) {
933 934 935 936
        if (qemudReadMonitorOutput(conn,
                                   vm, monfd,
                                   buf, sizeof(buf),
                                   qemudCheckMonitorPrompt,
937
                                   "monitor", 10) <= 0)
938 939 940
            ret = -1;
        else
            ret = 0;
941 942 943 944 945 946
    } else {
        vm->monitor = monfd;
        ret = 0;
    }

    if (ret != 0)
947
        return ret;
948

949 950
    if ((vm->monitorWatch = virEventAddHandle(vm->monitor,
                                              VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR,
951
                                              qemudDispatchVMEvent,
952
                                              vm, NULL)) < 0)
953
        return -1;
954

955 956
    return 0;
}
957

958 959 960 961 962 963 964 965
static int
qemudOpenMonitorUnix(virConnectPtr conn,
                     virDomainObjPtr vm,
                     const char *monitor,
                     int reconnect)
{
    struct sockaddr_un addr;
    int monfd;
966
    int timeout = 3; /* In seconds */
967
    int ret, i = 0;
968 969 970 971 972 973 974 975 976

    if ((monfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        virReportSystemError(conn, errno,
                             "%s", _("failed to create socket"));
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
C
Chris Lalancette 已提交
977 978 979 980 981
    if (virStrcpyStatic(addr.sun_path, monitor) == NULL) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Monitor path %s too big for destination"), monitor);
        goto error;
    }
982

983 984 985 986 987 988
    do {
        ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr));

        if (ret == 0)
            break;

989 990
        if (errno == ENOENT || errno == ECONNREFUSED) {
            /* ENOENT       : Socket may not have shown up yet
991 992 993 994
             * ECONNREFUSED : Leftover socket hasn't been removed yet */
            continue;
        }

995 996 997
        virReportSystemError(conn, errno, "%s",
                             _("failed to connect to monitor socket"));
        goto error;
998 999 1000 1001 1002 1003 1004

    } while ((++i <= timeout*5) && (usleep(.2 * 1000000) <= 0));

    if (ret != 0) {
        virReportSystemError(conn, errno, "%s",
                             _("monitor socket did not show up."));
        goto error;
1005 1006
    }

1007
    if (qemudOpenMonitorCommon(conn, vm, monfd, reconnect) < 0)
1008 1009 1010 1011 1012 1013 1014 1015 1016
        goto error;

    return 0;

error:
    close(monfd);
    return -1;
}

1017 1018 1019 1020 1021 1022 1023
static int
qemudOpenMonitorPty(virConnectPtr conn,
                    virDomainObjPtr vm,
                    const char *monitor,
                    int reconnect)
{
    int monfd;
1024

1025 1026 1027 1028 1029 1030
    if ((monfd = open(monitor, O_RDWR)) < 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Unable to open monitor path %s"), monitor);
        return -1;
    }

1031
    if (qemudOpenMonitorCommon(conn, vm, monfd, reconnect) < 0)
1032 1033 1034 1035 1036
        goto error;

    return 0;

error:
1037
    close(monfd);
1038 1039 1040 1041 1042 1043 1044 1045 1046
    return -1;
}

static int
qemudOpenMonitor(virConnectPtr conn,
                 virDomainObjPtr vm,
                 int reconnect)
{
    switch (vm->monitor_chr->type) {
1047
    case VIR_DOMAIN_CHR_TYPE_UNIX:
1048
        return qemudOpenMonitorUnix(conn, vm,
1049 1050
                                    vm->monitor_chr->data.nix.path,
                                    reconnect);
1051
    case VIR_DOMAIN_CHR_TYPE_PTY:
1052
        return qemudOpenMonitorPty(conn, vm,
1053 1054 1055 1056 1057 1058 1059 1060
                                   vm->monitor_chr->data.file.path,
                                   reconnect);
    default:
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("unable to handle monitor type: %s"),
                         virDomainChrTypeToString(vm->monitor_chr->type));
        return -1;
    }
1061 1062
}

1063
/* Returns -1 for error, 0 success, 1 continue reading */
1064 1065 1066 1067 1068 1069
static int
qemudExtractMonitorPath(virConnectPtr conn,
                        const char *haystack,
                        size_t *offset,
                        char **path)
{
1070
    static const char needle[] = "char device redirected to";
1071
    char *tmp, *dev;
1072

1073
    VIR_FREE(*path);
1074
    /* First look for our magic string */
1075 1076 1077 1078 1079
    if (!(tmp = strstr(haystack + *offset, needle))) {
        return 1;
    }
    tmp += sizeof(needle);
    dev = tmp;
1080

1081 1082 1083 1084 1085
    /*
     * And look for first whitespace character and nul terminate
     * to mark end of the pty path
     */
    while (*tmp) {
1086
        if (c_isspace(*tmp)) {
1087 1088
            *path = strndup(dev, tmp-dev);
            if (*path == NULL) {
1089
                virReportOOMError(conn);
1090 1091
                return -1;
            }
1092

1093
            /* ... now further update offset till we get EOL */
1094
            *offset = tmp - haystack;
1095 1096
            return 0;
        }
1097
        tmp++;
1098 1099 1100 1101 1102
    }

    /*
     * We found a path, but didn't find any whitespace,
     * so it must be still incomplete - we should at
1103 1104
     * least see a \n - indicate that we want to carry
     * on trying again
1105
     */
1106
    return 1;
1107 1108 1109
}

static int
1110
qemudFindCharDevicePTYs(virConnectPtr conn,
1111
                        virDomainObjPtr vm,
1112 1113
                        const char *output,
                        int fd ATTRIBUTE_UNUSED)
1114
{
1115
    size_t offset = 0;
1116
    int ret, i;
1117 1118

    /* The order in which QEMU prints out the PTY paths is
1119 1120
       the order in which it procsses its serial and parallel
       device args. This code must match that ordering.... */
1121

1122
    /* first comes the serial devices */
1123 1124
    for (i = 0 ; i < vm->def->nserials ; i++) {
        virDomainChrDefPtr chr = vm->def->serials[i];
1125 1126 1127
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
            if ((ret = qemudExtractMonitorPath(conn, output, &offset,
                                               &chr->data.file.path)) != 0)
1128
                return ret;
1129 1130 1131
        }
    }

1132
    /* then the parallel devices */
1133 1134
    for (i = 0 ; i < vm->def->nparallels ; i++) {
        virDomainChrDefPtr chr = vm->def->parallels[i];
1135 1136 1137
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
            if ((ret = qemudExtractMonitorPath(conn, output, &offset,
                                               &chr->data.file.path)) != 0)
1138
                return ret;
1139 1140 1141
        }
    }

1142
    return 0;
1143 1144
}

1145 1146 1147 1148
static int
qemudWaitForMonitor(virConnectPtr conn,
                    struct qemud_driver* driver,
                    virDomainObjPtr vm, off_t pos)
1149
{
1150
    char buf[4096]; /* Plenty of space to get startup greeting */
1151 1152 1153 1154 1155
    int logfd;
    int ret;

    if ((logfd = qemudLogReadFD(conn, driver->logDir, vm->def->name, pos))
        < 0)
1156
        return -1;
1157

1158 1159 1160
    ret = qemudReadLogOutput(conn, vm, logfd, buf, sizeof(buf),
                             qemudFindCharDevicePTYs,
                             "console", 3);
1161
    if (close(logfd) < 0) {
1162
        char ebuf[4096];
1163
        VIR_WARN(_("Unable to close logfile: %s\n"),
1164 1165
                 virStrerror(errno, ebuf, sizeof ebuf));
    }
1166

1167 1168 1169 1170 1171 1172
    if (ret < 0) {
        /* Unexpected end of file - inform user of QEMU log data */
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("unable to start guest: %s"), buf);
        return -1;
    }
1173

1174
    if (qemudOpenMonitor(conn, vm, 0) < 0)
1175 1176 1177
        return -1;

    return 0;
1178 1179
}

1180
static int
1181 1182 1183 1184
qemuDetectVcpuPIDs(virConnectPtr conn,
                   virDomainObjPtr vm) {
    pid_t *cpupids = NULL;
    int ncpupids;
1185

1186
    if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
1187 1188 1189 1190 1191
        vm->nvcpupids = 1;
        if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) {
            virReportOOMError(conn);
            return -1;
        }
1192 1193 1194 1195
        vm->vcpupids[0] = vm->pid;
        return 0;
    }

1196
    /* What follows is now all KVM specific */
1197

1198 1199
    if ((ncpupids = qemuMonitorGetCPUInfo(vm, &cpupids)) < 0)
        return -1;
1200

1201 1202 1203
    /* Treat failure to get VCPU<->PID mapping as non-fatal */
    if (ncpupids == 0)
        return 0;
1204

1205 1206 1207 1208 1209 1210 1211
    if (ncpupids != vm->def->vcpus) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"),
                         ncpupids, (int)vm->def->vcpus);
        VIR_FREE(cpupids);
        return -1;
    }
1212

1213 1214
    vm->nvcpupids = ncpupids;
    vm->vcpupids = cpupids;
1215 1216 1217
    return 0;
}

1218 1219
static int
qemudInitCpus(virConnectPtr conn,
D
Daniel Veillard 已提交
1220 1221
              virDomainObjPtr vm,
              const char *migrateFrom) {
1222 1223 1224 1225 1226
#if HAVE_SCHED_GETAFFINITY
    cpu_set_t mask;
    int i, maxcpu = QEMUD_CPUMASK_LEN;
    virNodeInfo nodeinfo;

1227
    if (nodeGetInfo(conn, &nodeinfo) < 0)
1228 1229 1230 1231 1232 1233 1234 1235
        return -1;

    /* setaffinity fails if you set bits for CPUs which
     * aren't present, so we have to limit ourselves */
    if (maxcpu > nodeinfo.cpus)
        maxcpu = nodeinfo.cpus;

    CPU_ZERO(&mask);
D
Daniel P. Berrange 已提交
1236 1237 1238 1239 1240 1241
    if (vm->def->cpumask) {
        for (i = 0 ; i < maxcpu ; i++)
            if (vm->def->cpumask[i])
                CPU_SET(i, &mask);
    } else {
        for (i = 0 ; i < maxcpu ; i++)
1242
            CPU_SET(i, &mask);
D
Daniel P. Berrange 已提交
1243
    }
1244 1245 1246 1247

    for (i = 0 ; i < vm->nvcpupids ; i++) {
        if (sched_setaffinity(vm->vcpupids[i],
                              sizeof(mask), &mask) < 0) {
1248 1249
            virReportSystemError(conn, errno, "%s",
                                 _("failed to set CPU affinity"));
1250 1251 1252 1253 1254
            return -1;
        }
    }
#endif /* HAVE_SCHED_GETAFFINITY */

D
Daniel Veillard 已提交
1255 1256
    if (migrateFrom == NULL) {
        /* Allow the CPUS to start executing */
1257
        if (qemuMonitorStartCPUs(conn, vm) < 0) {
1258 1259 1260
            if (virGetLastError() == NULL)
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("resume operation failed"));
D
Daniel Veillard 已提交
1261 1262
            return -1;
        }
1263 1264 1265 1266 1267 1268
    }

    return 0;
}


1269
static int
1270 1271
qemuInitPasswords(struct qemud_driver *driver,
                  virDomainObjPtr vm) {
1272
    int ret = 0;
1273

1274 1275 1276
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) {
1277

1278 1279 1280 1281
        ret = qemuMonitorSetVNCPassword(vm,
                                        vm->def->graphics[0]->data.vnc.passwd ?
                                        vm->def->graphics[0]->data.vnc.passwd :
                                        driver->vncPassword);
1282 1283
    }

1284
    return ret;
1285 1286 1287
}


1288
static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
    int i;

    for (i = 5900 ; i < 6000 ; i++) {
        int fd;
        int reuse = 1;
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(i);
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        fd = socket(PF_INET, SOCK_STREAM, 0);
        if (fd < 0)
            return -1;

        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse)) < 0) {
            close(fd);
            break;
        }

        if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
            /* Not in use, lets grab it */
            close(fd);
            return i;
        }
        close(fd);

        if (errno == EADDRINUSE) {
            /* In use, try next */
            continue;
        }
        /* Some other bad failure, get out.. */
        break;
    }
    return -1;
}

1324 1325 1326 1327 1328
static pciDeviceList *
qemuGetPciHostDeviceList(virConnectPtr conn,
                         virDomainDefPtr def)
{
    pciDeviceList *list;
1329 1330
    int i;

1331 1332
    if (!(list = pciDeviceListNew(conn)))
        return NULL;
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347

    for (i = 0 ; i < def->nhostdevs ; i++) {
        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
        pciDevice *dev;

        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;
        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
            continue;

        dev = pciGetDevice(conn,
                           hostdev->source.subsys.u.pci.domain,
                           hostdev->source.subsys.u.pci.bus,
                           hostdev->source.subsys.u.pci.slot,
                           hostdev->source.subsys.u.pci.function);
1348 1349 1350 1351
        if (!dev) {
            pciDeviceListFree(conn, list);
            return NULL;
        }
1352

1353
        if (pciDeviceListAdd(conn, list, dev) < 0) {
1354
            pciFreeDevice(conn, dev);
1355 1356
            pciDeviceListFree(conn, list);
            return NULL;
1357 1358
        }

1359
        pciDeviceSetManaged(dev, hostdev->managed);
1360 1361
    }

1362 1363 1364 1365
    return list;
}

static int
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                            virDomainDefPtr def)
{
    pciDeviceList *pcidevs;
    int i, ret;

    if (!def->nhostdevs)
        return 0;

    if (!(pcidevs = qemuGetPciHostDeviceList(NULL, def)))
        return -1;

    ret = 0;

    for (i = 0; i < pcidevs->count; i++) {
        if (pciDeviceListAdd(NULL,
                             driver->activePciHostdevs,
                             pcidevs->devs[i]) < 0) {
            ret = -1;
            break;
        }
        pcidevs->devs[i] = NULL;
    }

    pciDeviceListFree(NULL, pcidevs);
    return ret;
}

static int
qemuPrepareHostDevices(virConnectPtr conn,
                       struct qemud_driver *driver,
                       virDomainDefPtr def)
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
{
    pciDeviceList *pcidevs;
    int i;

    if (!def->nhostdevs)
        return 0;

    if (!(pcidevs = qemuGetPciHostDeviceList(conn, def)))
        return -1;

1408
    /* We have to use 3 loops here. *All* devices must
1409 1410
     * be detached before we reset any of them, because
     * in some cases you have to reset the whole PCI,
1411 1412
     * which impacts all devices on it. Also, all devices
     * must be reset before being marked as active.
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
     */

    /* XXX validate that non-managed device isn't in use, eg
     * by checking that device is either un-bound, or bound
     * to pci-stub.ko
     */

    for (i = 0; i < pcidevs->count; i++)
        if (pciDeviceGetManaged(pcidevs->devs[i]) &&
            pciDettachDevice(conn, pcidevs->devs[i]) < 0)
            goto error;

    /* Now that all the PCI hostdevs have be dettached, we can safely
     * reset them */
    for (i = 0; i < pcidevs->count; i++)
1428 1429
        if (pciResetDevice(conn, pcidevs->devs[i],
                           driver->activePciHostdevs) < 0)
1430 1431
            goto error;

1432 1433 1434 1435 1436 1437 1438 1439 1440
    /* Now mark all the devices as active */
    for (i = 0; i < pcidevs->count; i++) {
        if (pciDeviceListAdd(conn,
                             driver->activePciHostdevs,
                             pcidevs->devs[i]) < 0)
            goto error;
        pcidevs->devs[i] = NULL;
    }

1441
    pciDeviceListFree(conn, pcidevs);
1442 1443 1444
    return 0;

error:
1445
    pciDeviceListFree(conn, pcidevs);
1446 1447 1448
    return -1;
}

1449
static void
1450 1451 1452
qemuDomainReAttachHostDevices(virConnectPtr conn,
                              struct qemud_driver *driver,
                              virDomainDefPtr def)
1453
{
1454
    pciDeviceList *pcidevs;
1455 1456
    int i;

1457 1458
    if (!def->nhostdevs)
        return;
1459

1460 1461 1462 1463 1464 1465
    if (!(pcidevs = qemuGetPciHostDeviceList(conn, def))) {
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to allocate pciDeviceList: %s\n"),
                  err ? err->message : "");
        virResetError(err);
        return;
1466 1467
    }

1468 1469
    /* Again 3 loops; mark all devices as inactive before reset
     * them and reset all the devices before re-attach */
1470

1471
    for (i = 0; i < pcidevs->count; i++)
1472 1473 1474 1475 1476
        pciDeviceListDel(conn, driver->activePciHostdevs, pcidevs->devs[i]);

    for (i = 0; i < pcidevs->count; i++)
        if (pciResetDevice(conn, pcidevs->devs[i],
                           driver->activePciHostdevs) < 0) {
1477
            virErrorPtr err = virGetLastError();
1478
            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
1479 1480 1481 1482
                      err ? err->message : "");
            virResetError(err);
        }

1483 1484 1485
    for (i = 0; i < pcidevs->count; i++)
        if (pciDeviceGetManaged(pcidevs->devs[i]) &&
            pciReAttachDevice(conn, pcidevs->devs[i]) < 0) {
1486
            virErrorPtr err = virGetLastError();
1487
            VIR_ERROR(_("Failed to re-attach PCI device: %s\n"),
1488 1489 1490 1491
                      err ? err->message : "");
            virResetError(err);
        }

1492
    pciDeviceListFree(conn, pcidevs);
1493 1494
}

1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
static const char *const defaultDeviceACL[] = {
    "/dev/null", "/dev/full", "/dev/zero",
    "/dev/random", "/dev/urandom",
    "/dev/ptmx", "/dev/kvm", "/dev/kqemu",
    "/dev/rtc", "/dev/hpet", "/dev/net/tun",
    NULL,
};
#define DEVICE_PTY_MAJOR 136
#define DEVICE_SND_MAJOR 116

1505 1506 1507 1508 1509 1510
static int qemuSetupCgroup(virConnectPtr conn,
                           struct qemud_driver *driver,
                           virDomainObjPtr vm)
{
    virCgroupPtr cgroup = NULL;
    int rc;
1511
    unsigned int i;
1512 1513 1514 1515
    const char *const *deviceACL =
        driver->cgroupDeviceACL ?
        (const char *const *)driver->cgroupDeviceACL :
        defaultDeviceACL;
1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527

    if (driver->cgroup == NULL)
        return 0; /* Not supported, so claim success */

    rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 1);
    if (rc != 0) {
        virReportSystemError(conn, -rc,
                             _("Unable to create cgroup for %s"),
                             vm->def->name);
        goto cleanup;
    }

1528 1529
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        rc = virCgroupDenyAllDevices(cgroup);
1530
        if (rc != 0) {
1531 1532 1533 1534 1535
            if (rc == -EPERM) {
                VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
                goto done;
            }

1536
            virReportSystemError(conn, -rc,
1537
                                 _("Unable to deny all devices for %s"), vm->def->name);
1538 1539 1540
            goto cleanup;
        }

1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
        for (i = 0; i < vm->def->ndisks ; i++) {
            if (vm->def->disks[i]->type != VIR_DOMAIN_DISK_TYPE_BLOCK ||
                vm->def->disks[i]->src == NULL)
                continue;

            rc = virCgroupAllowDevicePath(cgroup,
                                          vm->def->disks[i]->src);
            if (rc != 0) {
                virReportSystemError(conn, -rc,
                                     _("Unable to allow device %s for %s"),
                                     vm->def->disks[i]->src, vm->def->name);
                goto cleanup;
            }
        }
1555

1556
        rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
1557 1558
        if (rc != 0) {
            virReportSystemError(conn, -rc, "%s",
1559
                                 _("unable to allow /dev/pts/ devices"));
1560 1561 1562
            goto cleanup;
        }

1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581
        if (vm->def->nsounds) {
            rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR);
            if (rc != 0) {
                virReportSystemError(conn, -rc, "%s",
                                     _("unable to allow /dev/snd/ devices"));
                goto cleanup;
            }
        }

        for (i = 0; deviceACL[i] != NULL ; i++) {
            rc = virCgroupAllowDevicePath(cgroup,
                                          deviceACL[i]);
            if (rc < 0 &&
                rc != -ENOENT) {
                virReportSystemError(conn, -rc,
                                     _("unable to allow device %s"),
                                     deviceACL[i]);
                goto cleanup;
            }
1582 1583 1584 1585
        }
    }

done:
1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
    virCgroupFree(&cgroup);
    return 0;

cleanup:
    if (cgroup) {
        virCgroupRemove(cgroup);
        virCgroupFree(&cgroup);
    }
    return -1;
}


static int qemuRemoveCgroup(virConnectPtr conn,
                            struct qemud_driver *driver,
                            virDomainObjPtr vm)
{
    virCgroupPtr cgroup;
    int rc;

    if (driver->cgroup == NULL)
        return 0; /* Not supported, so claim success */

    rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0);
    if (rc != 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Unable to find cgroup for %s\n"),
                         vm->def->name);
        return rc;
    }

    rc = virCgroupRemove(cgroup);
    virCgroupFree(&cgroup);
    return rc;
}

static int qemuAddToCgroup(struct qemud_driver *driver,
                           virDomainDefPtr def)
{
    virCgroupPtr cgroup = NULL;
    int ret = -1;
    int rc;

    if (driver->cgroup == NULL)
        return 0; /* Not supported, so claim success */

    rc = virCgroupForDomain(driver->cgroup, def->name, &cgroup, 0);
    if (rc != 0) {
        virReportSystemError(NULL, -rc,
                             _("unable to find cgroup for domain %s"),
                             def->name);
        goto cleanup;
    }

    rc = virCgroupAddTask(cgroup, getpid());
    if (rc != 0) {
        virReportSystemError(NULL, -rc,
                             _("unable to add domain %s task %d to cgroup"),
                             def->name, getpid());
        goto cleanup;
    }

    ret = 0;

cleanup:
    virCgroupFree(&cgroup);
    return ret;
}


1655 1656 1657 1658 1659 1660 1661 1662 1663
static int qemudDomainSetSecurityLabel(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm)
{
    if (vm->def->seclabel.label != NULL)
        if (driver->securityDriver && driver->securityDriver->domainSetSecurityLabel)
            return driver->securityDriver->domainSetSecurityLabel(conn, driver->securityDriver,
                                                                 vm);
    return 0;
}

1664 1665

#ifdef __linux__
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676
struct qemuFileOwner {
    uid_t uid;
    gid_t gid;
};

static int qemuDomainSetHostdevUSBOwnershipActor(virConnectPtr conn,
                                                 usbDevice *dev ATTRIBUTE_UNUSED,
                                                 const char *file, void *opaque)
{
    struct qemuFileOwner *owner = opaque;

1677 1678
    VIR_DEBUG("Setting ownership on %s to %d:%d", file, owner->uid, owner->gid);

1679 1680 1681 1682 1683 1684 1685 1686
    if (chown(file, owner->uid, owner->gid) < 0) {
        virReportSystemError(conn, errno, _("cannot set ownership on %s"), file);
        return -1;
    }

    return 0;
}

1687 1688 1689 1690
static int qemuDomainSetHostdevUSBOwnership(virConnectPtr conn,
                                            virDomainHostdevDefPtr def,
                                            uid_t uid, gid_t gid)
{
1691 1692
    struct qemuFileOwner owner = { uid, gid };
    int ret = -1;
1693 1694 1695 1696 1697 1698

    /* XXX what todo for USB devs assigned based on product/vendor ? Doom :-( */
    if (!def->source.subsys.u.usb.bus ||
        !def->source.subsys.u.usb.device)
        return 0;

1699 1700 1701 1702 1703 1704 1705 1706 1707
    usbDevice *dev = usbGetDevice(conn,
                                  def->source.subsys.u.usb.bus,
                                  def->source.subsys.u.usb.device);

    if (!dev)
        goto cleanup;

    ret = usbDeviceFileIterate(conn, dev,
                               qemuDomainSetHostdevUSBOwnershipActor, &owner);
1708

1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
    usbFreeDevice(conn, dev);
cleanup:
    return ret;
}

static int qemuDomainSetHostdevPCIOwnershipActor(virConnectPtr conn,
                                                 pciDevice *dev ATTRIBUTE_UNUSED,
                                                 const char *file, void *opaque)
{
    struct qemuFileOwner *owner = opaque;

1720 1721
    VIR_DEBUG("Setting ownership on %s to %d:%d", file, owner->uid, owner->gid);

1722 1723
    if (chown(file, owner->uid, owner->gid) < 0) {
        virReportSystemError(conn, errno, _("cannot set ownership on %s"), file);
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
        return -1;
    }

    return 0;
}

static int qemuDomainSetHostdevPCIOwnership(virConnectPtr conn,
                                            virDomainHostdevDefPtr def,
                                            uid_t uid, gid_t gid)
{
1734
    struct qemuFileOwner owner = { uid, gid };
1735 1736
    int ret = -1;

1737 1738 1739 1740 1741
    pciDevice *dev = pciGetDevice(conn,
                                  def->source.subsys.u.pci.domain,
                                  def->source.subsys.u.pci.bus,
                                  def->source.subsys.u.pci.slot,
                                  def->source.subsys.u.pci.function);
1742

1743
    if (!dev)
1744 1745
        goto cleanup;

1746 1747
    ret = pciDeviceFileIterate(conn, dev,
                               qemuDomainSetHostdevPCIOwnershipActor, &owner);
1748

1749
    pciFreeDevice(conn, dev);
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
cleanup:
    return ret;
}
#endif


static int qemuDomainSetHostdevOwnership(virConnectPtr conn,
                                         virDomainHostdevDefPtr def,
                                         uid_t uid, gid_t gid)
{
    if (def->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
        return 0;

#ifdef __linux__
    switch (def->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        return qemuDomainSetHostdevUSBOwnership(conn, def, uid, gid);

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
        return qemuDomainSetHostdevPCIOwnership(conn, def, uid, gid);

    }
    return 0;
#else
C
Cole Robinson 已提交
1774
    qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s",
1775 1776 1777 1778 1779 1780
                     _("unable to set host device ownership on this platform"));
    return -1;
#endif

}

1781 1782
static int qemuDomainSetFileOwnership(virConnectPtr conn,
                                      const char *path,
1783 1784 1785
                                      uid_t uid, gid_t gid)
{

1786
    if (!path)
1787 1788
        return 0;

1789 1790
    VIR_DEBUG("Setting ownership on %s to %d:%d", path, uid, gid);
    if (chown(path, uid, gid) < 0) {
1791
        virReportSystemError(conn, errno, _("cannot set ownership on %s"),
1792
                             path);
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
        return -1;
    }
    return 0;
}

static int qemuDomainSetDeviceOwnership(virConnectPtr conn,
                                        struct qemud_driver *driver,
                                        virDomainDeviceDefPtr def,
                                        int restore)
{
    uid_t uid;
    gid_t gid;

    if (!driver->privileged)
        return 0;

    /* short circuit case of root:root */
    if (!driver->user && !driver->group)
        return 0;

    uid = restore ? 0 : driver->user;
    gid = restore ? 0 : driver->group;

    switch (def->type) {
    case VIR_DOMAIN_DEVICE_DISK:
        if (restore &&
            (def->data.disk->readonly || def->data.disk->shared))
            return 0;

1822
        return qemuDomainSetFileOwnership(conn, def->data.disk->src, uid, gid);
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        return qemuDomainSetHostdevOwnership(conn, def->data.hostdev, uid, gid);
    }

    return 0;
}

static int qemuDomainSetAllDeviceOwnership(virConnectPtr conn,
                                           struct qemud_driver *driver,
                                           virDomainDefPtr def,
                                           int restore)
{
    int i;
    uid_t uid;
    gid_t gid;

    if (!driver->privileged)
        return 0;

    /* short circuit case of root:root */
    if (!driver->user && !driver->group)
        return 0;

    uid = restore ? 0 : driver->user;
    gid = restore ? 0 : driver->group;

1850 1851 1852 1853
    if (qemuDomainSetFileOwnership(conn, def->os.kernel, uid, gid) < 0 ||
        qemuDomainSetFileOwnership(conn, def->os.initrd, uid, gid) < 0)
        return -1;

1854 1855 1856 1857 1858
    for (i = 0 ; i < def->ndisks ; i++) {
        if (restore &&
            (def->disks[i]->readonly || def->disks[i]->shared))
            continue;

1859
        if (qemuDomainSetFileOwnership(conn, def->disks[i]->src, uid, gid) < 0)
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870
            return -1;
    }

    for (i = 0 ; i < def->nhostdevs ; i++) {
        if (qemuDomainSetHostdevOwnership(conn, def->hostdevs[i], uid, gid) < 0)
            return -1;
    }

    return 0;
}

1871 1872 1873
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
                                            const char *name);

1874 1875 1876 1877
struct qemudHookData {
    virConnectPtr conn;
    virDomainObjPtr vm;
    struct qemud_driver *driver;
1878 1879 1880
};

static int qemudSecurityHook(void *data) {
1881 1882 1883 1884
    struct qemudHookData *h = data;

    if (qemuAddToCgroup(h->driver, h->vm->def) < 0)
        return -1;
1885

1886
    if (qemudDomainSetSecurityLabel(h->conn, h->driver, h->vm) < 0)
1887 1888 1889 1890 1891
        return -1;

    if (h->driver->privileged) {
        if (qemuDomainSetAllDeviceOwnership(h->conn, h->driver, h->vm->def, 0) < 0)
            return -1;
1892

1893 1894
        DEBUG("Dropping privileges of VM to %d:%d", h->driver->user, h->driver->group);

1895 1896 1897 1898 1899
        if (h->driver->group) {
            if (setregid(h->driver->group, h->driver->group) < 0) {
                virReportSystemError(NULL, errno,
                                     _("cannot change to '%d' group"),
                                     h->driver->group);
1900
                return -1;
1901
            }
1902
        }
1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913
        if (h->driver->user) {
            if (setreuid(h->driver->user, h->driver->user) < 0) {
                virReportSystemError(NULL, errno,
                                     _("cannot change to '%d' user"),
                                     h->driver->user);
                return -1;
            }
        }
    }

    return 0;
1914 1915
}

1916 1917 1918 1919 1920 1921 1922 1923 1924 1925
static int
qemuPrepareMonitorChr(virConnectPtr conn,
                      struct qemud_driver *driver,
                      virDomainChrDefPtr monitor_chr,
                      const char *vm)
{
    monitor_chr->type = VIR_DOMAIN_CHR_TYPE_UNIX;
    monitor_chr->data.nix.listen = 1;

    if (virAsprintf(&monitor_chr->data.nix.path, "%s/%s.monitor",
1926
                    driver->libDir, vm) < 0) {
1927 1928 1929 1930 1931 1932 1933
        virReportOOMError(conn);
        return -1;
    }

    return 0;
}

1934 1935
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
1936
                              virDomainObjPtr vm,
1937 1938
                              const char *migrateFrom,
                              int stdin_fd) {
1939
    const char **argv = NULL, **tmp;
1940
    const char **progenv = NULL;
1941
    int i, ret;
1942
    struct stat sb;
1943 1944
    int *tapfds = NULL;
    int ntapfds = 0;
1945
    unsigned int qemuCmdFlags;
1946
    fd_set keepfd;
1947
    const char *emulator;
G
Guido Günther 已提交
1948
    pid_t child;
1949
    int pos = -1;
1950
    char ebuf[1024];
1951
    char *pidfile = NULL;
1952
    int logfile;
1953

1954
    struct qemudHookData hookData;
1955 1956 1957 1958
    hookData.conn = conn;
    hookData.vm = vm;
    hookData.driver = driver;

1959
    FD_ZERO(&keepfd);
1960

D
Daniel P. Berrange 已提交
1961
    if (virDomainObjIsActive(vm)) {
1962
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_INVALID,
1963
                         "%s", _("VM is already active"));
1964 1965 1966
        return -1;
    }

1967 1968 1969 1970 1971 1972 1973 1974
    /* If you are using a SecurityDriver with dynamic labelling,
       then generate a security label for isolation */
    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        driver->securityDriver &&
        driver->securityDriver->domainGenSecurityLabel &&
        driver->securityDriver->domainGenSecurityLabel(conn, vm) < 0)
        return -1;

1975 1976 1977
    /* Ensure no historical cgroup for this VM is lieing around bogus settings */
    qemuRemoveCgroup(conn, driver, vm);

1978 1979 1980
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        vm->def->graphics[0]->data.vnc.autoport) {
1981
        int port = qemudNextFreeVNCPort(driver);
1982
        if (port < 0) {
1983
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
1984
                             "%s", _("Unable to find an unused VNC port"));
1985
            goto cleanup;
1986
        }
1987
        vm->def->graphics[0]->data.vnc.port = port;
1988
    }
1989

1990
    if (virFileMakePath(driver->logDir) < 0) {
1991 1992 1993
        virReportSystemError(conn, errno,
                             _("cannot create log directory %s"),
                             driver->logDir);
1994
        goto cleanup;
1995 1996
    }

1997
    if ((logfile = qemudLogFD(conn, driver, vm->def->name)) < 0)
1998
        goto cleanup;
1999

2000 2001
    emulator = vm->def->emulator;

2002 2003 2004 2005
    /* Make sure the binary we are about to try exec'ing exists.
     * Technically we could catch the exec() failure, but that's
     * in a sub-process so its hard to feed back a useful error
     */
2006
    if (stat(emulator, &sb) < 0) {
2007 2008 2009
        virReportSystemError(conn, errno,
                             _("Cannot find QEMU binary %s"),
                             emulator);
2010
        goto cleanup;
2011 2012
    }

2013
    if (qemudExtractVersionInfo(emulator,
2014
                                NULL,
2015
                                &qemuCmdFlags) < 0)
2016
        goto cleanup;
2017

2018 2019 2020
    if (qemuSetupCgroup(conn, driver, vm) < 0)
        goto cleanup;

2021
    if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
2022
        goto cleanup;
2023

2024 2025 2026 2027 2028
    if (VIR_ALLOC(vm->monitor_chr) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }

2029 2030
    if (qemuPrepareMonitorChr(conn, driver, vm->monitor_chr, vm->def->name) < 0)
        goto cleanup;
2031

D
Daniel P. Berrange 已提交
2032 2033 2034 2035 2036 2037 2038
    if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
        virReportSystemError(conn, ret,
                             _("Cannot remove stale PID file for %s"),
                             vm->def->name);
        goto cleanup;
    }

2039 2040 2041 2042 2043
    if (!(pidfile = virFilePid(driver->stateDir, vm->def->name))) {
        virReportSystemError(conn, errno,
                             "%s", _("Failed to build pidfile path."));
        goto cleanup;
    }
D
Daniel P. Berrange 已提交
2044

2045
    vm->def->id = driver->nextvmid++;
2046
    if (qemudBuildCommandLine(conn, driver, vm->def, vm->monitor_chr,
2047
                              qemuCmdFlags, &argv, &progenv,
2048 2049
                              &tapfds, &ntapfds, migrateFrom) < 0)
        goto cleanup;
2050

2051 2052
    tmp = progenv;
    while (*tmp) {
2053
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
2054
            VIR_WARN(_("Unable to write envv to logfile: %s\n"),
2055
                     virStrerror(errno, ebuf, sizeof ebuf));
2056
        if (safewrite(logfile, " ", 1) < 0)
2057
            VIR_WARN(_("Unable to write envv to logfile: %s\n"),
2058
                     virStrerror(errno, ebuf, sizeof ebuf));
2059 2060
        tmp++;
    }
2061 2062
    tmp = argv;
    while (*tmp) {
2063
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
2064
            VIR_WARN(_("Unable to write argv to logfile: %s\n"),
2065
                     virStrerror(errno, ebuf, sizeof ebuf));
2066
        if (safewrite(logfile, " ", 1) < 0)
2067
            VIR_WARN(_("Unable to write argv to logfile: %s\n"),
2068
                     virStrerror(errno, ebuf, sizeof ebuf));
2069 2070
        tmp++;
    }
2071
    if (safewrite(logfile, "\n", 1) < 0)
2072
        VIR_WARN(_("Unable to write argv to logfile: %s\n"),
2073
                 virStrerror(errno, ebuf, sizeof ebuf));
2074

2075
    if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
2076
        VIR_WARN(_("Unable to seek to end of logfile: %s\n"),
2077
                 virStrerror(errno, ebuf, sizeof ebuf));
2078

2079 2080 2081
    for (i = 0 ; i < ntapfds ; i++)
        FD_SET(tapfds[i], &keepfd);

2082
    ret = virExecDaemonize(conn, argv, progenv, &keepfd, &child,
2083
                           stdin_fd, &logfile, &logfile,
2084
                           VIR_EXEC_NONBLOCK | VIR_EXEC_CLEAR_CAPS,
2085 2086 2087
                           qemudSecurityHook, &hookData,
                           pidfile);
    VIR_FREE(pidfile);
G
Guido Günther 已提交
2088 2089 2090

    /* wait for qemu process to to show up */
    if (ret == 0) {
2091
        if (virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) {
2092
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
2093
                             _("Domain %s didn't show up\n"), vm->def->name);
2094
            ret = -1;
G
Guido Günther 已提交
2095
        }
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
    } else if (ret == -2) {
        /* The virExec process that launches the daemon failed. Pending on
         * when it failed (we can't determine for sure), there may be
         * extra info in the domain log (if the hook failed for example).
         *
         * Pretend like things succeeded, and let 'WaitForMonitor' report
         * the log contents for us.
         */
        vm->pid = child;
        ret = 0;
    }
2107 2108

    vm->state = migrateFrom ? VIR_DOMAIN_PAUSED : VIR_DOMAIN_RUNNING;
2109

2110
    for (i = 0 ; argv[i] ; i++)
2111 2112
        VIR_FREE(argv[i]);
    VIR_FREE(argv);
2113

2114 2115 2116 2117
    for (i = 0 ; progenv[i] ; i++)
        VIR_FREE(progenv[i]);
    VIR_FREE(progenv);

2118 2119 2120
    if (tapfds) {
        for (i = 0 ; i < ntapfds ; i++) {
            close(tapfds[i]);
2121
        }
2122
        VIR_FREE(tapfds);
2123 2124
    }

2125 2126 2127 2128
    if (ret == -1)
        goto cleanup;

    if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) ||
2129
        (qemuDetectVcpuPIDs(conn, vm) < 0) ||
2130
        (qemudInitCpus(conn, vm, migrateFrom) < 0) ||
2131
        (qemuInitPasswords(driver, vm) < 0) ||
2132
        (qemuMonitorSetBalloon(vm, vm->def->memory) < 0) ||
2133
        (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)) {
2134 2135 2136
        qemudShutdownVMDaemon(conn, driver, vm);
        ret = -1;
        /* No need for 'goto cleanup' now since qemudShutdownVMDaemon does enough */
2137 2138
    }

2139 2140 2141
    if (logfile != -1)
        close(logfile);

2142
    return ret;
2143 2144 2145 2146 2147 2148 2149

cleanup:
    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        VIR_FREE(vm->def->seclabel.model);
        VIR_FREE(vm->def->seclabel.label);
        VIR_FREE(vm->def->seclabel.imagelabel);
    }
2150
    qemuRemoveCgroup(conn, driver, vm);
2151 2152 2153 2154
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        vm->def->graphics[0]->data.vnc.autoport)
        vm->def->graphics[0]->data.vnc.port = -1;
2155 2156
    if (logfile != -1)
        close(logfile);
2157 2158
    vm->def->id = -1;
    return -1;
2159 2160 2161
}


2162
static void qemudShutdownVMDaemon(virConnectPtr conn,
2163 2164
                                  struct qemud_driver *driver,
                                  virDomainObjPtr vm) {
D
Daniel P. Berrange 已提交
2165
    int ret;
2166
    int retries = 0;
D
Daniel P. Berrange 已提交
2167

D
Daniel P. Berrange 已提交
2168
    if (!virDomainObjIsActive(vm))
2169
        return;
2170

2171
    VIR_DEBUG(_("Shutting down VM '%s'\n"), vm->def->name);
2172

G
Guido Günther 已提交
2173 2174
    if (virKillProcess(vm->pid, 0) == 0 &&
        virKillProcess(vm->pid, SIGTERM) < 0)
2175 2176 2177
        virReportSystemError(conn, errno,
                             _("Failed to send SIGTERM to %s (%d)"),
                             vm->def->name, vm->pid);
2178

2179 2180 2181
    if (vm->monitorWatch != -1) {
        virEventRemoveHandle(vm->monitorWatch);
        vm->monitorWatch = -1;
2182
    }
2183 2184 2185 2186 2187

    if (vm->monitor != -1)
        close(vm->monitor);
    vm->monitor = -1;

2188 2189 2190 2191 2192 2193 2194
    if (vm->monitor_chr) {
        if (vm->monitor_chr->type == VIR_DOMAIN_CHR_TYPE_UNIX)
            unlink(vm->monitor_chr->data.nix.path);
        virDomainChrDefFree(vm->monitor_chr);
        vm->monitor_chr = NULL;
    }

G
Guido Günther 已提交
2195 2196
    /* shut it off for sure */
    virKillProcess(vm->pid, SIGKILL);
2197

2198 2199 2200 2201
    /* Reset Security Labels */
    if (driver->securityDriver)
        driver->securityDriver->domainRestoreSecurityLabel(conn, vm);

2202 2203 2204 2205 2206 2207 2208
    /* Clear out dynamically assigned labels */
    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        VIR_FREE(vm->def->seclabel.model);
        VIR_FREE(vm->def->seclabel.label);
        VIR_FREE(vm->def->seclabel.imagelabel);
    }

2209 2210 2211 2212
    if (qemuDomainSetAllDeviceOwnership(conn, driver, vm->def, 1) < 0)
        VIR_WARN("Failed to restore all device ownership for %s",
                 vm->def->name);

2213
    qemuDomainReAttachHostDevices(conn, driver, vm->def);
2214

2215 2216 2217 2218 2219 2220 2221 2222 2223 2224
retry:
    if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) {
        if (ret == -EBUSY && (retries++ < 5)) {
            usleep(200*1000);
            goto retry;
        }
        VIR_WARN("Failed to remove cgroup for %s",
                 vm->def->name);
    }

2225
    qemudRemoveDomainStatus(conn, driver, vm);
D
Daniel P. Berrange 已提交
2226

2227
    vm->pid = -1;
2228
    vm->def->id = -1;
2229
    vm->state = VIR_DOMAIN_SHUTOFF;
2230
    VIR_FREE(vm->vcpupids);
2231
    vm->nvcpupids = 0;
2232 2233

    if (vm->newDef) {
2234
        virDomainDefFree(vm->def);
2235
        vm->def = vm->newDef;
2236
        vm->def->id = -1;
2237 2238 2239 2240 2241
        vm->newDef = NULL;
    }
}


2242
static void
2243
qemudDispatchVMEvent(int watch, int fd, int events, void *opaque) {
2244 2245
    struct qemud_driver *driver = qemu_driver;
    virDomainObjPtr vm = opaque;
2246
    virDomainEventPtr event = NULL;
2247
    int quit = 0, failed = 0;
2248

2249 2250 2251 2252 2253 2254
    /* XXX Normally we have to lock the driver first, to protect
     * against someone adding/removing the domain. We know,
     * however, then if we're getting data in this callback
     * the VM must be running. Nowhere is allowed to remove
     * a domain while it is running, so it is safe to not
     * lock the driver here... */
2255
    qemuDriverLock(driver);
2256 2257
    virDomainObjLock(vm);
    qemuDriverUnlock(driver);
2258

2259
    if (vm->monitor != fd || vm->monitorWatch != watch) {
2260 2261
        failed = 1;
    } else {
2262
        if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR))
2263
            quit = 1;
2264
        else {
2265 2266
            VIR_ERROR(_("unhandled fd event %d for %s"),
                      events, vm->def->name);
2267
            failed = 1;
2268
        }
2269 2270
    }

2271
    if (failed || quit) {
2272 2273 2274 2275 2276
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         quit ?
                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN :
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
2277 2278 2279 2280 2281 2282 2283 2284
        qemudShutdownVMDaemon(NULL, driver, vm);
        if (!vm->persistent) {
            virDomainRemoveInactive(&driver->domains,
                                    vm);
            vm = NULL;
        }
    }

2285 2286 2287
    virDomainObjUnlock(vm);
    if (event) {
        qemuDriverLock(driver);
2288
        qemuDomainEventQueue(driver, event);
2289 2290
        qemuDriverUnlock(driver);
    }
2291 2292
}

2293

2294

2295
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
2296
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
2297
                                  int flags ATTRIBUTE_UNUSED) {
2298
    if (conn->uri == NULL) {
2299 2300 2301
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

2302
        conn->uri = xmlParseURI(qemu_driver->privileged ?
2303 2304
                                "qemu:///system" :
                                "qemu:///session");
2305
        if (!conn->uri) {
2306
            virReportOOMError(conn);
2307 2308
            return VIR_DRV_OPEN_ERROR;
        }
2309 2310 2311 2312 2313 2314 2315 2316 2317 2318
    } 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;

2319 2320 2321 2322 2323 2324
        if (qemu_driver == NULL) {
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                             _("qemu state driver is not active"));
            return VIR_DRV_OPEN_ERROR;
        }

2325
        if (qemu_driver->privileged) {
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340
            if (STRNEQ (conn->uri->path, "/system") &&
                STRNEQ (conn->uri->path, "/session")) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 _("unexpected QEMU URI path '%s', try qemu:///system"),
                                 conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 _("unexpected QEMU URI path '%s', try qemu:///session"),
                                 conn->uri->path);
                return VIR_DRV_OPEN_ERROR;
            }
        }
2341 2342 2343 2344 2345 2346 2347
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
2348
    struct qemud_driver *driver = conn->privateData;
2349 2350

    /* Get rid of callbacks registered for this conn */
2351
    qemuDriverLock(driver);
2352
    virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
2353
    qemuDriverUnlock(driver);
2354 2355 2356 2357 2358 2359

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
2360 2361 2362 2363 2364
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
2365 2366 2367 2368 2369
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
2370 2371 2372
    }
}

2373
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
2374
    return "QEMU";
2375 2376
}

2377 2378 2379 2380 2381

static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
2382

2383 2384
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
2385 2386
        virReportSystemError(NULL, errno, _("Unable to open %s"), KVM_DEVICE);
        return -1;
2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397
    }

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

    close(fd);
    return maxvcpus;
}


2398
static int qemudGetMaxVCPUs(virConnectPtr conn, const char *type) {
2399 2400 2401
    if (!type)
        return 16;

2402
    if (STRCASEEQ(type, "qemu"))
2403 2404
        return 16;

2405
    if (STRCASEEQ(type, "kvm"))
2406
        return kvmGetMaxVCPUs();
2407

2408
    if (STRCASEEQ(type, "kqemu"))
2409
        return 1;
2410 2411 2412

    qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
                     _("unknown type '%s'"), type);
2413 2414 2415
    return -1;
}

2416

2417
static char *qemudGetCapabilities(virConnectPtr conn) {
2418
    struct qemud_driver *driver = conn->privateData;
2419
    virCapsPtr caps;
2420
    char *xml = NULL;
2421

2422
    qemuDriverLock(driver);
2423
    if ((caps = qemudCapsInit(qemu_driver->caps)) == NULL) {
2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
        virReportOOMError(conn);
        goto cleanup;
    }

    if (qemu_driver->securityDriver &&
        qemudSecurityCapsInit(qemu_driver->securityDriver, caps) < 0) {
        virCapabilitiesFree(caps);
        virReportOOMError(conn);
        goto cleanup;
    }

2435
    virCapabilitiesFree(qemu_driver->caps);
2436 2437 2438
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
2439
        virReportOOMError(conn);
2440 2441

cleanup:
2442
    qemuDriverUnlock(driver);
2443

2444
    return xml;
2445 2446 2447
}


2448
static int qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid, int tid) {
D
Daniel P. Berrange 已提交
2449 2450
    char proc[PATH_MAX];
    FILE *pidinfo;
2451
    unsigned long long usertime, systime;
2452 2453
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
2454

2455 2456 2457 2458 2459 2460
    if (tid)
        ret = snprintf(proc, sizeof(proc), "/proc/%d/task/%d/stat", pid, tid);
    else
        ret = snprintf(proc, sizeof(proc), "/proc/%d/stat", pid);
    if (ret >= (int)sizeof(proc)) {
        errno = E2BIG;
D
Daniel P. Berrange 已提交
2461 2462 2463 2464
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
2465
        /*printf("cannot read pid info");*/
D
Daniel P. Berrange 已提交
2466
        /* VM probably shut down, so fake 0 */
2467 2468 2469 2470
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
D
Daniel P. Berrange 已提交
2471 2472 2473
        return 0;
    }

2474 2475 2476 2477 2478 2479 2480 2481 2482 2483
    /* 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) {
2484
        fclose(pidinfo);
2485 2486
        VIR_WARN0("cannot parse process status data");
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
2487 2488 2489 2490 2491 2492 2493 2494
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
2495 2496 2497 2498 2499
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

D
Daniel P. Berrange 已提交
2500

2501 2502
    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
              pid, tid, usertime, systime, cpu);
D
Daniel P. Berrange 已提交
2503 2504 2505 2506 2507 2508 2509

    fclose(pidinfo);

    return 0;
}


2510
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
2511
                                          int id) {
2512 2513 2514 2515
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

2516
    qemuDriverLock(driver);
2517
    vm  = virDomainFindByID(&driver->domains, id);
2518
    qemuDriverUnlock(driver);
2519 2520

    if (!vm) {
2521 2522
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching id %d"), id);
2523
        goto cleanup;
2524 2525
    }

2526
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2527
    if (dom) dom->id = vm->def->id;
2528 2529

cleanup:
2530 2531
    if (vm)
        virDomainObjUnlock(vm);
2532 2533
    return dom;
}
2534

2535
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
2536
                                            const unsigned char *uuid) {
2537 2538 2539
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
2540

2541
    qemuDriverLock(driver);
2542
    vm = virDomainFindByUUID(&driver->domains, uuid);
2543 2544
    qemuDriverUnlock(driver);

2545
    if (!vm) {
2546 2547 2548
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN,
2549
                         _("no domain with matching uuid '%s'"), uuidstr);
2550
        goto cleanup;
2551 2552
    }

2553
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2554
    if (dom) dom->id = vm->def->id;
2555 2556

cleanup:
2557 2558
    if (vm)
        virDomainObjUnlock(vm);
2559 2560
    return dom;
}
2561

2562
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
2563
                                            const char *name) {
2564 2565 2566
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
2567

2568
    qemuDriverLock(driver);
2569
    vm = virDomainFindByName(&driver->domains, name);
2570 2571
    qemuDriverUnlock(driver);

2572
    if (!vm) {
2573 2574
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching name '%s'"), name);
2575
        goto cleanup;
2576 2577
    }

2578
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2579
    if (dom) dom->id = vm->def->id;
2580 2581

cleanup:
2582 2583
    if (vm)
        virDomainObjUnlock(vm);
2584 2585 2586
    return dom;
}

2587
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
2588 2589 2590
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

2591
    qemuDriverLock(driver);
2592
    if (qemudExtractVersion(conn, driver) < 0)
2593
        goto cleanup;
2594

2595
    *version = qemu_driver->qemuVersion;
2596 2597 2598
    ret = 0;

cleanup:
2599
    qemuDriverUnlock(driver);
2600
    return ret;
D
Daniel P. Berrange 已提交
2601 2602
}

2603
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
2604
    struct qemud_driver *driver = conn->privateData;
2605
    int n;
2606

2607
    qemuDriverLock(driver);
2608
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
2609
    qemuDriverUnlock(driver);
2610

2611
    return n;
D
Daniel P. Berrange 已提交
2612
}
2613

2614
static int qemudNumDomains(virConnectPtr conn) {
2615
    struct qemud_driver *driver = conn->privateData;
2616
    int n;
2617

2618
    qemuDriverLock(driver);
2619
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
2620
    qemuDriverUnlock(driver);
2621

2622
    return n;
D
Daniel P. Berrange 已提交
2623
}
2624

2625
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
2626
                                      unsigned int flags ATTRIBUTE_UNUSED) {
2627
    struct qemud_driver *driver = conn->privateData;
2628
    virDomainDefPtr def;
2629
    virDomainObjPtr vm = NULL;
2630
    virDomainPtr dom = NULL;
2631
    virDomainEventPtr event = NULL;
D
Daniel P. Berrange 已提交
2632

2633
    qemuDriverLock(driver);
2634 2635
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE)))
2636
        goto cleanup;
2637

2638 2639 2640
    if (virSecurityDriverVerify(conn, def) < 0)
        goto cleanup;

2641
    /* See if a VM with matching UUID already exists */
2642
    vm = virDomainFindByUUID(&driver->domains, def->uuid);
2643
    if (vm) {
2644 2645 2646 2647 2648 2649 2650 2651 2652
        /* UUID matches, but if names don't match, refuse it */
        if (STRNEQ(vm->def->name, def->name)) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                             _("domain '%s' is already defined with uuid %s"),
                             vm->def->name, uuidstr);
            goto cleanup;
        }
2653

2654
        /* UUID & name match, but if VM is already active, refuse it */
D
Daniel P. Berrange 已提交
2655
        if (virDomainObjIsActive(vm)) {
2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                             _("domain is already active as '%s'"), vm->def->name);
            goto cleanup;
        }
        virDomainObjUnlock(vm);
    } else {
        /* UUID does not match, but if a name matches, refuse it */
        vm = virDomainFindByName(&driver->domains, def->name);
        if (vm) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                             _("domain '%s' is already defined with uuid %s"),
                             def->name, uuidstr);
            goto cleanup;
        }
2672
    }
2673

2674
    if (!(vm = virDomainAssignDef(conn,
2675
                                  driver->caps,
2676
                                  &driver->domains,
2677 2678 2679 2680
                                  def)))
        goto cleanup;

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

2682
    if (qemudStartVMDaemon(conn, driver, vm, NULL, -1) < 0) {
2683 2684
        virDomainRemoveInactive(&driver->domains,
                                vm);
2685
        vm = NULL;
2686
        goto cleanup;
D
Daniel P. Berrange 已提交
2687
    }
2688 2689 2690 2691

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
D
Daniel P. Berrange 已提交
2692

2693
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2694
    if (dom) dom->id = vm->def->id;
2695 2696 2697

cleanup:
    virDomainDefFree(def);
2698 2699
    if (vm)
        virDomainObjUnlock(vm);
2700 2701
    if (event)
        qemuDomainEventQueue(driver, event);
2702
    qemuDriverUnlock(driver);
2703
    return dom;
D
Daniel P. Berrange 已提交
2704 2705 2706
}


2707
static int qemudDomainSuspend(virDomainPtr dom) {
2708 2709 2710
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2711
    virDomainEventPtr event = NULL;
2712

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

D
Daniel P. Berrange 已提交
2716
    if (!vm) {
2717 2718 2719 2720
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
2721
        goto cleanup;
D
Daniel P. Berrange 已提交
2722
    }
D
Daniel P. Berrange 已提交
2723
    if (!virDomainObjIsActive(vm)) {
2724
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2725
                         "%s", _("domain is not running"));
2726
        goto cleanup;
D
Daniel P. Berrange 已提交
2727
    }
2728
    if (vm->state != VIR_DOMAIN_PAUSED) {
2729
        if (qemuMonitorStopCPUs(vm) < 0)
2730 2731
            goto cleanup;
        vm->state = VIR_DOMAIN_PAUSED;
2732 2733 2734
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
D
Daniel P. Berrange 已提交
2735
    }
2736
    if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
2737
        goto cleanup;
2738 2739 2740
    ret = 0;

cleanup:
2741 2742
    if (vm)
        virDomainObjUnlock(vm);
2743

2744
    if (event)
2745
        qemuDomainEventQueue(driver, event);
2746
    qemuDriverUnlock(driver);
2747
    return ret;
D
Daniel P. Berrange 已提交
2748 2749 2750
}


2751
static int qemudDomainResume(virDomainPtr dom) {
2752 2753 2754
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2755
    virDomainEventPtr event = NULL;
2756

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

D
Daniel P. Berrange 已提交
2760
    if (!vm) {
2761 2762 2763 2764
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
2765
        goto cleanup;
D
Daniel P. Berrange 已提交
2766
    }
D
Daniel P. Berrange 已提交
2767
    if (!virDomainObjIsActive(vm)) {
2768
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2769
                         "%s", _("domain is not running"));
2770
        goto cleanup;
D
Daniel P. Berrange 已提交
2771
    }
2772
    if (vm->state == VIR_DOMAIN_PAUSED) {
2773
        if (qemuMonitorStartCPUs(dom->conn, vm) < 0) {
2774 2775 2776
            if (virGetLastError() == NULL)
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("resume operation failed"));
2777 2778 2779
            goto cleanup;
        }
        vm->state = VIR_DOMAIN_RUNNING;
2780 2781 2782
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
2783
    }
2784
    if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
2785
        goto cleanup;
2786 2787 2788
    ret = 0;

cleanup:
2789 2790
    if (vm)
        virDomainObjUnlock(vm);
2791
    if (event)
2792
        qemuDomainEventQueue(driver, event);
2793
    qemuDriverUnlock(driver);
2794
    return ret;
D
Daniel P. Berrange 已提交
2795 2796 2797
}


2798
static int qemudDomainShutdown(virDomainPtr dom) {
2799 2800 2801
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2802

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

2807
    if (!vm) {
2808 2809 2810 2811
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
2812
        goto cleanup;
2813 2814
    }

D
Daniel P. Berrange 已提交
2815
    if (!virDomainObjIsActive(vm)) {
2816 2817 2818 2819 2820
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
        goto cleanup;
    }

2821
    if (qemuMonitorSystemPowerdown(vm) < 0)
2822
        goto cleanup;
2823

2824 2825 2826
    ret = 0;

cleanup:
2827 2828
    if (vm)
        virDomainObjUnlock(vm);
2829
    return ret;
2830 2831 2832
}


2833
static int qemudDomainDestroy(virDomainPtr dom) {
2834 2835 2836
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2837
    virDomainEventPtr event = NULL;
2838

2839
    qemuDriverLock(driver);
2840
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
2841
    if (!vm) {
2842 2843 2844 2845
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
2846
        goto cleanup;
D
Daniel P. Berrange 已提交
2847
    }
D
Daniel P. Berrange 已提交
2848
    if (!virDomainObjIsActive(vm)) {
2849
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2850 2851 2852
                         "%s", _("domain is not running"));
        goto cleanup;
    }
2853

2854
    qemudShutdownVMDaemon(dom->conn, driver, vm);
2855 2856 2857
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
2858
    if (!vm->persistent) {
2859 2860
        virDomainRemoveInactive(&driver->domains,
                                vm);
2861 2862
        vm = NULL;
    }
2863 2864 2865
    ret = 0;

cleanup:
2866 2867
    if (vm)
        virDomainObjUnlock(vm);
2868 2869
    if (event)
        qemuDomainEventQueue(driver, event);
2870
    qemuDriverUnlock(driver);
2871
    return ret;
D
Daniel P. Berrange 已提交
2872 2873 2874
}


2875
static char *qemudDomainGetOSType(virDomainPtr dom) {
2876 2877 2878
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
2879

2880
    qemuDriverLock(driver);
2881
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2882
    qemuDriverUnlock(driver);
2883
    if (!vm) {
2884 2885 2886 2887
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
2888
        goto cleanup;
2889 2890
    }

2891
    if (!(type = strdup(vm->def->os.type)))
2892
        virReportOOMError(dom->conn);
2893 2894

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

2900 2901
/* Returns max memory in kb, 0 if error */
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
2902 2903 2904
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
2905

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

2910
    if (!vm) {
2911 2912
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2913
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
2914
                         _("no domain with matching uuid '%s'"), uuidstr);
2915
        goto cleanup;
2916 2917
    }

2918 2919 2920
    ret = vm->def->maxmem;

cleanup:
2921 2922
    if (vm)
        virDomainObjUnlock(vm);
2923
    return ret;
2924 2925 2926
}

static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
2927 2928 2929
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2930

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

2935
    if (!vm) {
2936 2937
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2938
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
2939
                         _("no domain with matching uuid '%s'"), uuidstr);
2940
        goto cleanup;
2941 2942 2943 2944
    }

    if (newmax < vm->def->memory) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
2945
                         "%s", _("cannot set max memory lower than current memory"));
2946
        goto cleanup;;
2947 2948 2949
    }

    vm->def->maxmem = newmax;
2950 2951 2952
    ret = 0;

cleanup:
2953 2954
    if (vm)
        virDomainObjUnlock(vm);
2955
    return ret;
2956 2957
}

2958

2959
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
2960 2961 2962
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2963

2964
    qemuDriverLock(driver);
2965
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2966
    qemuDriverUnlock(driver);
2967
    if (!vm) {
2968 2969
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2970
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
2971
                         _("no domain with matching uuid '%s'"), uuidstr);
2972
        goto cleanup;
2973 2974 2975 2976
    }

    if (newmem > vm->def->maxmem) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
2977
                         "%s", _("cannot set memory higher than max memory"));
2978
        goto cleanup;
2979 2980
    }

D
Daniel P. Berrange 已提交
2981
    if (virDomainObjIsActive(vm)) {
2982 2983 2984 2985 2986 2987
        int r = qemuMonitorSetBalloon(vm, newmem);
        if (r < 0)
            goto cleanup;

        /* Lack of balloon support is a fatal error */
        if (r == 0) {
2988 2989
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                             "%s", _("cannot set memory of an active domain"));
2990
            goto cleanup;
2991
        }
2992 2993 2994
    } else {
        vm->def->memory = newmem;
    }
2995
    ret = 0;
2996 2997

cleanup:
2998 2999
    if (vm)
        virDomainObjUnlock(vm);
3000
    return ret;
3001 3002
}

3003
static int qemudDomainGetInfo(virDomainPtr dom,
3004
                              virDomainInfoPtr info) {
3005 3006 3007
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
3008 3009
    int err;
    unsigned long balloon;
3010

3011
    qemuDriverLock(driver);
3012
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3013
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
3014
    if (!vm) {
3015 3016 3017 3018
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
3019
        goto cleanup;
D
Daniel P. Berrange 已提交
3020 3021
    }

3022
    info->state = vm->state;
D
Daniel P. Berrange 已提交
3023

D
Daniel P. Berrange 已提交
3024
    if (!virDomainObjIsActive(vm)) {
3025
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
3026
    } else {
3027
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
3028
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, ("cannot read cputime for domain"));
3029
            goto cleanup;
D
Daniel P. Berrange 已提交
3030 3031 3032
        }
    }

3033
    info->maxMem = vm->def->maxmem;
3034

D
Daniel P. Berrange 已提交
3035
    if (virDomainObjIsActive(vm)) {
3036
        err = qemuMonitorGetBalloonInfo(vm, &balloon);
3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048
        if (err < 0)
            goto cleanup;

        if (err == 0)
            /* Balloon not supported, so maxmem is always the allocation */
            info->memory = vm->def->maxmem;
        else
            info->memory = balloon;
    } else {
        info->memory = vm->def->memory;
    }

3049
    info->nrVirtCpu = vm->def->vcpus;
3050 3051 3052
    ret = 0;

cleanup:
3053 3054
    if (vm)
        virDomainObjUnlock(vm);
3055
    return ret;
D
Daniel P. Berrange 已提交
3056 3057 3058
}


3059
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
3060 3061 3062
#define QEMUD_SAVE_VERSION 2

enum qemud_save_formats {
3063 3064 3065
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
3066 3067
    /*
     * Deprecated by xz and never used as part of a release
3068
     * QEMUD_SAVE_FORMAT_LZMA
3069 3070
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
3071
    QEMUD_SAVE_FORMAT_LZOP = 4,
3072 3073 3074
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
3075 3076

    QEMUD_SAVE_FORMAT_LAST
3077
};
3078

3079 3080 3081 3082 3083
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
3084 3085
              "xz",
              "lzop")
3086

3087 3088 3089 3090 3091
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
    int version;
    int xml_len;
    int was_running;
3092 3093
    int compressed;
    int unused[15];
3094 3095
};

3096
static int qemudDomainSave(virDomainPtr dom,
3097 3098
                           const char *path)
{
3099
    struct qemud_driver *driver = dom->conn->privateData;
3100
    virDomainObjPtr vm = NULL;
3101 3102
    int fd = -1;
    char *xml = NULL;
3103
    struct qemud_save_header header;
3104
    int ret = -1;
3105
    virDomainEventPtr event = NULL;
3106 3107 3108 3109 3110

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

3111
    qemuDriverLock(driver);
3112 3113 3114
    if (driver->saveImageFormat == NULL)
        header.compressed = QEMUD_SAVE_FORMAT_RAW;
    else {
3115 3116 3117 3118 3119 3120
        header.compressed =
            qemudSaveCompressionTypeFromString(driver->saveImageFormat);
        if (header.compressed < 0) {
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                             "%s", _("Invalid save image format specified "
                                     "in configuration file"));
3121
            goto cleanup;
3122
        }
3123 3124
    }

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

D
Daniel P. Berrange 已提交
3127
    if (!vm) {
3128 3129 3130 3131
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
3132
        goto cleanup;
D
Daniel P. Berrange 已提交
3133
    }
3134

D
Daniel P. Berrange 已提交
3135
    if (!virDomainObjIsActive(vm)) {
3136
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3137
                         "%s", _("domain is not running"));
3138
        goto cleanup;
D
Daniel P. Berrange 已提交
3139
    }
3140 3141 3142 3143

    /* Pause */
    if (vm->state == VIR_DOMAIN_RUNNING) {
        header.was_running = 1;
3144
        if (qemuMonitorStopCPUs(vm) < 0)
3145
            goto cleanup;
3146
        vm->state = VIR_DOMAIN_PAUSED;
3147 3148 3149
    }

    /* Get XML for the domain */
3150
    xml = virDomainDefFormat(dom->conn, vm->def, VIR_DOMAIN_XML_SECURE);
3151 3152
    if (!xml) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
3153
                         "%s", _("failed to get domain xml"));
3154
        goto cleanup;
3155 3156 3157 3158 3159 3160
    }
    header.xml_len = strlen(xml) + 1;

    /* Write header to file, followed by XML */
    if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
3161
                         _("failed to create '%s'"), path);
3162
        goto cleanup;
3163 3164 3165 3166
    }

    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
3167
                         "%s", _("failed to write save header"));
3168
        goto cleanup;
3169 3170 3171 3172
    }

    if (safewrite(fd, xml, header.xml_len) != header.xml_len) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
3173
                         "%s", _("failed to write xml"));
3174
        goto cleanup;
3175 3176
    }

3177
    if (close(fd) < 0) {
3178 3179 3180
        virReportSystemError(dom->conn, errno,
                             _("unable to save file %s"),
                             path);
3181 3182 3183
        goto cleanup;
    }
    fd = -1;
3184

3185 3186
    if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = { "cat", NULL };
3187
        ret = qemuMonitorMigrateToCommand(vm, 0, args, path);
3188
    } else {
3189
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
3190 3191 3192 3193 3194
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
3195
        ret = qemuMonitorMigrateToCommand(vm, 0, args, path);
3196 3197
    }

3198
    if (ret < 0)
3199
        goto cleanup;
3200

3201 3202
    /* Shut it down */
    qemudShutdownVMDaemon(dom->conn, driver, vm);
3203 3204 3205
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
3206
    if (!vm->persistent) {
3207 3208
        virDomainRemoveInactive(&driver->domains,
                                vm);
3209 3210
        vm = NULL;
    }
3211 3212 3213 3214 3215 3216 3217

cleanup:
    if (fd != -1)
        close(fd);
    VIR_FREE(xml);
    if (ret != 0)
        unlink(path);
3218 3219
    if (vm)
        virDomainObjUnlock(vm);
3220 3221
    if (event)
        qemuDomainEventQueue(driver, event);
3222
    qemuDriverUnlock(driver);
3223
    return ret;
D
Daniel P. Berrange 已提交
3224 3225 3226
}


P
Paolo Bonzini 已提交
3227 3228 3229 3230 3231 3232 3233
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;
    int ret = -1;
3234 3235 3236 3237
    const char *args[] = {
        "cat",
        NULL,
    };
P
Paolo Bonzini 已提交
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250

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

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

D
Daniel P. Berrange 已提交
3251
    if (!virDomainObjIsActive(vm)) {
P
Paolo Bonzini 已提交
3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
        goto cleanup;
    }

    /* Migrate will always stop the VM, so once we support live dumping
       the resume condition will stay the same, independent of whether
       the stop command is issued.  */
    resume = (vm->state == VIR_DOMAIN_RUNNING);

    /* Pause domain for non-live dump */
    if (vm->state == VIR_DOMAIN_RUNNING) {
3264
        if (qemuMonitorStopCPUs(vm) < 0)
P
Paolo Bonzini 已提交
3265 3266 3267 3268
            goto cleanup;
        paused = 1;
    }

3269
    ret = qemuMonitorMigrateToCommand(vm, 0, args, path);
P
Paolo Bonzini 已提交
3270 3271 3272 3273 3274 3275 3276
    paused = 1;
cleanup:

    /* 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.  */
    if (resume && paused) {
3277
        if (qemuMonitorStartCPUs(dom->conn, vm) < 0) {
3278 3279 3280
            if (virGetLastError() == NULL)
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3281 3282 3283 3284 3285 3286 3287 3288
        }
    }
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


3289
static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
3290 3291
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3292
    int max;
3293
    int ret = -1;
3294
    const char *type;
3295

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

3300
    if (!vm) {
3301 3302
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3303
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
3304
                         _("no domain with matching uuid '%s'"), uuidstr);
3305
        goto cleanup;
3306 3307
    }

D
Daniel P. Berrange 已提交
3308
    if (virDomainObjIsActive(vm)) {
3309
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID, "%s",
3310
                         _("cannot change vcpu count of an active domain"));
3311
        goto cleanup;
3312 3313
    }

3314 3315 3316 3317 3318 3319 3320 3321
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("unknown virt type in domain definition '%d'"),
                         vm->def->virtType);
        goto cleanup;
    }

    if ((max = qemudGetMaxVCPUs(dom->conn, type)) < 0) {
3322 3323
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                         _("could not determine max vcpus for the domain"));
3324
        goto cleanup;
3325 3326 3327 3328 3329 3330
    }

    if (nvcpus > max) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                         _("requested vcpus is greater than max allowable"
                           " vcpus for the domain: %d > %d"), nvcpus, max);
3331
        goto cleanup;
3332 3333 3334
    }

    vm->def->vcpus = nvcpus;
3335 3336 3337
    ret = 0;

cleanup:
3338 3339
    if (vm)
        virDomainObjUnlock(vm);
3340
    return ret;
3341 3342
}

3343 3344 3345 3346 3347 3348 3349

#if HAVE_SCHED_GETAFFINITY
static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
3350 3351
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3352 3353 3354
    cpu_set_t mask;
    int i, maxcpu;
    virNodeInfo nodeinfo;
3355
    int ret = -1;
3356

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

3361 3362 3363 3364 3365 3366 3367 3368
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
3369
    if (!virDomainObjIsActive(vm)) {
3370
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3371
                         "%s",_("cannot pin vcpus on an inactive domain"));
3372
        goto cleanup;
3373 3374 3375 3376 3377 3378
    }

    if (vcpu > (vm->nvcpupids-1)) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                         _("vcpu number out of range %d > %d"),
                         vcpu, vm->nvcpupids);
3379
        goto cleanup;
3380 3381
    }

3382
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
3383
        goto cleanup;
3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396

    maxcpu = maplen * 8;
    if (maxcpu > nodeinfo.cpus)
        maxcpu = nodeinfo.cpus;

    CPU_ZERO(&mask);
    for (i = 0 ; i < maxcpu ; i++) {
        if ((cpumap[i/8] >> (i % 8)) & 1)
            CPU_SET(i, &mask);
    }

    if (vm->vcpupids != NULL) {
        if (sched_setaffinity(vm->vcpupids[vcpu], sizeof(mask), &mask) < 0) {
3397 3398
            virReportSystemError(dom->conn, errno, "%s",
                                 _("cannot set affinity"));
3399
            goto cleanup;
3400 3401 3402 3403
        }
    } else {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         "%s", _("cpu affinity is not supported"));
3404
        goto cleanup;
3405
    }
3406
    ret = 0;
3407

3408
cleanup:
3409 3410
    if (vm)
        virDomainObjUnlock(vm);
3411
    return ret;
3412 3413 3414 3415 3416 3417 3418 3419
}

static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
3420 3421
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3422 3423
    virNodeInfo nodeinfo;
    int i, v, maxcpu;
3424
    int ret = -1;
3425

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

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

D
Daniel P. Berrange 已提交
3438
    if (!virDomainObjIsActive(vm)) {
3439
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3440 3441
                         "%s",
                         _("cannot list vcpu pinning for an inactive domain"));
3442
        goto cleanup;
3443 3444
    }

3445
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
3446
        goto cleanup;
3447 3448 3449 3450 3451 3452 3453 3454 3455

    maxcpu = maplen * 8;
    if (maxcpu > nodeinfo.cpus)
        maxcpu = nodeinfo.cpus;

    /* Clamp to actual number of vcpus */
    if (maxinfo > vm->nvcpupids)
        maxinfo = vm->nvcpupids;

3456 3457 3458 3459 3460 3461
    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;
3462 3463 3464 3465 3466 3467 3468 3469 3470 3471

                if (vm->vcpupids != NULL &&
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
                                        vm->pid,
                                        vm->vcpupids[i]) < 0) {
                    virReportSystemError(dom->conn, errno, "%s",
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
3472
            }
3473 3474
        }

3475 3476 3477 3478 3479 3480 3481 3482 3483
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
            if (vm->vcpupids != NULL) {
                for (v = 0 ; v < maxinfo ; v++) {
                    cpu_set_t mask;
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
                    CPU_ZERO(&mask);

                    if (sched_getaffinity(vm->vcpupids[v], sizeof(mask), &mask) < 0) {
3484 3485
                        virReportSystemError(dom->conn, errno, "%s",
                                             _("cannot get affinity"));
3486 3487 3488 3489 3490 3491
                        goto cleanup;
                    }

                    for (i = 0 ; i < maxcpu ; i++)
                        if (CPU_ISSET(i, &mask))
                            VIR_USE_CPU(cpumap, i);
3492
                }
3493 3494 3495 3496
            } else {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                                 "%s", _("cpu affinity is not available"));
                goto cleanup;
3497 3498 3499
            }
        }
    }
3500
    ret = maxinfo;
3501

3502
cleanup:
3503 3504
    if (vm)
        virDomainObjUnlock(vm);
3505
    return ret;
3506 3507 3508 3509
}
#endif /* HAVE_SCHED_GETAFFINITY */


3510
static int qemudDomainGetMaxVcpus(virDomainPtr dom) {
3511 3512
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3513
    const char *type;
3514
    int ret = -1;
3515

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

3520
    if (!vm) {
3521 3522
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3523
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
3524
                         _("no domain with matching uuid '%s'"), uuidstr);
3525
        goto cleanup;
3526 3527
    }

3528
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
3529 3530 3531
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("unknown virt type in domain definition '%d'"),
                         vm->def->virtType);
3532
        goto cleanup;
3533 3534
    }

3535
    ret = qemudGetMaxVCPUs(dom->conn, type);
3536

3537
cleanup:
3538 3539
    if (vm)
        virDomainObjUnlock(vm);
3540 3541 3542
    return ret;
}

3543 3544 3545 3546 3547 3548 3549 3550 3551 3552
static int qemudDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
    virDomainObjPtr vm;
    const char *type;
    int ret = -1;

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

3553 3554
    memset(seclabel, 0, sizeof(*seclabel));

3555 3556 3557
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3558
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583
                         _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("unknown virt type in domain definition '%d'"),
                         vm->def->virtType);
        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 已提交
3584
    if (virDomainObjIsActive(vm)) {
3585 3586 3587
        if (driver->securityDriver && driver->securityDriver->domainGetSecurityLabel) {
            if (driver->securityDriver->domainGetSecurityLabel(dom->conn, vm, seclabel) == -1) {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
3588
                                 "%s", _("Failed to get security label"));
3589 3590 3591 3592 3593 3594 3595 3596 3597 3598
                goto cleanup;
            }
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
3599
    qemuDriverUnlock(driver);
3600 3601 3602
    return ret;
}

3603 3604
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
3605 3606 3607
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
3608
    int ret = 0;
3609

3610 3611
    qemuDriverLock(driver);
    if (!driver->securityDriver) {
3612
        memset(secmodel, 0, sizeof (*secmodel));
3613 3614
        goto cleanup;
    }
3615

3616 3617 3618 3619 3620
    p = driver->caps->host.secModel.model;
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("security model string exceeds max %d bytes"),
                         VIR_SECURITY_MODEL_BUFLEN-1);
3621 3622
        ret = -1;
        goto cleanup;
3623 3624 3625 3626 3627 3628 3629 3630
    }
    strcpy(secmodel->model, p);

    p = driver->caps->host.secModel.doi;
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("security DOI string exceeds max %d bytes"),
                         VIR_SECURITY_DOI_BUFLEN-1);
3631 3632
        ret = -1;
        goto cleanup;
3633 3634
    }
    strcpy(secmodel->doi, p);
3635 3636 3637 3638

cleanup:
    qemuDriverUnlock(driver);
    return ret;
3639 3640 3641
}

/* TODO: check seclabel restore */
3642
static int qemudDomainRestore(virConnectPtr conn,
3643 3644 3645
                              const char *path) {
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
3646
    virDomainObjPtr vm = NULL;
3647 3648 3649
    int fd = -1;
    int ret = -1;
    char *xml = NULL;
3650
    struct qemud_save_header header;
3651
    virDomainEventPtr event = NULL;
3652 3653 3654
    int intermediatefd = -1;
    pid_t intermediate_pid = -1;
    int childstat;
3655

3656
    qemuDriverLock(driver);
3657 3658 3659
    /* Verify the header and read the XML */
    if ((fd = open(path, O_RDONLY)) < 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3660
                         "%s", _("cannot read domain image"));
3661
        goto cleanup;
3662 3663 3664 3665
    }

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3666
                         "%s", _("failed to read qemu header"));
3667
        goto cleanup;
3668 3669 3670 3671
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3672
                         "%s", _("image magic is incorrect"));
3673
        goto cleanup;
3674 3675 3676 3677
    }

    if (header.version > QEMUD_SAVE_VERSION) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3678
                         _("image version is not supported (%d > %d)"),
3679
                         header.version, QEMUD_SAVE_VERSION);
3680
        goto cleanup;
3681 3682
    }

3683
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
3684
        virReportOOMError(conn);
3685
        goto cleanup;
3686 3687 3688 3689
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3690
                         "%s", _("failed to read XML"));
3691
        goto cleanup;
3692 3693 3694
    }

    /* Create a domain from this XML */
3695 3696
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE))) {
3697
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3698
                         "%s", _("failed to parse XML"));
3699
        goto cleanup;
3700 3701
    }

3702
    /* See if a VM with matching UUID already exists */
3703
    vm = virDomainFindByUUID(&driver->domains, def->uuid);
3704
    if (vm) {
3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715
        /* UUID matches, but if names don't match, refuse it */
        if (STRNEQ(vm->def->name, def->name)) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                             _("domain '%s' is already defined with uuid %s"),
                             vm->def->name, uuidstr);
            goto cleanup;
        }

        /* UUID & name match, but if VM is already active, refuse it */
D
Daniel P. Berrange 已提交
3716
        if (virDomainObjIsActive(vm)) {
3717
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_INVALID,
3718 3719
                             _("domain is already active as '%s'"), vm->def->name);
            goto cleanup;
3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731
        }
        virDomainObjUnlock(vm);
    } else {
        /* UUID does not match, but if a name matches, refuse it */
        vm = virDomainFindByName(&driver->domains, def->name);
        if (vm) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                             _("domain '%s' is already defined with uuid %s"),
                             def->name, uuidstr);
            goto cleanup;
3732
        }
3733 3734
    }

3735
    if (!(vm = virDomainAssignDef(conn,
3736
                                  driver->caps,
3737 3738
                                  &driver->domains,
                                  def))) {
3739
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3740
                         "%s", _("failed to assign new VM"));
3741
        goto cleanup;
3742
    }
3743
    def = NULL;
3744

3745 3746
    if (header.version == 2) {
        const char *intermediate_argv[3] = { NULL, "-dc", NULL };
3747 3748
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
        if (prog == NULL) {
3749
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3750
                             _("Invalid compressed save format %d"),
3751 3752 3753
                             header.compressed);
            goto cleanup;
        }
3754

3755
        if (header.compressed != QEMUD_SAVE_FORMAT_RAW) {
3756
            intermediate_argv[0] = prog;
3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767
            intermediatefd = fd;
            fd = -1;
            if (virExec(conn, intermediate_argv, NULL, NULL,
                        &intermediate_pid, intermediatefd, &fd, NULL, 0) < 0) {
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 _("Failed to start decompression binary %s"),
                                 intermediate_argv[0]);
                goto cleanup;
            }
        }
    }
3768
    /* Set the migration source and start it up. */
3769
    ret = qemudStartVMDaemon(conn, driver, vm, "stdio", fd);
3770 3771 3772 3773 3774 3775 3776
    if (intermediate_pid != -1) {
        /* Wait for intermediate process to exit */
        while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
               errno == EINTR);
    }
    if (intermediatefd != -1)
        close(intermediatefd);
3777
    close(fd);
3778
    fd = -1;
3779
    if (ret < 0) {
3780
        if (!vm->persistent) {
3781 3782
            virDomainRemoveInactive(&driver->domains,
                                    vm);
3783 3784
            vm = NULL;
        }
3785
        goto cleanup;
3786 3787
    }

3788 3789 3790
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
3791

3792 3793
    /* If it was running before, resume it now. */
    if (header.was_running) {
3794
        if (qemuMonitorStartCPUs(conn, vm) < 0) {
3795 3796 3797
            if (virGetLastError() == NULL)
                qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("failed to resume domain"));
3798
            goto cleanup;
3799 3800
        }
        vm->state = VIR_DOMAIN_RUNNING;
3801
        virDomainSaveStatus(conn, driver->stateDir, vm);
3802
    }
3803
    ret = 0;
3804

3805 3806 3807 3808 3809
cleanup:
    virDomainDefFree(def);
    VIR_FREE(xml);
    if (fd != -1)
        close(fd);
3810 3811
    if (vm)
        virDomainObjUnlock(vm);
3812 3813
    if (event)
        qemuDomainEventQueue(driver, event);
3814
    qemuDriverUnlock(driver);
3815
    return ret;
D
Daniel P. Berrange 已提交
3816 3817 3818
}


3819
static char *qemudDomainDumpXML(virDomainPtr dom,
3820
                                int flags) {
3821 3822 3823
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
3824 3825
    unsigned long balloon;
    int err;
3826

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

D
Daniel P. Berrange 已提交
3831
    if (!vm) {
3832 3833 3834 3835
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
3836
        goto cleanup;
D
Daniel P. Berrange 已提交
3837 3838
    }

3839
    /* Refresh current memory based on balloon info */
D
Daniel P. Berrange 已提交
3840
    if (virDomainObjIsActive(vm)) {
3841 3842 3843 3844 3845 3846 3847
        err = qemuMonitorGetBalloonInfo(vm, &balloon);
        if (err < 0)
            goto cleanup;
        if (err > 0)
            vm->def->memory = balloon;
        /* err == 0 indicates no balloon support, so ignore it */
    }
3848

3849 3850 3851 3852 3853 3854
    ret = virDomainDefFormat(dom->conn,
                             (flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
                             vm->newDef : vm->def,
                             flags);

cleanup:
3855 3856
    if (vm)
        virDomainObjUnlock(vm);
3857
    return ret;
D
Daniel P. Berrange 已提交
3858 3859 3860
}


3861 3862 3863 3864
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
                                     unsigned int flags ATTRIBUTE_UNUSED) {
3865
    struct qemud_driver *driver = conn->privateData;
3866 3867 3868 3869 3870 3871 3872 3873 3874
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
                         _("unsupported config type %s"), format);
        goto cleanup;
    }

3875
    qemuDriverLock(driver);
3876
    def = qemuParseCommandLineString(conn, driver->caps, config);
3877
    qemuDriverUnlock(driver);
3878 3879 3880 3881 3882 3883 3884 3885 3886 3887
    if (!def)
        goto cleanup;

    xml = virDomainDefFormat(conn, def, VIR_DOMAIN_XML_INACTIVE);

cleanup:
    virDomainDefFree(def);
    return xml;
}

3888 3889 3890 3891 3892 3893
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;
3894
    virDomainChrDef monitor_chr;
3895 3896 3897 3898 3899 3900 3901 3902 3903 3904
    const char *emulator;
    unsigned int qemuCmdFlags;
    struct stat sb;
    const char **retargv = NULL;
    const char **retenv = NULL;
    const char **tmp;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *ret = NULL;
    int i;

3905 3906
    qemuDriverLock(driver);

3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
                         _("unsupported config type %s"), format);
        goto cleanup;
    }

    def = virDomainDefParseString(conn, driver->caps, xmlData, 0);
    if (!def)
        goto cleanup;

    /* Since we're just exporting args, we can't do bridge/network
     * setups, since libvirt will normally create TAP devices
     * 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];
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            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;
        }
    }
    for (i = 0 ; i < def->ngraphics ; i++) {
        if (def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
            def->graphics[i]->data.vnc.autoport)
            def->graphics[i]->data.vnc.port = 5900;
    }
    emulator = def->emulator;

    /* Make sure the binary we are about to try exec'ing exists.
     * Technically we could catch the exec() failure, but that's
     * in a sub-process so its hard to feed back a useful error
     */
    if (stat(emulator, &sb) < 0) {
        virReportSystemError(conn, errno,
                             _("Cannot find QEMU binary %s"),
                             emulator);
        goto cleanup;
    }

    if (qemudExtractVersionInfo(emulator,
                                NULL,
                                &qemuCmdFlags) < 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Cannot determine QEMU argv syntax %s"),
                         emulator);
        goto cleanup;
    }

3973 3974
    if (qemuPrepareMonitorChr(conn, driver, &monitor_chr, def->name) < 0)
        goto cleanup;
3975 3976

    if (qemudBuildCommandLine(conn, driver, def,
3977
                              &monitor_chr, qemuCmdFlags,
3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002
                              &retargv, &retenv,
                              NULL, NULL, /* Don't want it to create TAP devices */
                              NULL) < 0) {
        goto cleanup;
    }

    tmp = retenv;
    while (*tmp) {
        virBufferAdd(&buf, *tmp, strlen(*tmp));
        virBufferAddLit(&buf, " ");
        tmp++;
    }
    tmp = retargv;
    while (*tmp) {
        virBufferAdd(&buf, *tmp, strlen(*tmp));
        virBufferAddLit(&buf, " ");
        tmp++;
    }

    if (virBufferError(&buf))
        goto cleanup;

    ret = virBufferContentAndReset(&buf);

cleanup:
4003
    qemuDriverUnlock(driver);
4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016
    for (tmp = retargv ; tmp && *tmp ; tmp++)
        VIR_FREE(*tmp);
    VIR_FREE(retargv);

    for (tmp = retenv ; tmp && *tmp ; tmp++)
        VIR_FREE(*tmp);
    VIR_FREE(retenv);

    virDomainDefFree(def);
    return ret;
}


4017
static int qemudListDefinedDomains(virConnectPtr conn,
4018
                            char **const names, int nnames) {
4019
    struct qemud_driver *driver = conn->privateData;
4020
    int n;
4021

4022
    qemuDriverLock(driver);
4023
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
4024
    qemuDriverUnlock(driver);
4025
    return n;
D
Daniel P. Berrange 已提交
4026 4027
}

4028
static int qemudNumDefinedDomains(virConnectPtr conn) {
4029
    struct qemud_driver *driver = conn->privateData;
4030
    int n;
4031

4032
    qemuDriverLock(driver);
4033
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
4034
    qemuDriverUnlock(driver);
4035

4036
    return n;
D
Daniel P. Berrange 已提交
4037 4038 4039
}


4040
static int qemudDomainStart(virDomainPtr dom) {
4041 4042 4043
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4044
    virDomainEventPtr event = NULL;
4045

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

4049
    if (!vm) {
4050 4051 4052 4053
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
4054
        goto cleanup;
4055 4056
    }

4057
    ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL, -1);
4058
    if (ret != -1)
4059 4060 4061
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
4062 4063

cleanup:
4064 4065
    if (vm)
        virDomainObjUnlock(vm);
4066
    if (event)
4067
        qemuDomainEventQueue(driver, event);
4068
    qemuDriverUnlock(driver);
4069
    return ret;
D
Daniel P. Berrange 已提交
4070 4071
}

4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086
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;

4087
        if (STRNEQ(def->os.machine, machine->name))
4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
            virReportOOMError(NULL);
            return -1;
        }

        break;
    }

    return 0;
}

4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
    int i, nmachines = 0;

    if (qemudProbeMachineTypes(def->emulator, &machines, &nmachines) < 0) {
        virReportOOMError(NULL);
        return -1;
    }

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

4116
        if (STRNEQ(def->os.machine, machines[i]->name))
4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

4129 4130
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
4131 4132 4133 4134 4135 4136
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
4137
        virCapsGuestDomainInfoPtr info;
4138 4139 4140
        int j;

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

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

4154 4155 4156 4157
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
4158 4159 4160 4161
                return -1;
            goto out;
        }
    }
4162 4163 4164 4165

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

4166 4167 4168 4169 4170 4171 4172
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
4173

4174
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
4175
    struct qemud_driver *driver = conn->privateData;
4176
    virDomainDefPtr def;
4177
    virDomainObjPtr vm = NULL;
4178
    virDomainPtr dom = NULL;
4179
    virDomainEventPtr event = NULL;
4180
    int newVM = 1;
4181

4182
    qemuDriverLock(driver);
4183 4184
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE)))
4185
        goto cleanup;
4186

4187 4188 4189
    if (virSecurityDriverVerify(conn, def) < 0)
        goto cleanup;

4190 4191
    /* See if a VM with matching UUID already exists */
    vm = virDomainFindByUUID(&driver->domains, def->uuid);
4192
    if (vm) {
4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203
        /* UUID matches, but if names don't match, refuse it */
        if (STRNEQ(vm->def->name, def->name)) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                             _("domain '%s' is already defined with uuid %s"),
                             vm->def->name, uuidstr);
            goto cleanup;
        }

        /* UUID & name match */
4204
        virDomainObjUnlock(vm);
4205
        newVM = 0;
4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216
    } else {
        /* UUID does not match, but if a name matches, refuse it */
        vm = virDomainFindByName(&driver->domains, def->name);
        if (vm) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                             _("domain '%s' is already defined with uuid %s"),
                             def->name, uuidstr);
            goto cleanup;
        }
4217
    }
4218

4219
    if (qemudCanonicalizeMachine(driver, def) < 0)
4220 4221
        goto cleanup;

4222
    if (!(vm = virDomainAssignDef(conn,
4223
                                  driver->caps,
4224 4225
                                  &driver->domains,
                                  def))) {
4226
        goto cleanup;
4227
    }
4228
    def = NULL;
4229
    vm->persistent = 1;
4230

4231 4232
    if (virDomainSaveConfig(conn,
                            driver->configDir,
4233
                            vm->newDef ? vm->newDef : vm->def) < 0) {
4234 4235
        virDomainRemoveInactive(&driver->domains,
                                vm);
4236
        vm = NULL;
4237
        goto cleanup;
4238 4239
    }

4240 4241 4242 4243 4244
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     newVM ?
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
4245

4246
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4247
    if (dom) dom->id = vm->def->id;
4248 4249

cleanup:
4250
    virDomainDefFree(def);
4251 4252
    if (vm)
        virDomainObjUnlock(vm);
4253 4254
    if (event)
        qemuDomainEventQueue(driver, event);
4255
    qemuDriverUnlock(driver);
4256
    return dom;
D
Daniel P. Berrange 已提交
4257 4258
}

4259
static int qemudDomainUndefine(virDomainPtr dom) {
4260 4261
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4262
    virDomainEventPtr event = NULL;
4263
    int ret = -1;
D
Daniel P. Berrange 已提交
4264

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

D
Daniel P. Berrange 已提交
4268
    if (!vm) {
4269 4270 4271 4272
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
4273
        goto cleanup;
D
Daniel P. Berrange 已提交
4274 4275
    }

D
Daniel P. Berrange 已提交
4276
    if (virDomainObjIsActive(vm)) {
4277
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
4278
                         "%s", _("cannot delete active domain"));
4279
        goto cleanup;
D
Daniel P. Berrange 已提交
4280 4281
    }

4282 4283 4284
    if (!vm->persistent) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot undefine transient domain"));
4285
        goto cleanup;
4286 4287 4288
    }

    if (virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm) < 0)
4289
        goto cleanup;
D
Daniel P. Berrange 已提交
4290

4291 4292 4293
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
4294

4295 4296
    virDomainRemoveInactive(&driver->domains,
                            vm);
4297
    vm = NULL;
4298
    ret = 0;
D
Daniel P. Berrange 已提交
4299

4300
cleanup:
4301 4302
    if (vm)
        virDomainObjUnlock(vm);
4303 4304
    if (event)
        qemuDomainEventQueue(driver, event);
4305
    qemuDriverUnlock(driver);
4306
    return ret;
D
Daniel P. Berrange 已提交
4307 4308
}

4309
/* Return the disks name for use in monitor commands */
4310
static char *qemudDiskDeviceName(const virConnectPtr conn,
4311
                                 const virDomainDiskDefPtr disk) {
4312 4313 4314 4315 4316 4317

    int busid, devid;
    int ret;
    char *devname;

    if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0) {
4318
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
4319 4320 4321 4322 4323 4324 4325
                         _("cannot convert disk '%s' to bus/device index"),
                         disk->dst);
        return NULL;
    }

    switch (disk->bus) {
        case VIR_DOMAIN_DISK_BUS_IDE:
4326
            if (disk->device== VIR_DOMAIN_DISK_DEVICE_DISK)
4327
                ret = virAsprintf(&devname, "ide%d-hd%d", busid, devid);
4328
            else
4329
                ret = virAsprintf(&devname, "ide%d-cd%d", busid, devid);
4330 4331
            break;
        case VIR_DOMAIN_DISK_BUS_SCSI:
4332
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
4333
                ret = virAsprintf(&devname, "scsi%d-hd%d", busid, devid);
4334
            else
4335
                ret = virAsprintf(&devname, "scsi%d-cd%d", busid, devid);
4336 4337
            break;
        case VIR_DOMAIN_DISK_BUS_FDC:
4338
            ret = virAsprintf(&devname, "floppy%d", devid);
4339 4340
            break;
        case VIR_DOMAIN_DISK_BUS_VIRTIO:
4341
            ret = virAsprintf(&devname, "virtio%d", devid);
4342 4343
            break;
        default:
4344
            qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
4345 4346 4347 4348 4349 4350
                             _("Unsupported disk name mapping for bus '%s'"),
                             virDomainDiskBusTypeToString(disk->bus));
            return NULL;
    }

    if (ret == -1) {
4351
        virReportOOMError(conn);
4352 4353 4354 4355 4356 4357
        return NULL;
    }

    return devname;
}

4358 4359
static int qemudDomainChangeEjectableMedia(virConnectPtr conn,
                                           virDomainObjPtr vm,
4360 4361
                                           virDomainDeviceDefPtr dev,
                                           unsigned int qemuCmdFlags)
4362
{
4363
    virDomainDiskDefPtr origdisk = NULL, newdisk;
4364
    char *devname = NULL;
4365
    int i;
4366
    int ret;
4367

4368
    origdisk = NULL;
4369
    newdisk = dev->data.disk;
4370 4371 4372 4373
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->bus == newdisk->bus &&
            STREQ(vm->def->disks[i]->dst, newdisk->dst)) {
            origdisk = vm->def->disks[i];
4374
            break;
4375
        }
4376 4377 4378
    }

    if (!origdisk) {
4379
        qemudReportError(conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
4380 4381 4382 4383 4384 4385 4386
                         _("No device with bus '%s' and target '%s'"),
                         virDomainDiskBusTypeToString(newdisk->bus),
                         newdisk->dst);
        return -1;
    }

    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
4387
        if (!(devname = qemudDiskDeviceName(conn, newdisk)))
4388 4389 4390 4391 4392 4393 4394 4395 4396
            return -1;
    } else {
        /* Back compat for no -drive option */
        if (newdisk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
            devname = strdup(newdisk->dst);
        else if (newdisk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
                 STREQ(newdisk->dst, "hdc"))
            devname = strdup("cdrom");
        else {
4397
            qemudReportError(conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
4398 4399 4400 4401 4402 4403 4404 4405
                             _("Emulator version does not support removable "
                               "media for device '%s' and target '%s'"),
                               virDomainDiskDeviceTypeToString(newdisk->device),
                               newdisk->dst);
            return -1;
        }

        if (!devname) {
4406
            virReportOOMError(conn);
4407 4408 4409
            return -1;
        }
    }
4410

4411
    if (newdisk->src) {
4412 4413 4414
        ret = qemuMonitorChangeMedia(vm, devname, newdisk->src);
    } else {
        ret = qemuMonitorEjectMedia(vm, devname);
4415
    }
4416

4417 4418 4419 4420 4421
    if (ret == 0) {
        VIR_FREE(origdisk->src);
        origdisk->src = newdisk->src;
        newdisk->src = NULL;
        origdisk->type = newdisk->type;
4422
    }
4423

4424
    return ret;
4425 4426
}

4427

4428 4429 4430
static int qemudDomainAttachPciDiskDevice(virConnectPtr conn,
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
4431
{
4432
    int i;
4433 4434 4435 4436
    const char* type = virDomainDiskBusTypeToString(dev->data.disk->bus);

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
4437
            qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
4438 4439 4440 4441 4442 4443
                           _("target %s already exists"), dev->data.disk->dst);
            return -1;
        }
    }

    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
4444
        virReportOOMError(conn);
4445 4446 4447
        return -1;
    }

4448 4449 4450 4451 4452 4453
    if (qemuMonitorAddPCIDisk(vm,
                              dev->data.disk->src,
                              type,
                              &dev->data.disk->pci_addr.domain,
                              &dev->data.disk->pci_addr.bus,
                              &dev->data.disk->pci_addr.slot) < 0)
4454
        return -1;
4455

4456
    virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
4457 4458 4459

    return 0;
}
4460

4461 4462 4463
static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn,
                                                 virDomainObjPtr vm,
                                                 virDomainDeviceDefPtr dev)
4464
{
4465
    int i;
4466

4467 4468
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
4469
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4470 4471 4472 4473 4474
                           _("target %s already exists"), dev->data.disk->dst);
            return -1;
        }
    }

4475 4476 4477
    if (!dev->data.disk->src) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("disk source path is missing"));
4478 4479 4480
        return -1;
    }

4481
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
4482
        virReportOOMError(conn);
4483 4484 4485
        return -1;
    }

4486
    if (qemuMonitorAddUSBDisk(vm, dev->data.disk->src) < 0)
4487
        return -1;
4488

4489
    virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
4490

4491 4492 4493
    return 0;
}

M
Mark McLoughlin 已提交
4494
static int qemudDomainAttachNetDevice(virConnectPtr conn,
4495
                                      struct qemud_driver *driver,
M
Mark McLoughlin 已提交
4496 4497 4498 4499 4500
                                      virDomainObjPtr vm,
                                      virDomainDeviceDefPtr dev,
                                      unsigned int qemuCmdFlags)
{
    virDomainNetDefPtr net = dev->data.net;
4501
    char *tapfd_name = NULL;
4502
    int i, tapfd = -1;
4503
    char *nicstr = NULL;
4504
    char *netstr = NULL;
4505
    int ret = -1;
M
Mark McLoughlin 已提交
4506 4507 4508 4509 4510 4511 4512 4513 4514

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s",
                         _("installed qemu version does not support host_net_add"));
        return -1;
    }

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4515 4516 4517 4518 4519 4520 4521 4522 4523 4524
        if (vm->monitor_chr->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
            qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                             _("network device type '%s' cannot be attached: "
                               "qemu is not using a unix socket monitor"),
                             virDomainNetTypeToString(net->type));
            return -1;
        }

        if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
            return -1;
M
Mark McLoughlin 已提交
4525 4526
    }

4527 4528
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
        goto no_memory;
M
Mark McLoughlin 已提交
4529 4530

    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) &&
4531 4532
        qemuAssignNetNames(vm->def, net) < 0)
        goto no_memory;
M
Mark McLoughlin 已提交
4533 4534 4535 4536 4537 4538 4539 4540 4541

    /* Choose a vlan value greater than all other values since
     * older versions did not store the value in the state file.
     */
    net->vlan = vm->def->nnets;
    for (i = 0; i < vm->def->nnets; i++)
        if (vm->def->nets[i]->vlan >= net->vlan)
            net->vlan = vm->def->nets[i]->vlan;

4542 4543 4544 4545
    if (tapfd != -1) {
        if (virAsprintf(&tapfd_name, "fd-%s", net->hostnet_name) < 0)
            goto no_memory;

4546
        if (qemuMonitorSendFileHandle(vm, tapfd_name, tapfd) < 0)
4547 4548 4549
            goto cleanup;
    }

4550 4551
    if (qemuBuildHostNetStr(conn, net, ' ',
                            net->vlan, tapfd_name, &netstr) < 0)
4552
        goto try_tapfd_close;
M
Mark McLoughlin 已提交
4553

4554
    if (qemuMonitorAddHostNetwork(vm, netstr) < 0)
4555
        goto try_tapfd_close;
M
Mark McLoughlin 已提交
4556

4557 4558 4559
    if (tapfd != -1)
        close(tapfd);
    tapfd = -1;
M
Mark McLoughlin 已提交
4560

4561
    if (qemuBuildNicStr(conn, net, NULL, net->vlan, &nicstr) < 0)
4562
        goto try_remove;
M
Mark McLoughlin 已提交
4563

4564 4565 4566 4567
    if (qemuMonitorAddPCINetwork(vm, nicstr,
                                 &net->pci_addr.domain,
                                 &net->pci_addr.bus,
                                 &net->pci_addr.slot) < 0)
4568 4569
        goto try_remove;

4570
    ret = 0;
M
Mark McLoughlin 已提交
4571 4572 4573

    vm->def->nets[vm->def->nnets++] = net;

4574 4575 4576 4577 4578 4579
cleanup:
    VIR_FREE(nicstr);
    VIR_FREE(netstr);
    VIR_FREE(tapfd_name);
    if (tapfd != -1)
        close(tapfd);
4580

4581
    return ret;
4582

4583 4584
try_remove:
    if (!net->hostnet_name || net->vlan == 0)
4585
        VIR_WARN0(_("Unable to remove network backend\n"));
4586 4587 4588
    else if (qemuMonitorRemoveHostNetwork(vm, net->vlan, net->hostnet_name) < 0)
        VIR_WARN(_("Failed to remove network backend for vlan %d, net %s"),
                 net->vlan, net->hostnet_name);
4589
    goto cleanup;
4590

4591
try_tapfd_close:
4592 4593 4594 4595
    if (tapfd_name &&
        qemuMonitorCloseFileHandle(vm, tapfd_name) < 0)
        VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_name);

4596 4597
    goto cleanup;

4598 4599
no_memory:
    virReportOOMError(conn);
4600
    goto cleanup;
M
Mark McLoughlin 已提交
4601 4602
}

4603
static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
4604
                                          struct qemud_driver *driver,
4605 4606 4607 4608
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
4609
    pciDevice *pci;
4610 4611 4612 4613 4614 4615

    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
        virReportOOMError(conn);
        return -1;
    }

4616 4617 4618 4619 4620 4621 4622
    pci = pciGetDevice(conn,
                       hostdev->source.subsys.u.pci.domain,
                       hostdev->source.subsys.u.pci.bus,
                       hostdev->source.subsys.u.pci.slot,
                       hostdev->source.subsys.u.pci.function);
    if (!dev)
        return -1;
4623

4624
    if ((hostdev->managed && pciDettachDevice(conn, pci) < 0) ||
4625 4626 4627 4628 4629 4630
        pciResetDevice(conn, pci, driver->activePciHostdevs) < 0) {
        pciFreeDevice(conn, pci);
        return -1;
    }

    if (pciDeviceListAdd(conn, driver->activePciHostdevs, pci) < 0) {
4631
        pciFreeDevice(conn, pci);
4632
        return -1;
4633 4634
    }

4635 4636 4637 4638 4639 4640 4641 4642
    if (qemuMonitorAddPCIHostDevice(vm,
                                    hostdev->source.subsys.u.pci.domain,
                                    hostdev->source.subsys.u.pci.bus,
                                    hostdev->source.subsys.u.pci.slot,
                                    hostdev->source.subsys.u.pci.function,
                                    &hostdev->source.subsys.u.pci.guest_addr.domain,
                                    &hostdev->source.subsys.u.pci.guest_addr.bus,
                                    &hostdev->source.subsys.u.pci.guest_addr.slot) < 0)
4643
        goto error;
4644 4645 4646 4647

    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;

    return 0;
4648 4649 4650 4651 4652

error:
    pciDeviceListDel(conn, driver->activePciHostdevs, pci);

    return -1;
4653 4654
}

M
Mark McLoughlin 已提交
4655 4656 4657
static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
4658 4659 4660
{
    int ret;

4661
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
4662
        virReportOOMError(conn);
4663 4664
        return -1;
    }
4665

4666
    if (dev->data.hostdev->source.subsys.u.usb.vendor) {
4667 4668 4669
        ret = qemuMonitorAddUSBDeviceMatch(vm,
                                           dev->data.hostdev->source.subsys.u.usb.vendor,
                                           dev->data.hostdev->source.subsys.u.usb.product);
4670
    } else {
4671 4672 4673
        ret = qemuMonitorAddUSBDeviceExact(vm,
                                           dev->data.hostdev->source.subsys.u.usb.bus,
                                           dev->data.hostdev->source.subsys.u.usb.device);
4674 4675
    }

4676 4677
    if (ret != -1)
        vm->def->hostdevs[vm->def->nhostdevs++] = dev->data.hostdev;
4678

4679
    return ret;
4680 4681
}

M
Mark McLoughlin 已提交
4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697
static int qemudDomainAttachHostDevice(virConnectPtr conn,
                                       struct qemud_driver *driver,
                                       virDomainObjPtr vm,
                                       virDomainDeviceDefPtr dev)
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         _("hostdev mode '%s' not supported"),
                         virDomainHostdevModeTypeToString(hostdev->mode));
        return -1;
    }

    if (qemuDomainSetDeviceOwnership(conn, driver, dev, 0) < 0)
        return -1;
4698 4699 4700
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
        return -1;
M
Mark McLoughlin 已提交
4701 4702

    switch (hostdev->source.subsys.type) {
4703
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
4704
        return qemudDomainAttachHostPciDevice(conn, driver, vm, dev);
M
Mark McLoughlin 已提交
4705 4706 4707 4708 4709 4710 4711 4712 4713 4714
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        return qemudDomainAttachHostUsbDevice(conn, vm, dev);
    default:
        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         _("hostdev subsys type '%s' not supported"),
                         virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
        return -1;
    }
}

4715 4716
static int qemudDomainAttachDevice(virDomainPtr dom,
                                   const char *xml) {
4717 4718 4719
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
4720
    unsigned int qemuCmdFlags;
4721
    virCgroupPtr cgroup = NULL;
4722
    int ret = -1;
4723

4724
    qemuDriverLock(driver);
4725
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4726
    if (!vm) {
4727 4728 4729 4730
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
4731
        goto cleanup;
4732 4733
    }

D
Daniel P. Berrange 已提交
4734
    if (!virDomainObjIsActive(vm)) {
4735
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
4736
                         "%s", _("cannot attach device on inactive domain"));
4737
        goto cleanup;
4738 4739
    }

4740 4741
    dev = virDomainDeviceDefParse(dom->conn, driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
4742 4743 4744
    if (dev == NULL)
        goto cleanup;

4745 4746 4747 4748
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
        goto cleanup;
4749

4750
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
4751
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
                qemudReportError(dom->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 _("Unable to find cgroup for %s\n"),
                                 vm->def->name);
                goto cleanup;
            }
            if (dev->data.disk->src != NULL &&
                dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
                virCgroupAllowDevicePath(cgroup,
                                         dev->data.disk->src) < 0) {
                qemudReportError(dom->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 _("unable to allow device %s"),
                                 dev->data.disk->src);
                goto cleanup;
            }
        }

4769
        switch (dev->data.disk->device) {
4770 4771
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
4772 4773
            if (driver->securityDriver)
                driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
4774 4775 4776 4777

            if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
                goto cleanup;

4778
            ret = qemudDomainChangeEjectableMedia(dom->conn, vm, dev, qemuCmdFlags);
4779
            break;
4780

4781
        case VIR_DOMAIN_DISK_DEVICE_DISK:
4782 4783
            if (driver->securityDriver)
                driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
4784 4785 4786 4787

            if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
                goto cleanup;

4788
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
4789
                ret = qemudDomainAttachUsbMassstorageDevice(dom->conn, vm, dev);
4790 4791
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                       dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
4792
                ret = qemudDomainAttachPciDiskDevice(dom->conn, vm, dev);
4793 4794 4795 4796
            } else {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                                 _("disk bus '%s' cannot be hotplugged."),
                                 virDomainDiskBusTypeToString(dev->data.disk->bus));
4797
                /* fallthrough */
4798 4799
            }
            break;
4800

4801 4802
        default:
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
4803 4804
                             _("disk device type '%s' cannot be hotplugged"),
                             virDomainDiskDeviceTypeToString(dev->data.disk->device));
4805 4806 4807 4808 4809
            /* Fallthrough */
        }
        if (ret != 0) {
            virCgroupDenyDevicePath(cgroup,
                                    dev->data.disk->src);
4810
        }
M
Mark McLoughlin 已提交
4811
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
4812
        ret = qemudDomainAttachNetDevice(dom->conn, driver, vm, dev, qemuCmdFlags);
M
Mark McLoughlin 已提交
4813 4814
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        ret = qemudDomainAttachHostDevice(dom->conn, driver, vm, dev);
4815
    } else {
4816
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
4817 4818
                         _("device type '%s' cannot be attached"),
                         virDomainDeviceTypeToString(dev->type));
4819
        goto cleanup;
4820 4821
    }

4822
    if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
4823 4824
        ret = -1;

4825
cleanup:
4826 4827 4828
    if (cgroup)
        virCgroupFree(&cgroup);

4829
    if (ret < 0 && dev != NULL) {
4830 4831
        if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
            VIR_WARN0("Fail to restore disk device ownership");
G
Guido Günther 已提交
4832
        virDomainDeviceDefFree(dev);
4833
    }
4834 4835
    if (vm)
        virDomainObjUnlock(vm);
4836
    qemuDriverUnlock(driver);
4837 4838 4839
    return ret;
}

4840 4841
static int qemudDomainDetachPciDiskDevice(virConnectPtr conn,
                                          virDomainObjPtr vm, virDomainDeviceDefPtr dev)
4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853
{
    int i, ret = -1;
    virDomainDiskDefPtr detach = NULL;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
            detach = vm->def->disks[i];
            break;
        }
    }

    if (!detach) {
4854
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4855
                         _("disk %s not found"), dev->data.disk->dst);
4856
        goto cleanup;
4857 4858
    }

4859
    if (!virDiskHasValidPciAddr(detach)) {
4860
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4861 4862
                         _("disk %s cannot be detached - no PCI address for device"),
                           detach->dst);
4863
        goto cleanup;
4864 4865
    }

4866 4867 4868 4869
    if (qemuMonitorRemovePCIDevice(vm,
                                   detach->pci_addr.domain,
                                   detach->pci_addr.bus,
                                   detach->pci_addr.slot) < 0)
4870
        goto cleanup;
4871

4872 4873 4874 4875 4876 4877 4878 4879 4880 4881
    if (vm->def->ndisks > 1) {
        memmove(vm->def->disks + i,
                vm->def->disks + i + 1,
                sizeof(*vm->def->disks) *
                (vm->def->ndisks - (i + 1)));
        vm->def->ndisks--;
        if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks) < 0) {
            /* ignore, harmless */
        }
    } else {
4882
        VIR_FREE(vm->def->disks);
4883
        vm->def->ndisks = 0;
4884
    }
4885
    virDomainDiskDefFree(detach);
4886

4887
    ret = 0;
4888 4889

cleanup:
4890 4891 4892
    return ret;
}

4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924
static int
qemudDomainDetachNetDevice(virConnectPtr conn,
                           virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev)
{
    int i, ret = -1;
    virDomainNetDefPtr detach = NULL;

    for (i = 0 ; i < vm->def->nnets ; i++) {
        virDomainNetDefPtr net = vm->def->nets[i];

        if (!memcmp(net->mac, dev->data.net->mac,  sizeof(net->mac))) {
            detach = net;
            break;
        }
    }

    if (!detach) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         _("network device %02x:%02x:%02x:%02x:%02x:%02x not found"),
                         dev->data.net->mac[0], dev->data.net->mac[1],
                         dev->data.net->mac[2], dev->data.net->mac[3],
                         dev->data.net->mac[4], dev->data.net->mac[5]);
        goto cleanup;
    }

    if (!virNetHasValidPciAddr(detach) || detach->vlan < 0 || !detach->hostnet_name) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("network device cannot be detached - device state missing"));
        goto cleanup;
    }

4925 4926 4927 4928
    if (qemuMonitorRemovePCIDevice(vm,
                                   detach->pci_addr.domain,
                                   detach->pci_addr.bus,
                                   detach->pci_addr.slot) < 0)
4929 4930
        goto cleanup;

4931
    if (qemuMonitorRemoveHostNetwork(vm, detach->vlan, detach->hostnet_name) < 0)
4932 4933
        goto cleanup;

4934 4935 4936 4937 4938 4939 4940 4941 4942 4943
    if (vm->def->nnets > 1) {
        memmove(vm->def->nets + i,
                vm->def->nets + i + 1,
                sizeof(*vm->def->nets) *
                (vm->def->nnets - (i + 1)));
        vm->def->nnets--;
        if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets) < 0) {
            /* ignore, harmless */
        }
    } else {
4944
        VIR_FREE(vm->def->nets);
4945
        vm->def->nnets = 0;
4946
    }
4947
    virDomainNetDefFree(detach);
4948

4949 4950 4951 4952 4953 4954
    ret = 0;

cleanup:
    return ret;
}

4955
static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
4956
                                          struct qemud_driver *driver,
4957 4958 4959
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
{
4960
    virDomainHostdevDefPtr detach = NULL;
4961
    int i, ret;
4962
    pciDevice *pci;
4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994

    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
        unsigned domain   = vm->def->hostdevs[i]->source.subsys.u.pci.domain;
        unsigned bus      = vm->def->hostdevs[i]->source.subsys.u.pci.bus;
        unsigned slot     = vm->def->hostdevs[i]->source.subsys.u.pci.slot;
        unsigned function = vm->def->hostdevs[i]->source.subsys.u.pci.function;

        if (dev->data.hostdev->source.subsys.u.pci.domain   == domain &&
            dev->data.hostdev->source.subsys.u.pci.bus      == bus &&
            dev->data.hostdev->source.subsys.u.pci.slot     == slot &&
            dev->data.hostdev->source.subsys.u.pci.function == function) {
            detach = vm->def->hostdevs[i];
            break;
        }
    }

    if (!detach) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
                         dev->data.hostdev->source.subsys.u.pci.domain,
                         dev->data.hostdev->source.subsys.u.pci.bus,
                         dev->data.hostdev->source.subsys.u.pci.slot,
                         dev->data.hostdev->source.subsys.u.pci.function);
        return -1;
    }

    if (!virHostdevHasValidGuestAddr(detach)) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("hostdev cannot be detached - device state missing"));
        return -1;
    }

4995 4996 4997 4998
    if (qemuMonitorRemovePCIDevice(vm,
                                   detach->source.subsys.u.pci.guest_addr.domain,
                                   detach->source.subsys.u.pci.guest_addr.bus,
                                   detach->source.subsys.u.pci.guest_addr.slot) < 0)
4999 5000 5001 5002
        return -1;

    ret = 0;

5003 5004 5005 5006 5007 5008 5009 5010
    pci = pciGetDevice(conn,
                       detach->source.subsys.u.pci.domain,
                       detach->source.subsys.u.pci.bus,
                       detach->source.subsys.u.pci.slot,
                       detach->source.subsys.u.pci.function);
    if (!pci)
        ret = -1;
    else {
5011 5012
        pciDeviceListDel(conn, driver->activePciHostdevs, pci);
        if (pciResetDevice(conn, pci, driver->activePciHostdevs) < 0)
5013 5014
            ret = -1;
        if (detach->managed && pciReAttachDevice(conn, pci) < 0)
5015
            ret = -1;
5016
        pciFreeDevice(conn, pci);
5017 5018
    }

5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030
    if (vm->def->nhostdevs > 1) {
        memmove(vm->def->hostdevs + i,
                vm->def->hostdevs + i + 1,
                sizeof(*vm->def->hostdevs) *
                (vm->def->nhostdevs - (i + 1)));
        vm->def->nhostdevs--;
        if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs) < 0) {
            /* ignore, harmless */
        }
    } else {
        VIR_FREE(vm->def->hostdevs);
        vm->def->nhostdevs = 0;
5031
    }
5032
    virDomainHostdevDefFree(detach);
5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053

    return ret;
}

static int qemudDomainDetachHostDevice(virConnectPtr conn,
                                       struct qemud_driver *driver,
                                       virDomainObjPtr vm,
                                       virDomainDeviceDefPtr dev)
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
    int ret;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         _("hostdev mode '%s' not supported"),
                         virDomainHostdevModeTypeToString(hostdev->mode));
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
5054
        ret = qemudDomainDetachHostPciDevice(conn, driver, vm, dev);
5055
        break;
5056 5057 5058 5059 5060 5061 5062
    default:
        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         _("hostdev subsys type '%s' not supported"),
                         virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
        return -1;
    }

5063 5064 5065 5066
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
        VIR_WARN0("Failed to restore device labelling");

5067
    if (qemuDomainSetDeviceOwnership(conn, driver, dev, 1) < 0)
5068
        VIR_WARN0("Failed to restore device ownership");
5069 5070 5071 5072

    return ret;
}

5073 5074
static int qemudDomainDetachDevice(virDomainPtr dom,
                                   const char *xml) {
5075 5076 5077 5078
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;
5079

5080
    qemuDriverLock(driver);
5081
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5082
    if (!vm) {
5083 5084 5085 5086
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
5087
        goto cleanup;
5088 5089
    }

D
Daniel P. Berrange 已提交
5090
    if (!virDomainObjIsActive(vm)) {
5091
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
G
Guido Günther 已提交
5092
                         "%s", _("cannot detach device on inactive domain"));
5093
        goto cleanup;
5094 5095
    }

5096 5097
    dev = virDomainDeviceDefParse(dom->conn, driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
5098 5099 5100
    if (dev == NULL)
        goto cleanup;

5101 5102 5103 5104

    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
        (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
5105
         dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)) {
5106
        ret = qemudDomainDetachPciDiskDevice(dom->conn, vm, dev);
5107
        if (driver->securityDriver)
5108
            driver->securityDriver->domainRestoreSecurityImageLabel(dom->conn, vm, dev->data.disk);
5109 5110
        if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
            VIR_WARN0("Fail to restore disk device ownership");
5111 5112
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
        ret = qemudDomainDetachNetDevice(dom->conn, vm, dev);
5113 5114
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        ret = qemudDomainDetachHostDevice(dom->conn, driver, vm, dev);
5115
    } else
5116 5117 5118
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         "%s", _("only SCSI or virtio disk device can be detached dynamically"));

5119
    if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
5120 5121
        ret = -1;

5122 5123
cleanup:
    virDomainDeviceDefFree(dev);
5124 5125
    if (vm)
        virDomainObjUnlock(vm);
5126
    qemuDriverUnlock(driver);
5127 5128 5129
    return ret;
}

5130
static int qemudDomainGetAutostart(virDomainPtr dom,
5131
                                   int *autostart) {
5132 5133 5134
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5135

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

5140
    if (!vm) {
5141 5142 5143 5144
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
5145
        goto cleanup;
5146 5147 5148
    }

    *autostart = vm->autostart;
5149
    ret = 0;
5150

5151
cleanup:
5152 5153
    if (vm)
        virDomainObjUnlock(vm);
5154
    return ret;
5155 5156
}

5157
static int qemudDomainSetAutostart(virDomainPtr dom,
5158
                                   int autostart) {
5159 5160
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5161 5162
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
5163

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

5167
    if (!vm) {
5168 5169 5170 5171
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
5172
        goto cleanup;
5173 5174
    }

5175 5176 5177
    if (!vm->persistent) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot set autostart for transient domain"));
5178
        goto cleanup;
5179 5180
    }

5181 5182
    autostart = (autostart != 0);

5183 5184 5185 5186 5187
    if (vm->autostart != autostart) {
        if ((configFile = virDomainConfigFile(dom->conn, driver->configDir, vm->def->name)) == NULL)
            goto cleanup;
        if ((autostartLink = virDomainConfigFile(dom->conn, driver->autostartDir, vm->def->name)) == NULL)
            goto cleanup;
5188

5189 5190
        if (autostart) {
            int err;
5191

5192
            if ((err = virFileMakePath(driver->autostartDir))) {
5193 5194 5195
                virReportSystemError(dom->conn, err,
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
5196 5197
                goto cleanup;
            }
5198

5199
            if (symlink(configFile, autostartLink) < 0) {
5200 5201 5202
                virReportSystemError(dom->conn, errno,
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
5203 5204 5205 5206
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
5207 5208 5209
                virReportSystemError(dom->conn, errno,
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
5210 5211
                goto cleanup;
            }
5212 5213
        }

5214
        vm->autostart = autostart;
5215
    }
5216
    ret = 0;
5217

5218 5219 5220
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
5221 5222
    if (vm)
        virDomainObjUnlock(vm);
5223
    qemuDriverUnlock(driver);
5224
    return ret;
5225 5226
}

5227 5228 5229 5230 5231

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

5234
    qemuDriverLock(driver);
5235
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5236 5237
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
5238
        goto cleanup;
5239 5240 5241 5242 5243 5244 5245 5246
    }

    if (nparams)
        *nparams = 1;

    ret = strdup("posix");
    if (!ret)
        virReportOOMError(dom->conn);
5247 5248 5249

cleanup:
    qemuDriverUnlock(driver);
5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262
    return ret;
}

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;

5263
    qemuDriverLock(driver);
5264
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5265 5266
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
5267
        goto cleanup;
5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289
    }

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

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

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("cannot find cgroup for domain %s"), vm->def->name);
        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) {
C
Chris Lalancette 已提交
5290
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, "%s",
5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312
                                 _("invalid type for cpu_shares tunable, expected a 'ullong'"));
                goto cleanup;
            }

            rc = virCgroupSetCpuShares(group, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(dom->conn, -rc, "%s",
                                     _("unable to set cpu shares tunable"));
                goto cleanup;
            }
        } else {
            qemudReportError(dom->conn, domain, NULL, VIR_ERR_INVALID_ARG,
                             _("Invalid parameter `%s'"), param->field);
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
5313
    qemuDriverUnlock(driver);
5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327
    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;

5328
    qemuDriverLock(driver);
5329
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5330 5331
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
5332
        goto cleanup;
5333 5334 5335 5336 5337
    }

    if ((*nparams) != 1) {
        qemudReportError(dom->conn, domain, NULL, VIR_ERR_INVALID_ARG,
                         "%s", _("Invalid parameter count"));
5338
        goto cleanup;
5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362
    }

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

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

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

    rc = virCgroupGetCpuShares(group, &val);
    if (rc != 0) {
        virReportSystemError(dom->conn, -rc, "%s",
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
    params[0].value.ul = val;
    params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
C
Chris Lalancette 已提交
5363 5364 5365 5366 5367
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field cpu_shares too long for destination"));
        goto cleanup;
    }
5368 5369 5370 5371 5372 5373 5374

    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
5375
    qemuDriverUnlock(driver);
5376 5377 5378 5379
    return ret;
}


5380 5381 5382 5383 5384 5385 5386 5387 5388
/* 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)
{
5389
    struct qemud_driver *driver = dom->conn->privateData;
5390 5391
    const char *qemu_dev_name = NULL;
    int i, ret = -1;
5392
    virDomainObjPtr vm;
5393
    virDomainDiskDefPtr disk = NULL;
5394

5395
    qemuDriverLock(driver);
5396
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5397
    qemuDriverUnlock(driver);
5398
    if (!vm) {
5399 5400 5401 5402
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
5403
        goto cleanup;
5404
    }
D
Daniel P. Berrange 已提交
5405
    if (!virDomainObjIsActive (vm)) {
5406
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
5407
                          "%s", _("domain is not running"));
5408
        goto cleanup;
5409 5410
    }

5411 5412 5413 5414 5415 5416 5417 5418
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
5419 5420
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                          _("invalid path: %s"), path);
5421
        goto cleanup;
5422 5423
    }

5424
    qemu_dev_name = qemudDiskDeviceName(dom->conn, disk);
5425
    if (!qemu_dev_name)
5426
        goto cleanup;
5427

5428 5429 5430 5431 5432 5433
    if (qemuMonitorGetBlockStatsInfo(vm, qemu_dev_name,
                                     &stats->rd_req,
                                     &stats->rd_bytes,
                                     &stats->wr_req,
                                     &stats->wr_bytes,
                                     &stats->errs) < 0)
5434
        goto cleanup;
5435

5436
    ret = 0;
5437

5438
cleanup:
5439
    VIR_FREE(qemu_dev_name);
5440 5441
    if (vm)
        virDomainObjUnlock(vm);
5442
    return ret;
5443 5444
}

5445
#ifdef __linux__
5446 5447 5448 5449 5450
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
5451 5452
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5453
    int i;
5454
    int ret = -1;
5455

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

5460
    if (!vm) {
5461 5462 5463 5464
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
5465
        goto cleanup;
5466 5467
    }

D
Daniel P. Berrange 已提交
5468
    if (!virDomainObjIsActive(vm)) {
5469
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
5470
                         "%s", _("domain is not running"));
5471
        goto cleanup;
5472 5473 5474
    }

    /* Check the path is one of the domain's network interfaces. */
5475 5476
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
5477 5478 5479 5480
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
5481 5482
    }

5483 5484 5485 5486 5487
    if (ret == 0)
        ret = linuxDomainInterfaceStats (dom->conn, path, stats);
    else
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                          _("invalid path, '%s' is not a known interface"), path);
5488

5489
cleanup:
5490 5491
    if (vm)
        virDomainObjUnlock(vm);
5492 5493
    return ret;
}
5494
#else
5495 5496 5497 5498
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
5499 5500 5501 5502
    qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                      "%s", __FUNCTION__);
    return -1;
}
5503
#endif
5504

5505 5506 5507 5508 5509 5510 5511
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
5512 5513 5514
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
5515

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

5520
    if (!vm) {
5521 5522 5523 5524
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
5525
        goto cleanup;
5526 5527 5528 5529
    }

    if (!path || path[0] == '\0') {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
5530
                         "%s", _("NULL or empty path"));
5531
        goto cleanup;
5532 5533 5534
    }

    /* Check the path belongs to this domain. */
5535 5536
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
5537 5538 5539 5540
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
5541 5542
    }

5543 5544 5545 5546 5547
    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) {
5548 5549
            virReportSystemError (dom->conn, errno,
                                  _("%s: failed to open"), path);
5550 5551
            goto cleanup;
        }
5552

5553 5554 5555 5556 5557 5558
        /* 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) {
5559 5560
            virReportSystemError (dom->conn, errno,
                                  _("%s: failed to seek or read"), path);
5561 5562 5563 5564 5565 5566 5567
            goto cleanup;
        }

        ret = 0;
    } else {
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                          "%s", _("invalid path"));
5568 5569
    }

5570 5571 5572
cleanup:
    if (fd >= 0)
        close (fd);
5573 5574
    if (vm)
        virDomainObjUnlock(vm);
5575 5576 5577
    return ret;
}

R
Richard W.M. Jones 已提交
5578 5579 5580 5581 5582 5583
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
5584 5585
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5586
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
5587 5588
    int fd = -1, ret = -1;

5589
    qemuDriverLock(driver);
5590
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5591
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
5592 5593

    if (!vm) {
5594 5595 5596 5597
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
5598 5599 5600
        goto cleanup;
    }

5601
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
5602
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
5603
                     "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
5604
        goto cleanup;
R
Richard W.M. Jones 已提交
5605 5606
    }

D
Daniel P. Berrange 已提交
5607
    if (!virDomainObjIsActive(vm)) {
5608
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
R
Richard W.M. Jones 已提交
5609
                         "%s", _("domain is not running"));
5610
        goto cleanup;
R
Richard W.M. Jones 已提交
5611 5612
    }

5613 5614 5615 5616 5617
    if (virAsprintf(&tmp, driver->cacheDir,  "/qemu.mem.XXXXXX") < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }

R
Richard W.M. Jones 已提交
5618 5619
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
5620 5621
        virReportSystemError (dom->conn, errno,
                              _("mkstemp(\"%s\") failed"), tmp);
5622
        goto cleanup;
R
Richard W.M. Jones 已提交
5623 5624
    }

5625 5626 5627 5628 5629 5630
    if (flags == VIR_MEMORY_VIRTUAL) {
        if (qemuMonitorSaveVirtualMemory(vm, offset, size, tmp) < 0)
            goto cleanup;
    } else {
        if (qemuMonitorSavePhysicalMemory(vm, offset, size, tmp) < 0)
            goto cleanup;
R
Richard W.M. Jones 已提交
5631 5632 5633 5634
    }

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
5635 5636 5637
        virReportSystemError (dom->conn, errno,
                              _("failed to read temporary file "
                                "created with template %s"), tmp);
5638
        goto cleanup;
R
Richard W.M. Jones 已提交
5639 5640 5641
    }

    ret = 0;
5642 5643

cleanup:
5644
    VIR_FREE(tmp);
R
Richard W.M. Jones 已提交
5645 5646
    if (fd >= 0) close (fd);
    unlink (tmp);
5647 5648
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
5649 5650 5651
    return ret;
}

5652

5653 5654
static int
qemudDomainEventRegister (virConnectPtr conn,
5655
                          virConnectDomainEventCallback callback,
5656 5657
                          void *opaque,
                          virFreeCallback freecb)
5658
{
5659 5660 5661
    struct qemud_driver *driver = conn->privateData;
    int ret;

5662
    qemuDriverLock(driver);
5663 5664
    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
                                        callback, opaque, freecb);
5665
    qemuDriverUnlock(driver);
5666

5667
    return ret;
5668 5669 5670 5671
}

static int
qemudDomainEventDeregister (virConnectPtr conn,
5672
                            virConnectDomainEventCallback callback)
5673
{
5674 5675 5676
    struct qemud_driver *driver = conn->privateData;
    int ret;

5677
    qemuDriverLock(driver);
5678 5679 5680 5681 5682 5683
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
                                               callback);
5684
    qemuDriverUnlock(driver);
5685

5686
    return ret;
5687 5688
}

5689 5690 5691 5692 5693
static void qemuDomainEventDispatchFunc(virConnectPtr conn,
                                        virDomainEventPtr event,
                                        virConnectDomainEventCallback cb,
                                        void *cbopaque,
                                        void *opaque)
5694
{
5695
    struct qemud_driver *driver = opaque;
5696

5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740
    /* Drop the lock whle dispatching, for sake of re-entrancy */
    qemuDriverUnlock(driver);
    virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
    qemuDriverLock(driver);
}

static void qemuDomainEventFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
{
    struct qemud_driver *driver = opaque;
    virDomainEventQueue tempQueue;

    qemuDriverLock(driver);

    driver->domainEventDispatching = 1;

    /* Copy the queue, so we're reentrant safe */
    tempQueue.count = driver->domainEventQueue->count;
    tempQueue.events = driver->domainEventQueue->events;
    driver->domainEventQueue->count = 0;
    driver->domainEventQueue->events = NULL;

    virEventUpdateTimeout(driver->domainEventTimer, -1);
    virDomainEventQueueDispatch(&tempQueue,
                                driver->domainEventCallbacks,
                                qemuDomainEventDispatchFunc,
                                driver);

    /* Purge any deleted callbacks */
    virDomainEventCallbackListPurgeMarked(driver->domainEventCallbacks);

    driver->domainEventDispatching = 0;
    qemuDriverUnlock(driver);
}


/* driver must be locked before calling */
static void qemuDomainEventQueue(struct qemud_driver *driver,
                                 virDomainEventPtr event)
{
    if (virDomainEventQueuePush(driver->domainEventQueue,
                                event) < 0)
        virDomainEventFree(event);
    if (qemu_driver->domainEventQueue->count == 1)
        virEventUpdateTimeout(driver->domainEventTimer, 0);
5741 5742
}

D
Daniel Veillard 已提交
5743 5744
/* Migration support. */

C
Chris Lalancette 已提交
5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 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 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071
/* Tunnelled migration stream support */
struct qemuStreamMigFile {
    int fd;

    int watch;
    unsigned int cbRemoved;
    unsigned int dispatching;
    virStreamEventCallback cb;
    void *opaque;
    virFreeCallback ff;
};

static int qemuStreamMigRemoveCallback(virStreamPtr stream)
{
    struct qemud_driver *driver = stream->conn->privateData;
    struct qemuStreamMigFile *qemust = stream->privateData;
    int ret = -1;

    if (!qemust) {
        qemudReportError(stream->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("stream is not open"));
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch == 0) {
        qemudReportError(stream->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("stream does not have a callback registered"));
        goto cleanup;
    }

    virEventRemoveHandle(qemust->watch);
    if (qemust->dispatching)
        qemust->cbRemoved = 1;
    else if (qemust->ff)
        (qemust->ff)(qemust->opaque);

    qemust->watch = 0;
    qemust->ff = NULL;
    qemust->cb = NULL;
    qemust->opaque = NULL;

    ret = 0;

cleanup:
    qemuDriverUnlock(driver);
    return ret;
}

static int qemuStreamMigUpdateCallback(virStreamPtr stream, int events)
{
    struct qemud_driver *driver = stream->conn->privateData;
    struct qemuStreamMigFile *qemust = stream->privateData;
    int ret = -1;

    if (!qemust) {
        qemudReportError(stream->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("stream is not open"));
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch == 0) {
        qemudReportError(stream->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("stream does not have a callback registered"));
        goto cleanup;
    }

    virEventUpdateHandle(qemust->watch, events);

    ret = 0;

cleanup:
    qemuDriverUnlock(driver);
    return ret;
}

static void qemuStreamMigEvent(int watch ATTRIBUTE_UNUSED,
                               int fd ATTRIBUTE_UNUSED,
                               int events,
                               void *opaque)
{
    virStreamPtr stream = opaque;
    struct qemud_driver *driver = stream->conn->privateData;
    struct qemuStreamMigFile *qemust = stream->privateData;
    virStreamEventCallback cb;
    void *cbopaque;
    virFreeCallback ff;

    qemuDriverLock(driver);
    if (!qemust || !qemust->cb) {
        qemuDriverUnlock(driver);
        return;
    }

    cb = qemust->cb;
    cbopaque = qemust->opaque;
    ff = qemust->ff;
    qemust->dispatching = 1;
    qemuDriverUnlock(driver);

    cb(stream, events, cbopaque);

    qemuDriverLock(driver);
    qemust->dispatching = 0;
    if (qemust->cbRemoved && ff)
        (ff)(cbopaque);
    qemuDriverUnlock(driver);
}

static int
qemuStreamMigAddCallback(virStreamPtr st,
                         int events,
                         virStreamEventCallback cb,
                         void *opaque,
                         virFreeCallback ff)
{
    struct qemud_driver *driver = st->conn->privateData;
    struct qemuStreamMigFile *qemust = st->privateData;
    int ret = -1;

    if (!qemust) {
        qemudReportError(st->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("stream is not open"));
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch != 0) {
        qemudReportError(st->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("stream already has a callback registered"));
        goto cleanup;
    }

    if ((qemust->watch = virEventAddHandle(qemust->fd,
                                           events,
                                           qemuStreamMigEvent,
                                           st,
                                           NULL)) < 0) {
        qemudReportError(st->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot register file watch on stream"));
        goto cleanup;
    }

    qemust->cbRemoved = 0;
    qemust->cb = cb;
    qemust->opaque = opaque;
    qemust->ff = ff;
    virStreamRef(st);

    ret = 0;

cleanup:
    qemuDriverUnlock(driver);
    return ret;
}

static void qemuStreamMigFree(struct qemuStreamMigFile *qemust)
{
    if (qemust->fd != -1)
        close(qemust->fd);
    VIR_FREE(qemust);
}

static struct qemuStreamMigFile *qemuStreamMigOpen(virStreamPtr st,
                                                   const char *unixfile)
{
    struct qemuStreamMigFile *qemust = NULL;
    struct sockaddr_un sa_qemu;
    int i = 0;
    int timeout = 3;
    int ret;

    if (VIR_ALLOC(qemust) < 0)
        return NULL;

    qemust->fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (qemust->fd < 0)
        goto cleanup;

    memset(&sa_qemu, 0, sizeof(sa_qemu));
    sa_qemu.sun_family = AF_UNIX;
    if (virStrcpy(sa_qemu.sun_path, unixfile, sizeof(sa_qemu.sun_path)) == NULL)
        goto cleanup;

    do {
        ret = connect(qemust->fd, (struct sockaddr *)&sa_qemu, sizeof(sa_qemu));
        if (ret == 0)
            break;

        if (errno == ENOENT || errno == ECONNREFUSED) {
            /* ENOENT       : Socket may not have shown up yet
             * ECONNREFUSED : Leftover socket hasn't been removed yet */
            continue;
        }

        goto cleanup;
    } while ((++i <= timeout*5) && (usleep(.2 * 1000000) <= 0));

    if ((st->flags & VIR_STREAM_NONBLOCK) && virSetNonBlock(qemust->fd) < 0)
        goto cleanup;

    return qemust;

cleanup:
    qemuStreamMigFree(qemust);
    return NULL;
}

static int
qemuStreamMigClose(virStreamPtr st)
{
    struct qemud_driver *driver = st->conn->privateData;
    struct qemuStreamMigFile *qemust = st->privateData;

    if (!qemust)
        return 0;

    qemuDriverLock(driver);

    qemuStreamMigFree(qemust);

    st->privateData = NULL;

    qemuDriverUnlock(driver);

    return 0;
}

static int qemuStreamMigWrite(virStreamPtr st, const char *bytes, size_t nbytes)
{
    struct qemud_driver *driver = st->conn->privateData;
    struct qemuStreamMigFile *qemust = st->privateData;
    int ret;

    if (!qemust) {
        qemudReportError(st->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("stream is not open"));
        return -1;
    }

    qemuDriverLock(driver);

retry:
    ret = write(qemust->fd, bytes, nbytes);
    if (ret < 0) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            ret = -2;
        } else if (errno == EINTR) {
            goto retry;
        } else {
            ret = -1;
            virReportSystemError(st->conn, errno, "%s",
                                 _("cannot write to stream"));
        }
    }

    qemuDriverUnlock(driver);
    return ret;
}

static virStreamDriver qemuStreamMigDrv = {
    .streamSend = qemuStreamMigWrite,
    .streamFinish = qemuStreamMigClose,
    .streamAbort = qemuStreamMigClose,
    .streamAddCallback = qemuStreamMigAddCallback,
    .streamUpdateCallback = qemuStreamMigUpdateCallback,
    .streamRemoveCallback = qemuStreamMigRemoveCallback
};

/* 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;
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    char *migrateFrom;
    virDomainEventPtr event = NULL;
    int ret = -1;
    int internalret;
    char *unixfile = NULL;
    unsigned int qemuCmdFlags;
    struct qemuStreamMigFile *qemust = NULL;

    qemuDriverLock(driver);
    if (!dom_xml) {
        qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("no domain XML passed"));
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
        qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
        qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("tunnelled migration requested but NULL stream passed"));
        goto cleanup;
    }

    /* Parse the domain XML. */
    if (!(def = virDomainDefParseString(dconn, driver->caps, dom_xml,
                                        VIR_DOMAIN_XML_INACTIVE))) {
        qemudReportError(dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("failed to parse XML"));
        goto cleanup;
    }

    /* Target domain name, maybe renamed. */
    dname = dname ? dname : def->name;

    /* Ensure the name and UUID don't already exist in an active VM */
    vm = virDomainFindByUUID(&driver->domains, def->uuid);

    if (!vm) vm = virDomainFindByName(&driver->domains, dname);
    if (vm) {
D
Daniel P. Berrange 已提交
6072
        if (virDomainObjIsActive(vm)) {
C
Chris Lalancette 已提交
6073 6074 6075 6076 6077 6078 6079 6080 6081
            qemudReportError(dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                             _("domain with the same name or UUID already exists as '%s'"),
                             vm->def->name);
            goto cleanup;
        }
        virDomainObjUnlock(vm);
    }

    if (!(vm = virDomainAssignDef(dconn,
6082
                                  driver->caps,
C
Chris Lalancette 已提交
6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165
                                  &driver->domains,
                                  def))) {
        qemudReportError(dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("failed to assign new VM"));
        goto cleanup;
    }
    def = NULL;

    /* Domain starts inactive, even if the domain XML had an id field. */
    vm->def->id = -1;

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.dest.%s",
                    driver->stateDir, vm->def->name) < 0) {
        virReportOOMError (dconn);
        goto cleanup;
    }
    unlink(unixfile);

    /* check that this qemu version supports the interactive exec */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
        qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Cannot determine QEMU argv syntax %s"),
                         vm->def->emulator);
        goto cleanup;
    }
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX)
        internalret = virAsprintf(&migrateFrom, "unix:%s", unixfile);
    else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)
        internalret = virAsprintf(&migrateFrom, "exec:nc -U -l %s", unixfile);
    else {
        qemudReportError(dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("Destination qemu is too old to support tunnelled migration"));
        goto cleanup;
    }
    if (internalret < 0) {
        virReportOOMError(dconn);
        goto cleanup;
    }
    /* Start the QEMU daemon, with the same command-line arguments plus
     * -incoming unix:/path/to/file or exec:nc -U /path/to/file
     */
    internalret = qemudStartVMDaemon(dconn, driver, vm, migrateFrom, -1);
    VIR_FREE(migrateFrom);
    if (internalret < 0) {
        /* Note that we don't set an error here because qemudStartVMDaemon
         * should have already done that.
         */
        if (!vm->persistent) {
            virDomainRemoveInactive(&driver->domains, vm);
            vm = NULL;
        }
        goto cleanup;
    }

    qemust = qemuStreamMigOpen(st, unixfile);
    if (qemust == NULL) {
        qemudShutdownVMDaemon(NULL, driver, vm);
        virReportSystemError(dconn, errno,
                             _("cannot open unix socket '%s' for tunnelled migration"),
                             unixfile);
        goto cleanup;
    }

    st->driver = &qemuStreamMigDrv;
    st->privateData = qemust;

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_MIGRATED);
    ret = 0;

cleanup:
    virDomainDefFree(def);
    unlink(unixfile);
    VIR_FREE(unixfile);
    if (vm)
        virDomainObjUnlock(vm);
    if (event)
        qemuDomainEventQueue(driver, event);
    qemuDriverUnlock(driver);
    return ret;
}

D
Daniel Veillard 已提交
6166 6167 6168 6169 6170 6171 6172 6173 6174 6175
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
static int
qemudDomainMigratePrepare2 (virConnectPtr dconn,
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
6176
                            unsigned long flags,
D
Daniel Veillard 已提交
6177 6178 6179 6180 6181
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
    static int port = 0;
6182 6183
    struct qemud_driver *driver = dconn->privateData;
    virDomainDefPtr def = NULL;
D
Daniel Veillard 已提交
6184 6185
    virDomainObjPtr vm = NULL;
    int this_port;
6186
    char *hostname;
D
Daniel Veillard 已提交
6187 6188
    char migrateFrom [64];
    const char *p;
6189
    virDomainEventPtr event = NULL;
6190
    int ret = -1;
6191
    int internalret;
6192 6193

    *uri_out = NULL;
D
Daniel Veillard 已提交
6194

6195
    qemuDriverLock(driver);
C
Chris Lalancette 已提交
6196 6197 6198 6199 6200 6201 6202 6203 6204
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
        qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Tunnelled migration requested but invalid RPC method called"));
        goto cleanup;
    }

D
Daniel Veillard 已提交
6205 6206 6207
    if (!dom_xml) {
        qemudReportError (dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                          "%s", _("no domain XML passed"));
6208
        goto cleanup;
D
Daniel Veillard 已提交
6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225
    }

    /* The URI passed in may be NULL or a string "tcp://somehostname:port".
     *
     * If the URI passed in is NULL then we allocate a port number
     * from our pool of port numbers and return a URI of
     * "tcp://ourhostname:port".
     *
     * If the URI passed in is not NULL then we try to parse out the
     * port number and use that (note that the hostname is assumed
     * to be a correct hostname which refers to the target machine).
     */
    if (uri_in == NULL) {
        this_port = QEMUD_MIGRATION_FIRST_PORT + port++;
        if (port == QEMUD_MIGRATION_NUM_PORTS) port = 0;

        /* Get hostname */
6226
        if ((hostname = virGetHostname(dconn)) == NULL)
6227
            goto cleanup;
D
Daniel Veillard 已提交
6228

6229 6230 6231 6232 6233
        /* XXX this really should have been a properly well-formed
         * URI, but we can't add in tcp:// now without breaking
         * compatability with old targets. We at least make the
         * new targets accept both syntaxes though.
         */
D
Daniel Veillard 已提交
6234
        /* Caller frees */
6235 6236 6237
        internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
        VIR_FREE(hostname);
        if (internalret < 0) {
6238
            virReportOOMError (dconn);
6239
            goto cleanup;
D
Daniel Veillard 已提交
6240 6241 6242 6243 6244 6245
        }
    } else {
        /* Check the URI starts with "tcp:".  We will escape the
         * URI when passing it to the qemu monitor, so bad
         * characters in hostname part don't matter.
         */
6246
        if (!STRPREFIX (uri_in, "tcp:")) {
D
Daniel Veillard 已提交
6247
            qemudReportError (dconn, NULL, NULL, VIR_ERR_INVALID_ARG,
6248
                  "%s", _("only tcp URIs are supported for KVM/QEMU migrations"));
6249
            goto cleanup;
D
Daniel Veillard 已提交
6250 6251 6252 6253
        }

        /* Get the port number. */
        p = strrchr (uri_in, ':');
6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273
        if (p == strchr(uri_in, ':')) {
            /* Generate a port */
            this_port = QEMUD_MIGRATION_FIRST_PORT + port++;
            if (port == QEMUD_MIGRATION_NUM_PORTS)
                port = 0;

            /* Caller frees */
            if (virAsprintf(uri_out, "%s:%d", uri_in, this_port) < 0) {
                virReportOOMError (dconn);
                goto cleanup;
            }

        } else {
            p++; /* definitely has a ':' in it, see above */
            this_port = virParseNumber (&p);
            if (this_port == -1 || p-uri_in != strlen (uri_in)) {
                qemudReportError (dconn, NULL, NULL, VIR_ERR_INVALID_ARG,
                                  "%s", _("URI ended with incorrect ':port'"));
                goto cleanup;
            }
D
Daniel Veillard 已提交
6274 6275 6276
        }
    }

6277 6278 6279
    if (uri_out && *uri_out)
        VIR_DEBUG("Generated uri_out=%s", *uri_out);

D
Daniel Veillard 已提交
6280
    /* Parse the domain XML. */
6281 6282
    if (!(def = virDomainDefParseString(dconn, driver->caps, dom_xml,
                                        VIR_DOMAIN_XML_INACTIVE))) {
D
Daniel Veillard 已提交
6283 6284
        qemudReportError (dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                          "%s", _("failed to parse XML"));
6285
        goto cleanup;
D
Daniel Veillard 已提交
6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301
    }

    /* Target domain name, maybe renamed. */
    dname = dname ? dname : def->name;

#if 1
    /* Ensure the name and UUID don't already exist in an active VM */
    vm = virDomainFindByUUID(&driver->domains, def->uuid);
#else
    /* For TESTING ONLY you can change #if 1 -> #if 0 above and use
     * this code which lets you do localhost migrations.  You must still
     * supply a fresh 'dname' but this code assigns a random UUID.
     */
    if (virUUIDGenerate (def->uuid) == -1) {
        qemudReportError (dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
            _("could not generate random UUID"));
6302
        goto cleanup;
D
Daniel Veillard 已提交
6303 6304 6305 6306 6307
    }
#endif

    if (!vm) vm = virDomainFindByName(&driver->domains, dname);
    if (vm) {
D
Daniel P. Berrange 已提交
6308
        if (virDomainObjIsActive(vm)) {
D
Daniel Veillard 已提交
6309 6310 6311
            qemudReportError (dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                              _("domain with the same name or UUID already exists as '%s'"),
                              vm->def->name);
6312
            goto cleanup;
D
Daniel Veillard 已提交
6313
        }
6314
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
6315 6316 6317
    }

    if (!(vm = virDomainAssignDef(dconn,
6318
                                  driver->caps,
D
Daniel Veillard 已提交
6319 6320 6321 6322
                                  &driver->domains,
                                  def))) {
        qemudReportError (dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                          "%s", _("failed to assign new VM"));
6323
        goto cleanup;
D
Daniel Veillard 已提交
6324
    }
6325
    def = NULL;
D
Daniel Veillard 已提交
6326 6327 6328 6329 6330 6331 6332 6333

    /* Domain starts inactive, even if the domain XML had an id field. */
    vm->def->id = -1;

    /* Start the QEMU daemon, with the same command-line arguments plus
     * -incoming tcp:0.0.0.0:port
     */
    snprintf (migrateFrom, sizeof (migrateFrom), "tcp:0.0.0.0:%d", this_port);
6334
    if (qemudStartVMDaemon (dconn, driver, vm, migrateFrom, -1) < 0) {
6335 6336 6337
        /* Note that we don't set an error here because qemudStartVMDaemon
         * should have already done that.
         */
6338
        if (!vm->persistent) {
D
Daniel Veillard 已提交
6339
            virDomainRemoveInactive(&driver->domains, vm);
6340 6341
            vm = NULL;
        }
6342
        goto cleanup;
D
Daniel Veillard 已提交
6343
    }
6344 6345 6346 6347

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_MIGRATED);
6348
    ret = 0;
D
Daniel Veillard 已提交
6349

6350 6351 6352 6353 6354
cleanup:
    virDomainDefFree(def);
    if (ret != 0) {
        VIR_FREE(*uri_out);
    }
6355 6356
    if (vm)
        virDomainObjUnlock(vm);
6357 6358
    if (event)
        qemuDomainEventQueue(driver, event);
6359
    qemuDriverUnlock(driver);
6360
    return ret;
C
Chris Lalancette 已提交
6361 6362 6363

}

6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375

/* Perform migration using QEMU's native TCP migrate support,
 * not encrypted obviously
 */
static int doNativeMigrate(virDomainPtr dom,
                           virDomainObjPtr vm,
                           const char *uri,
                           unsigned long flags ATTRIBUTE_UNUSED,
                           const char *dname ATTRIBUTE_UNUSED,
                           unsigned long resource)
{
    int ret = -1;
6376
    xmlURIPtr uribits = NULL;
6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429
    int status;
    unsigned long long transferred, remaining, total;

    /* Issue the migrate command. */
    if (STRPREFIX(uri, "tcp:") && !STRPREFIX(uri, "tcp://")) {
        /* HACK: source host generates bogus URIs, so fix them up */
        char *tmpuri;
        if (virAsprintf(&tmpuri, "tcp://%s", uri + strlen("tcp:")) < 0) {
            virReportOOMError(dom->conn);
            goto cleanup;
        }
        uribits = xmlParseURI(tmpuri);
        VIR_FREE(tmpuri);
    } else {
        uribits = xmlParseURI(uri);
    }
    if (!uribits) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("cannot parse URI %s"), uri);
        goto cleanup;
    }

    if (resource > 0 &&
        qemuMonitorSetMigrationSpeed(vm, resource) < 0)
        goto cleanup;

    if (qemuMonitorMigrateToHost(vm, 0, uribits->server, uribits->port) < 0)
        goto cleanup;

    /* it is also possible that the migrate didn't fail initially, but
     * rather failed later on.  Check the output of "info migrate"
     */
    if (qemuMonitorGetMigrationStatus(vm, &status,
                                      &transferred,
                                      &remaining,
                                      &total) < 0) {
        goto cleanup;
    }

    if (status != QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) {
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                          "%s", _("migrate did not successfully complete"));
        goto cleanup;
    }

    ret = 0;

cleanup:
    xmlFreeURI(uribits);
    return ret;
}


6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450
static int doTunnelSendAll(virDomainPtr dom,
                           virStreamPtr st,
                           int sock)
{
    char buffer[65536];
    int nbytes = sizeof(buffer);

    /* XXX should honour the 'resource' parameter here */
    for (;;) {
        nbytes = saferead(sock, buffer, nbytes);
        if (nbytes < 0) {
            virStreamAbort(st);
            virReportSystemError(dom->conn, errno, "%s",
                                 _("tunnelled migration failed to read from qemu"));
            return -1;
        }
        else if (nbytes == 0)
            /* EOF; get out of here */
            break;

        if (virStreamSend(st, buffer, nbytes) < 0) {
C
Chris Lalancette 已提交
6451
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s",
6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463
                             _("Failed to write migration data to remote libvirtd"));
            return -1;
        }
    }

    if (virStreamFinish(st) < 0)
        /* virStreamFinish set the error for us */
        return -1;

    return 0;
}

C
Chris Lalancette 已提交
6464
static int doTunnelMigrate(virDomainPtr dom,
6465
                           virConnectPtr dconn,
C
Chris Lalancette 已提交
6466
                           virDomainObjPtr vm,
6467
                           const char *dom_xml,
C
Chris Lalancette 已提交
6468 6469 6470 6471 6472 6473
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
6474 6475
    int client_sock = -1;
    int qemu_sock = -1;
C
Chris Lalancette 已提交
6476 6477
    struct sockaddr_un sa_qemu, sa_client;
    socklen_t addrlen;
6478
    virDomainPtr ddomain = NULL;
C
Chris Lalancette 已提交
6479
    int retval = -1;
6480
    virStreamPtr st = NULL;
C
Chris Lalancette 已提交
6481 6482 6483 6484 6485 6486
    char *unixfile = NULL;
    int internalret;
    unsigned int qemuCmdFlags;
    int status;
    unsigned long long transferred, remaining, total;

6487 6488 6489 6490 6491 6492 6493 6494
    /*
     * The order of operations is important here to avoid touching
     * the source VM until we are very sure we can successfully
     * start the migration operation.
     *
     *   1. setup local support infrastructure (eg sockets)
     *   2. setup destination fully
     *   3. start migration on source
C
Chris Lalancette 已提交
6495 6496
     */

6497

6498
    /* Stage 1. setup local support infrastructure */
C
Chris Lalancette 已提交
6499 6500 6501 6502

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
                    driver->stateDir, vm->def->name) < 0) {
        virReportOOMError(dom->conn);
6503
        goto cleanup;
C
Chris Lalancette 已提交
6504 6505 6506 6507 6508 6509
    }

    qemu_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (qemu_sock < 0) {
        virReportSystemError(dom->conn, errno, "%s",
                             _("cannot open tunnelled migration socket"));
6510
        goto cleanup;
C
Chris Lalancette 已提交
6511 6512 6513 6514 6515 6516 6517 6518
    }
    memset(&sa_qemu, 0, sizeof(sa_qemu));
    sa_qemu.sun_family = AF_UNIX;
    if (virStrcpy(sa_qemu.sun_path, unixfile,
                  sizeof(sa_qemu.sun_path)) == NULL) {
        qemudReportError(dom->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Unix socket '%s' too big for destination"),
                         unixfile);
6519
        goto cleanup;
C
Chris Lalancette 已提交
6520 6521 6522 6523 6524 6525
    }
    unlink(unixfile);
    if (bind(qemu_sock, (struct sockaddr *)&sa_qemu, sizeof(sa_qemu)) < 0) {
        virReportSystemError(dom->conn, errno,
                             _("Cannot bind to unix socket '%s' for tunnelled migration"),
                             unixfile);
6526
        goto cleanup;
C
Chris Lalancette 已提交
6527 6528 6529 6530 6531
    }
    if (listen(qemu_sock, 1) < 0) {
        virReportSystemError(dom->conn, errno,
                             _("Cannot listen on unix socket '%s' for tunnelled migration"),
                             unixfile);
6532
        goto cleanup;
C
Chris Lalancette 已提交
6533 6534 6535 6536 6537 6538 6539
    }

    /* check that this qemu version supports the unix migration */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
        qemudReportError(dom->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("Cannot extract Qemu version from '%s'"),
                         vm->def->emulator);
6540 6541 6542 6543 6544 6545 6546 6547
        goto cleanup;
    }

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX) &&
        !(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
        qemudReportError(dom->conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("Source qemu is too old to support tunnelled migration"));
        goto cleanup;
C
Chris Lalancette 已提交
6548
    }
6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569


    /* Stage 2. setup destination fully
     *
     * Once stage 2 has completed successfully, we *must* call finish
     * to cleanup the target whether we succeed or fail
     */
    st = virStreamNew(dconn, 0);
    if (st == NULL)
        /* virStreamNew only fails on OOM, and it reports the error itself */
        goto cleanup;

    internalret = dconn->driver->domainMigratePrepareTunnel(dconn, st,
                                                            flags, dname,
                                                            resource, dom_xml);

    if (internalret < 0)
        /* domainMigratePrepareTunnel sets the error for us */
        goto cleanup;

    /*   3. start migration on source */
C
Chris Lalancette 已提交
6570 6571 6572 6573 6574
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX)
        internalret = qemuMonitorMigrateToUnix(vm, 1, unixfile);
    else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
        const char *args[] = { "nc", "-U", unixfile, NULL };
        internalret = qemuMonitorMigrateToCommand(vm, 1, args, "/dev/null");
6575 6576
    } else {
        internalret = -1;
C
Chris Lalancette 已提交
6577 6578 6579 6580
    }
    if (internalret < 0) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("tunnelled migration monitor command failed"));
6581
        goto finish;
C
Chris Lalancette 已提交
6582 6583
    }

6584 6585 6586
    /* From this point onwards we *must* call cancel to abort the
     * migration on source if anything goes wrong */

C
Chris Lalancette 已提交
6587 6588 6589 6590 6591 6592 6593
    /* it is also possible that the migrate didn't fail initially, but
     * rather failed later on.  Check the output of "info migrate"
     */
    if (qemuMonitorGetMigrationStatus(vm, &status,
                                      &transferred,
                                      &remaining,
                                      &total) < 0) {
6594
        goto cancel;
C
Chris Lalancette 已提交
6595 6596 6597 6598 6599
    }

    if (status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s",_("migrate failed"));
6600
        goto cancel;
C
Chris Lalancette 已提交
6601 6602 6603 6604 6605 6606 6607 6608
    }

    addrlen = sizeof(sa_client);
    while ((client_sock = accept(qemu_sock, (struct sockaddr *)&sa_client, &addrlen)) < 0) {
        if (errno == EAGAIN || errno == EINTR)
            continue;
        virReportSystemError(dom->conn, errno, "%s",
                             _("tunnelled migration failed to accept from qemu"));
6609
        goto cancel;
C
Chris Lalancette 已提交
6610 6611
    }

6612
    retval = doTunnelSendAll(dom, st, client_sock);
6613

6614
cancel:
C
Chris Lalancette 已提交
6615 6616 6617
    if (retval != 0)
        qemuMonitorMigrateCancel(vm);

6618
finish:
C
Chris Lalancette 已提交
6619 6620 6621
    dname = dname ? dname : dom->name;
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri, flags, retval);
6622 6623 6624 6625 6626 6627 6628

cleanup:
    if (client_sock != -1)
        close(client_sock);
    if (qemu_sock != -1)
        close(qemu_sock);

C
Chris Lalancette 已提交
6629 6630 6631
    if (ddomain)
        virUnrefDomain(ddomain);

6632 6633 6634 6635
    if (unixfile) {
        unlink(unixfile);
        VIR_FREE(unixfile);
    }
C
Chris Lalancette 已提交
6636

6637 6638 6639
    if (st)
        /* don't call virStreamFree(), because that resets any pending errors */
        virUnrefStream(st);
6640 6641 6642 6643
    return retval;
}


6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672
/* This is essentially a simplified re-impl of
 * virDomainMigrateVersion2 from libvirt.c, but running in source
 * libvirtd context, instead of client app context */
static int doNonTunnelMigrate(virDomainPtr dom,
                              virConnectPtr dconn,
                              virDomainObjPtr vm,
                              const char *dom_xml,
                              const char *uri ATTRIBUTE_UNUSED,
                              unsigned long flags,
                              const char *dname,
                              unsigned long resource)
{
    virDomainPtr ddomain = NULL;
    int retval = -1;
    char *uri_out = NULL;

    /* NB we don't pass 'uri' into this, since that's the libvirtd
     * URI in this context - so we let dest pick it */
    if (dconn->driver->domainMigratePrepare2(dconn,
                                             NULL, /* cookie */
                                             0, /* cookielen */
                                             NULL, /* uri */
                                             &uri_out,
                                             flags, dname,
                                             resource, dom_xml) < 0)
        /* domainMigratePrepare2 sets the error for us */
        goto cleanup;

    if (uri_out == NULL) {
C
Chris Lalancette 已提交
6673
        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694
                         _("domainMigratePrepare2 did not set uri"));
    }

    if (doNativeMigrate(dom, vm, uri_out, flags, dname, resource) < 0)
        goto finish;

    retval = 0;

finish:
    dname = dname ? dname : dom->name;
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri_out, flags, retval);

    if (ddomain)
        virUnrefDomain(ddomain);

cleanup:
    return retval;
}


6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716
static int doPeer2PeerMigrate(virDomainPtr dom,
                              virDomainObjPtr vm,
                              const char *uri,
                              unsigned long flags,
                              const char *dname,
                              unsigned long resource)
{
    int ret = -1;
    virConnectPtr dconn = NULL;
    char *dom_xml;

    /* the order of operations is important here; we make sure the
     * destination side is completely setup before we touch the source
     */

    dconn = virConnectOpen(uri);
    if (dconn == NULL) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         _("Failed to connect to remote libvirt URI %s"), uri);
        return -1;
    }
    if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
6717
                                  VIR_DRV_FEATURE_MIGRATION_P2P)) {
6718
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s",
6719
                         _("Destination libvirt does not support peer-to-peer migration protocol"));
6720 6721 6722 6723 6724 6725 6726 6727 6728 6729
        goto cleanup;
    }

    dom_xml = virDomainDefFormat(dom->conn, vm->def, VIR_DOMAIN_XML_SECURE);
    if (!dom_xml) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("failed to get domain xml"));
        goto cleanup;
    }

6730 6731 6732 6733
    if (flags & VIR_MIGRATE_TUNNELLED)
        ret = doTunnelMigrate(dom, dconn, vm, dom_xml, uri, flags, dname, resource);
    else
        ret = doNonTunnelMigrate(dom, dconn, vm, dom_xml, uri, flags, dname, resource);
6734 6735 6736

cleanup:
    VIR_FREE(dom_xml);
C
Chris Lalancette 已提交
6737 6738 6739
    /* don't call virConnectClose(), because that resets any pending errors */
    virUnrefConnect(dconn);

6740
    return ret;
D
Daniel Veillard 已提交
6741 6742
}

6743

D
Daniel Veillard 已提交
6744 6745 6746 6747 6748 6749
/* 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,
6750
                           unsigned long flags,
6751
                           const char *dname,
D
Daniel Veillard 已提交
6752 6753
                           unsigned long resource)
{
6754 6755
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6756
    virDomainEventPtr event = NULL;
6757
    int ret = -1;
6758
    int paused = 0;
D
Daniel Veillard 已提交
6759

6760
    qemuDriverLock(driver);
6761
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
6762
    if (!vm) {
6763 6764 6765 6766
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching uuid '%s'"), uuidstr);
6767
        goto cleanup;
D
Daniel Veillard 已提交
6768 6769
    }

D
Daniel P. Berrange 已提交
6770
    if (!virDomainObjIsActive(vm)) {
6771
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
D
Daniel Veillard 已提交
6772
                          "%s", _("domain is not running"));
6773
        goto cleanup;
D
Daniel Veillard 已提交
6774 6775
    }

6776 6777
    if (!(flags & VIR_MIGRATE_LIVE)) {
        /* Pause domain for non-live migration */
6778
        if (qemuMonitorStopCPUs(vm) < 0)
6779 6780
            goto cleanup;
        paused = 1;
6781

6782 6783 6784 6785 6786 6787
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
        if (event)
            qemuDomainEventQueue(driver, event);
        event = NULL;
6788 6789
    }

6790
    if ((flags & VIR_MIGRATE_TUNNELLED)) {
6791
        if (doPeer2PeerMigrate(dom, vm, uri, flags, dname, resource) < 0)
C
Chris Lalancette 已提交
6792 6793
            /* doTunnelMigrate already set the error, so just get out */
            goto cleanup;
6794 6795 6796
    } else {
        if (doNativeMigrate(dom, vm, uri, flags, dname, resource) < 0)
            goto cleanup;
6797 6798
    }

D
Daniel Veillard 已提交
6799 6800
    /* Clean up the source domain. */
    qemudShutdownVMDaemon (dom->conn, driver, vm);
6801
    paused = 0;
6802 6803 6804 6805

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
C
Chris Lalancette 已提交
6806 6807
    if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
        virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm);
D
Daniel Veillard 已提交
6808
        virDomainRemoveInactive(&driver->domains, vm);
6809 6810
        vm = NULL;
    }
6811
    ret = 0;
D
Daniel Veillard 已提交
6812

6813
cleanup:
6814 6815
    if (paused) {
        /* we got here through some sort of failure; start the domain again */
6816
        if (qemuMonitorStartCPUs(dom->conn, vm) < 0) {
6817 6818 6819 6820
            /* Hm, we already know we are in error here.  We don't want to
             * overwrite the previous error, though, so we just throw something
             * to the logs and hope for the best
             */
6821 6822
            VIR_ERROR(_("Failed to resume guest %s after failure\n"),
                      vm->def->name);
6823 6824 6825 6826 6827 6828 6829
        }

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }

6830 6831
    if (vm)
        virDomainObjUnlock(vm);
6832 6833
    if (event)
        qemuDomainEventQueue(driver, event);
6834
    qemuDriverUnlock(driver);
6835
    return ret;
D
Daniel Veillard 已提交
6836 6837 6838 6839 6840 6841 6842 6843 6844
}

/* 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 已提交
6845
                           unsigned long flags,
D
Daniel Veillard 已提交
6846 6847
                           int retcode)
{
6848 6849 6850
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
6851
    virDomainEventPtr event = NULL;
C
Chris Lalancette 已提交
6852
    int newVM = 1;
D
Daniel Veillard 已提交
6853

6854
    qemuDriverLock(driver);
6855
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
6856
    if (!vm) {
6857 6858
        qemudReportError (dconn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                          _("no domain with matching name '%s'"), dname);
6859
        goto cleanup;
D
Daniel Veillard 已提交
6860 6861 6862 6863 6864 6865
    }

    /* Did the migration go as planned?  If yes, return the domain
     * object, but if no, clean up the empty qemu process.
     */
    if (retcode == 0) {
C
Chris Lalancette 已提交
6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893
        if (flags & VIR_MIGRATE_PERSIST_DEST) {
            if (vm->persistent)
                newVM = 0;
            vm->persistent = 1;

            if (virDomainSaveConfig(dconn, driver->configDir, vm->def) < 0) {
                /* Hmpf.  Migration was successful, but making it persistent
                 * was not.  If we report successful, then when this domain
                 * shuts down, management tools are in for a surprise.  On the
                 * other hand, if we report failure, then the management tools
                 * might try to restart the domain on the source side, even
                 * though the domain is actually running on the destination.
                 * Return a NULL dom pointer, and hope that this is a rare
                 * situation and management tools are smart.
                 */
                vm = NULL;
                goto cleanup;
            }

            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_DEFINED,
                                             newVM ?
                                             VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                             VIR_DOMAIN_EVENT_DEFINED_UPDATED);
            if (event)
                qemuDomainEventQueue(driver, event);

        }
D
Daniel Veillard 已提交
6894
        dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
6895 6896 6897 6898 6899

        /* run 'cont' on the destination, which allows migration on qemu
         * >= 0.10.6 to work properly.  This isn't strictly necessary on
         * older qemu's, but it also doesn't hurt anything there
         */
6900
        if (qemuMonitorStartCPUs(dconn, vm) < 0) {
6901 6902 6903
            if (virGetLastError() == NULL)
                qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("resume operation failed"));
6904 6905 6906
            goto cleanup;
        }

D
Daniel Veillard 已提交
6907
        vm->state = VIR_DOMAIN_RUNNING;
6908 6909 6910
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
D
Daniel Veillard 已提交
6911
        virDomainSaveStatus(dconn, driver->stateDir, vm);
D
Daniel Veillard 已提交
6912 6913
    } else {
        qemudShutdownVMDaemon (dconn, driver, vm);
6914 6915 6916
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
6917
        if (!vm->persistent) {
D
Daniel Veillard 已提交
6918
            virDomainRemoveInactive(&driver->domains, vm);
6919 6920
            vm = NULL;
        }
D
Daniel Veillard 已提交
6921
    }
6922 6923

cleanup:
6924 6925
    if (vm)
        virDomainObjUnlock(vm);
6926 6927
    if (event)
        qemuDomainEventQueue(driver, event);
6928
    qemuDriverUnlock(driver);
6929
    return dom;
D
Daniel Veillard 已提交
6930 6931
}

6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947
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;

6948
    def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026
    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) {
        qemudReportError(dev->conn, NULL, NULL, VIR_ERR_INVALID_ARG,
                         _("device %s is not a PCI device"), dev->name);
        goto out;
    }

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

static int
qemudNodeDeviceDettach (virNodeDevicePtr dev)
{
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

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

    pci = pciGetDevice(dev->conn, domain, bus, slot, function);
    if (!pci)
        return -1;

    if (pciDettachDevice(dev->conn, pci) < 0)
        goto out;

    ret = 0;
out:
    pciFreeDevice(dev->conn, pci);
    return ret;
}

static int
qemudNodeDeviceReAttach (virNodeDevicePtr dev)
{
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

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

    pci = pciGetDevice(dev->conn, domain, bus, slot, function);
    if (!pci)
        return -1;

    if (pciReAttachDevice(dev->conn, pci) < 0)
        goto out;

    ret = 0;
out:
    pciFreeDevice(dev->conn, pci);
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
7027
    struct qemud_driver *driver = dev->conn->privateData;
7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

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

    pci = pciGetDevice(dev->conn, domain, bus, slot, function);
    if (!pci)
        return -1;

7039 7040 7041
    qemuDriverLock(driver);

    if (pciResetDevice(dev->conn, pci, driver->activePciHostdevs) < 0)
7042 7043 7044 7045
        goto out;

    ret = 0;
out:
7046
    qemuDriverUnlock(driver);
7047 7048 7049 7050
    pciFreeDevice(dev->conn, pci);
    return ret;
}

7051 7052 7053 7054 7055
static virDriver qemuDriver = {
    VIR_DRV_QEMU,
    "QEMU",
    qemudOpen, /* open */
    qemudClose, /* close */
D
Daniel Veillard 已提交
7056
    qemudSupportsFeature, /* supports_feature */
7057 7058
    qemudGetType, /* type */
    qemudGetVersion, /* version */
7059
    virGetHostname, /* getHostname */
7060
    qemudGetMaxVCPUs, /* getMaxVcpus */
7061
    nodeGetInfo, /* nodeGetInfo */
7062 7063 7064
    qemudGetCapabilities, /* getCapabilities */
    qemudListDomains, /* listDomains */
    qemudNumDomains, /* numOfDomains */
7065
    qemudDomainCreate, /* domainCreateXML */
7066 7067 7068 7069 7070
    qemudDomainLookupByID, /* domainLookupByID */
    qemudDomainLookupByUUID, /* domainLookupByUUID */
    qemudDomainLookupByName, /* domainLookupByName */
    qemudDomainSuspend, /* domainSuspend */
    qemudDomainResume, /* domainResume */
7071
    qemudDomainShutdown, /* domainShutdown */
7072 7073 7074
    NULL, /* domainReboot */
    qemudDomainDestroy, /* domainDestroy */
    qemudDomainGetOSType, /* domainGetOSType */
7075 7076 7077
    qemudDomainGetMaxMemory, /* domainGetMaxMemory */
    qemudDomainSetMaxMemory, /* domainSetMaxMemory */
    qemudDomainSetMemory, /* domainSetMemory */
7078 7079 7080
    qemudDomainGetInfo, /* domainGetInfo */
    qemudDomainSave, /* domainSave */
    qemudDomainRestore, /* domainRestore */
P
Paolo Bonzini 已提交
7081
    qemudDomainCoreDump, /* domainCoreDump */
7082
    qemudDomainSetVcpus, /* domainSetVcpus */
7083 7084 7085 7086
#if HAVE_SCHED_GETAFFINITY
    qemudDomainPinVcpu, /* domainPinVcpu */
    qemudDomainGetVcpus, /* domainGetVcpus */
#else
7087 7088
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
7089
#endif
7090
    qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
7091 7092
    qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
    qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
7093
    qemudDomainDumpXML, /* domainDumpXML */
7094
    qemuDomainXMLFromNative, /* domainXmlFromNative */
7095
    qemuDomainXMLToNative, /* domainXMLToNative */
7096 7097
    qemudListDefinedDomains, /* listDefinedDomains */
    qemudNumDefinedDomains, /* numOfDefinedDomains */
7098 7099 7100
    qemudDomainStart, /* domainCreate */
    qemudDomainDefine, /* domainDefineXML */
    qemudDomainUndefine, /* domainUndefine */
7101
    qemudDomainAttachDevice, /* domainAttachDevice */
7102
    qemudDomainDetachDevice, /* domainDetachDevice */
7103 7104
    qemudDomainGetAutostart, /* domainGetAutostart */
    qemudDomainSetAutostart, /* domainSetAutostart */
7105 7106 7107
    qemuGetSchedulerType, /* domainGetSchedulerType */
    qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
    qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
7108 7109
    NULL, /* domainMigratePrepare (v1) */
    qemudDomainMigratePerform, /* domainMigratePerform */
7110
    NULL, /* domainMigrateFinish */
7111
    qemudDomainBlockStats, /* domainBlockStats */
7112
    qemudDomainInterfaceStats, /* domainInterfaceStats */
7113
    qemudDomainBlockPeek, /* domainBlockPeek */
R
Richard W.M. Jones 已提交
7114
    qemudDomainMemoryPeek, /* domainMemoryPeek */
7115 7116
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
7117 7118
    qemudDomainEventRegister, /* domainEventRegister */
    qemudDomainEventDeregister, /* domainEventDeregister */
D
Daniel Veillard 已提交
7119 7120
    qemudDomainMigratePrepare2, /* domainMigratePrepare2 */
    qemudDomainMigrateFinish2, /* domainMigrateFinish2 */
7121 7122 7123
    qemudNodeDeviceDettach, /* nodeDeviceDettach */
    qemudNodeDeviceReAttach, /* nodeDeviceReAttach */
    qemudNodeDeviceReset, /* nodeDeviceReset */
C
Chris Lalancette 已提交
7124
    qemudDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
7125 7126 7127
};


7128
static virStateDriver qemuStateDriver = {
7129
    .name = "QEMU",
7130 7131 7132 7133
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
7134
};
7135

7136
int qemuRegister(void) {
7137 7138 7139 7140
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
    return 0;
}