qemu_driver.c 208.5 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.h"
59
#include "qemu_monitor_text.h"
60
#include "qemu_bridge_filter.h"
J
Jim Meyering 已提交
61
#include "c-ctype.h"
62
#include "event.h"
63
#include "buf.h"
64
#include "util.h"
65
#include "nodeinfo.h"
66
#include "stats_linux.h"
67
#include "capabilities.h"
68
#include "memory.h"
69
#include "uuid.h"
70
#include "domain_conf.h"
71 72
#include "node_device_conf.h"
#include "pci.h"
73
#include "hostusb.h"
74
#include "security/security_driver.h"
75
#include "cgroup.h"
C
Chris Lalancette 已提交
76
#include "libvirt_internal.h"
77

78

79 80
#define VIR_FROM_THIS VIR_FROM_QEMU

81 82
static int qemudShutdown(void);

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

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

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

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

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

111
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
112

113 114
static int qemuDetectVcpuPIDs(virConnectPtr conn,
                              virDomainObjPtr vm);
115

116 117 118
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                                       virDomainDefPtr def);

J
Jim Meyering 已提交
119
static struct qemud_driver *qemu_driver = NULL;
120

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

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

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

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

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


168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
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) {
185 186 187
        virReportSystemError(conn, errno,
                             _("failed to create logfile %s"),
                             logfile);
188 189
        return -1;
    }
190
    if (virSetCloseExec(fd) < 0) {
191 192
        virReportSystemError(conn, errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
193 194 195 196
        close(fd);
        return -1;
    }
    if (lseek(fd, pos, SEEK_SET) < 0) {
197 198 199
        virReportSystemError(conn, errno,
                             _("Unable to seek to %lld in %s"),
                             (long long) pos, logfile);
200 201 202 203 204 205
        close(fd);
    }
    return fd;
}


206 207 208 209 210 211 212 213 214 215 216 217
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 已提交
218
        !virDomainObjIsActive(vm)) {
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
        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);
}

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

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

257 258
    if (conn)
        virConnectClose(conn);
259 260
}

261 262 263 264 265 266 267 268 269 270 271 272 273

/**
 * 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)
{
274
    char ebuf[1024];
275 276 277
    char *file = NULL;

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

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

287 288 289
    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)));
290

D
Daniel Veillard 已提交
291

292
    return 0;
293 294
}

295 296 297 298 299 300 301 302 303
static int
qemuConnectMonitor(virDomainObjPtr vm, int reconnect)
{
    int rc;
    if ((rc = qemuMonitorOpen(vm, reconnect)) != 0) {
        VIR_ERROR(_("Failed to connect monitor for %s: %d\n"),
                  vm->def->name, rc);
        return -1;
    }
304

305 306 307 308 309
    if ((vm->monitorWatch = virEventAddHandle(vm->monitor,
                                              VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR,
                                              qemudDispatchVMEvent,
                                              vm, NULL)) < 0)
        return -1;
310

311 312
    return 0;
}
313 314 315 316

/*
 * Open an existing VM's monitor, re-detect VCPU threads
 * and re-reserve the security labels in use
317
 */
318 319
static void
qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
320
{
321 322 323 324
    virDomainObjPtr obj = payload;
    struct qemud_driver *driver = opaque;

    virDomainObjLock(obj);
325

326
    if (qemuConnectMonitor(obj, 1) < 0)
327
        goto error;
328

329 330 331 332
    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
        goto error;
    }

333 334 335 336
    if (obj->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        driver->securityDriver &&
        driver->securityDriver->domainReserveSecurityLabel &&
        driver->securityDriver->domainReserveSecurityLabel(NULL, obj) < 0)
337
        goto error;
338

339 340
    if (obj->def->id >= driver->nextvmid)
        driver->nextvmid = obj->def->id + 1;
341

342 343
    virDomainObjUnlock(obj);
    return;
344

345
error:
346 347 348 349 350
    /* 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);
351
}
352

353 354 355 356 357 358 359 360 361
/**
 * qemudReconnectVMs
 *
 * Try to re-open the resources for live VMs that we care
 * about.
 */
static void
qemuReconnectDomains(struct qemud_driver *driver)
{
362
    virHashForEach(driver->domains.objs, qemuReconnectDomain, driver);
363 364
}

365 366 367 368 369 370 371 372 373 374 375 376

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) {
377
        virReportOOMError(NULL);
378 379 380 381 382
        return -1;
    }

    caps->host.secModel.doi = strdup(doi);
    if (!caps->host.secModel.doi) {
383
        virReportOOMError(NULL);
384 385 386 387 388 389 390 391 392 393
        return -1;
    }

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

    return 0;
}


394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
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;

414
    VIR_INFO("Initialized security driver %s", security_drv->name);
415 416 417 418 419

    /*
     * Add security policy host caps now that the security driver is
     * initialized.
     */
420 421
    return qemudSecurityCapsInit(security_drv, qemud_drv->caps);
}
422 423


424

425 426 427 428 429 430
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
431
qemudStartup(int privileged) {
432
    char *base = NULL;
D
Daniel P. Berrange 已提交
433
    char driverConf[PATH_MAX];
434
    int rc;
435

436
    if (VIR_ALLOC(qemu_driver) < 0)
437 438
        return -1;

439
    if (virMutexInit(&qemu_driver->lock) < 0) {
440
        VIR_ERROR("%s", _("cannot initialize mutex"));
441 442 443
        VIR_FREE(qemu_driver);
        return -1;
    }
444
    qemuDriverLock(qemu_driver);
445
    qemu_driver->privileged = privileged;
446

447 448 449
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;

450 451 452
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;

453
    /* Init callback list */
454
    if (VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
455
        goto out_of_memory;
456 457 458 459 460 461
    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
        goto out_of_memory;

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

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

D
Daniel P. Berrange 已提交
468
        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
469
            goto out_of_memory;
470 471

        if (virAsprintf(&qemu_driver->stateDir,
472
                      "%s/run/libvirt/qemu", LOCAL_STATE_DIR) == -1)
473
            goto out_of_memory;
474 475 476 477 478 479 480 481

        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;
482
    } else {
483
        uid_t uid = geteuid();
484 485
        char *userdir = virGetUserDirectory(NULL, uid);
        if (!userdir)
486
            goto error;
487

488
        if (virAsprintf(&qemu_driver->logDir,
489 490
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
491
            goto out_of_memory;
492
        }
493

494 495
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
496
            goto out_of_memory;
497 498
        }
        VIR_FREE(userdir);
499 500 501

        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
            goto out_of_memory;
502 503 504 505
        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;
506 507 508
    }

    if (virFileMakePath(qemu_driver->stateDir) < 0) {
509
        char ebuf[1024];
510 511
        VIR_ERROR(_("Failed to create state dir '%s': %s\n"),
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
512
        goto error;
513
    }
514 515 516 517 518 519 520 521 522 523 524 525
    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;
    }
526 527 528 529

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

534
    if (virAsprintf(&qemu_driver->configDir, "%s/qemu", base) == -1)
535 536
        goto out_of_memory;

537
    if (virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1)
538 539
        goto out_of_memory;

540
    VIR_FREE(base);
541

542 543 544 545 546 547 548
    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)));
    }

549
    if ((qemu_driver->caps = qemudCapsInit(NULL)) == NULL)
550
        goto out_of_memory;
D
Daniel P. Berrange 已提交
551

552 553 554
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew(NULL)) == NULL)
        goto error;

555
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
556 557 558
        goto error;
    }

559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
    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;
        }
    }

574
    if (qemudSecurityInit(qemu_driver) < 0) {
575
        goto error;
D
Daniel P. Berrange 已提交
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 602 603 604 605 606 607 608
    /* 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;
    }

609 610 611 612 613 614 615 616 617 618 619 620
    /* 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 */
621 622 623 624
    if (virDomainLoadAllConfigs(NULL,
                                qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->configDir,
625
                                qemu_driver->autostartDir,
626
                                0, NULL, NULL) < 0)
627
        goto error;
628 629
    qemuDriverUnlock(qemu_driver);

630 631
    qemudAutostartConfigs(qemu_driver);

632

633 634
    return 0;

635
out_of_memory:
636
    virReportOOMError(NULL);
637 638 639
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
640
    VIR_FREE(base);
641
    qemudShutdown();
642 643 644
    return -1;
}

645 646 647 648
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;

649 650 651 652 653 654 655 656
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }
657 658
}

659 660 661 662 663 664 665 666
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
667 668 669
    if (!qemu_driver)
        return 0;

670
    qemuDriverLock(qemu_driver);
671 672 673 674
    virDomainLoadAllConfigs(NULL,
                            qemu_driver->caps,
                            &qemu_driver->domains,
                            qemu_driver->configDir,
675
                            qemu_driver->autostartDir,
676
                            0, qemudNotifyLoadDomain, qemu_driver);
677
    qemuDriverUnlock(qemu_driver);
678

679
    qemudAutostartConfigs(qemu_driver);
680 681

    return 0;
682 683
}

684 685 686 687 688 689 690 691 692 693
/**
 * 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) {
694
    int active = 0;
695

696 697 698
    if (!qemu_driver)
        return 0;

699
    /* XXX having to iterate here is not great because it requires many locks */
700
    qemuDriverLock(qemu_driver);
701
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
702 703
    qemuDriverUnlock(qemu_driver);
    return active;
704 705
}

706 707 708 709 710 711 712
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
713

714
    if (!qemu_driver)
715
        return -1;
716

717
    qemuDriverLock(qemu_driver);
718
    pciDeviceListFree(NULL, qemu_driver->activePciHostdevs);
719 720
    virCapabilitiesFree(qemu_driver->caps);

721
    virDomainObjListDeinit(&qemu_driver->domains);
722

723
    VIR_FREE(qemu_driver->securityDriverName);
724
    VIR_FREE(qemu_driver->logDir);
725 726
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
727
    VIR_FREE(qemu_driver->stateDir);
728 729
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
730
    VIR_FREE(qemu_driver->vncTLSx509certdir);
J
Jim Meyering 已提交
731
    VIR_FREE(qemu_driver->vncListen);
732
    VIR_FREE(qemu_driver->vncPassword);
733
    VIR_FREE(qemu_driver->vncSASLdir);
734
    VIR_FREE(qemu_driver->saveImageFormat);
735 736
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
D
Daniel P. Berrange 已提交
737

738 739
    /* Free domain callback list */
    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
740 741 742 743
    virDomainEventQueueFree(qemu_driver->domainEventQueue);

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

745 746 747
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);

748 749
    virCgroupFree(&qemu_driver->cgroup);

750
    qemuDriverUnlock(qemu_driver);
751
    virMutexDestroy(&qemu_driver->lock);
752
    VIR_FREE(qemu_driver);
753 754

    return 0;
755 756
}

757 758 759 760
typedef int qemuLogHandleOutput(virConnectPtr conn,
                                virDomainObjPtr vm,
                                const char *output,
                                int fd);
761 762 763 764 765 766 767 768 769

/*
 * Returns -1 for error, 0 on success
 */
static int
qemudReadLogOutput(virConnectPtr conn,
                   virDomainObjPtr vm,
                   int fd,
                   char *buf,
G
Guido Günther 已提交
770
                   size_t buflen,
771
                   qemuLogHandleOutput func,
772 773 774
                   const char *what,
                   int timeout)
{
775
    int retries = (timeout*10);
776
    int got = 0;
777 778 779
    buf[0] = '\0';

    while (retries) {
780
        ssize_t func_ret, ret;
781
        int isdead = 0;
G
Guido Günther 已提交
782

783 784
        func_ret = func(conn, vm, buf, fd);

785 786
        if (kill(vm->pid, 0) == -1 && errno == ESRCH)
            isdead = 1;
787

788 789
        /* Any failures should be detected before we read the log, so we
         * always have something useful to report on failure. */
790 791
        ret = saferead(fd, buf+got, buflen-got-1);
        if (ret < 0) {
792 793 794 795 796 797
            virReportSystemError(conn, errno,
                                 _("Failure while reading %s log output"),
                                 what);
            return -1;
        }

798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
        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;
        }

814 815
        if (func_ret <= 0)
            return func_ret;
816 817 818 819 820 821 822 823 824 825

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

826

827 828 829 830 831 832 833 834
/*
 * Look at a chunk of data from the QEMU stdout logs and try to
 * find a TTY device, as indicated by a line like
 *
 * char device redirected to /dev/pts/3
 *
 * Returns -1 for error, 0 success, 1 continue reading
 */
835
static int
836 837 838 839
qemudExtractTTYPath(virConnectPtr conn,
                    const char *haystack,
                    size_t *offset,
                    char **path)
840
{
841
    static const char needle[] = "char device redirected to";
842
    char *tmp, *dev;
843

844
    VIR_FREE(*path);
845
    /* First look for our magic string */
846 847 848 849 850
    if (!(tmp = strstr(haystack + *offset, needle))) {
        return 1;
    }
    tmp += sizeof(needle);
    dev = tmp;
851

852 853 854 855 856
    /*
     * And look for first whitespace character and nul terminate
     * to mark end of the pty path
     */
    while (*tmp) {
857
        if (c_isspace(*tmp)) {
858 859
            *path = strndup(dev, tmp-dev);
            if (*path == NULL) {
860
                virReportOOMError(conn);
861 862
                return -1;
            }
863

864
            /* ... now further update offset till we get EOL */
865
            *offset = tmp - haystack;
866 867
            return 0;
        }
868
        tmp++;
869 870 871 872 873
    }

    /*
     * We found a path, but didn't find any whitespace,
     * so it must be still incomplete - we should at
874 875
     * least see a \n - indicate that we want to carry
     * on trying again
876
     */
877
    return 1;
878 879 880
}

static int
881
qemudFindCharDevicePTYs(virConnectPtr conn,
882
                        virDomainObjPtr vm,
883 884
                        const char *output,
                        int fd ATTRIBUTE_UNUSED)
885
{
886
    size_t offset = 0;
887
    int ret, i;
888 889

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

893
    /* first comes the serial devices */
894 895
    for (i = 0 ; i < vm->def->nserials ; i++) {
        virDomainChrDefPtr chr = vm->def->serials[i];
896
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
897 898
            if ((ret = qemudExtractTTYPath(conn, output, &offset,
                                           &chr->data.file.path)) != 0)
899
                return ret;
900 901 902
        }
    }

903
    /* then the parallel devices */
904 905
    for (i = 0 ; i < vm->def->nparallels ; i++) {
        virDomainChrDefPtr chr = vm->def->parallels[i];
906
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
907 908
            if ((ret = qemudExtractTTYPath(conn, output, &offset,
                                           &chr->data.file.path)) != 0)
909
                return ret;
910 911 912
        }
    }

913
    return 0;
914 915
}

916 917 918 919
static int
qemudWaitForMonitor(virConnectPtr conn,
                    struct qemud_driver* driver,
                    virDomainObjPtr vm, off_t pos)
920
{
921
    char buf[4096]; /* Plenty of space to get startup greeting */
922 923 924 925 926
    int logfd;
    int ret;

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

929 930 931
    ret = qemudReadLogOutput(conn, vm, logfd, buf, sizeof(buf),
                             qemudFindCharDevicePTYs,
                             "console", 3);
932
    if (close(logfd) < 0) {
933
        char ebuf[4096];
934
        VIR_WARN(_("Unable to close logfile: %s\n"),
935 936
                 virStrerror(errno, ebuf, sizeof ebuf));
    }
937

938 939 940 941 942 943
    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;
    }
944

945
    if (qemuConnectMonitor(vm, 0) < 0)
946 947 948
        return -1;

    return 0;
949 950
}

951
static int
952 953 954 955
qemuDetectVcpuPIDs(virConnectPtr conn,
                   virDomainObjPtr vm) {
    pid_t *cpupids = NULL;
    int ncpupids;
956

957
    if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
958 959 960 961 962
        vm->nvcpupids = 1;
        if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) {
            virReportOOMError(conn);
            return -1;
        }
963 964 965 966
        vm->vcpupids[0] = vm->pid;
        return 0;
    }

967
    /* What follows is now all KVM specific */
968

969 970
    if ((ncpupids = qemuMonitorGetCPUInfo(vm, &cpupids)) < 0)
        return -1;
971

972 973 974
    /* Treat failure to get VCPU<->PID mapping as non-fatal */
    if (ncpupids == 0)
        return 0;
975

976 977 978 979 980 981 982
    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;
    }
983

984 985
    vm->nvcpupids = ncpupids;
    vm->vcpupids = cpupids;
986 987 988
    return 0;
}

989 990
static int
qemudInitCpus(virConnectPtr conn,
D
Daniel Veillard 已提交
991 992
              virDomainObjPtr vm,
              const char *migrateFrom) {
993 994
#if HAVE_SCHED_GETAFFINITY
    cpu_set_t mask;
995
    int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN;
996 997
    virNodeInfo nodeinfo;

998
    if (nodeGetInfo(conn, &nodeinfo) < 0)
999 1000 1001 1002
        return -1;

    /* setaffinity fails if you set bits for CPUs which
     * aren't present, so we have to limit ourselves */
1003 1004 1005
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
1006 1007

    CPU_ZERO(&mask);
D
Daniel P. Berrange 已提交
1008 1009 1010 1011 1012 1013
    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++)
1014
            CPU_SET(i, &mask);
D
Daniel P. Berrange 已提交
1015
    }
1016 1017 1018 1019

    for (i = 0 ; i < vm->nvcpupids ; i++) {
        if (sched_setaffinity(vm->vcpupids[i],
                              sizeof(mask), &mask) < 0) {
1020 1021
            virReportSystemError(conn, errno, "%s",
                                 _("failed to set CPU affinity"));
1022 1023 1024 1025 1026
            return -1;
        }
    }
#endif /* HAVE_SCHED_GETAFFINITY */

D
Daniel Veillard 已提交
1027 1028
    if (migrateFrom == NULL) {
        /* Allow the CPUS to start executing */
1029
        if (qemuMonitorStartCPUs(conn, vm) < 0) {
1030 1031 1032
            if (virGetLastError() == NULL)
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("resume operation failed"));
D
Daniel Veillard 已提交
1033 1034
            return -1;
        }
1035 1036 1037 1038 1039 1040
    }

    return 0;
}


1041
static int
1042 1043
qemuInitPasswords(struct qemud_driver *driver,
                  virDomainObjPtr vm) {
1044
    int ret = 0;
1045

1046 1047 1048
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) {
1049

1050 1051 1052 1053
        ret = qemuMonitorSetVNCPassword(vm,
                                        vm->def->graphics[0]->data.vnc.passwd ?
                                        vm->def->graphics[0]->data.vnc.passwd :
                                        driver->vncPassword);
1054 1055
    }

1056
    return ret;
1057 1058 1059
}


1060
static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
    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;
}

1096 1097 1098 1099 1100
static pciDeviceList *
qemuGetPciHostDeviceList(virConnectPtr conn,
                         virDomainDefPtr def)
{
    pciDeviceList *list;
1101 1102
    int i;

1103 1104
    if (!(list = pciDeviceListNew(conn)))
        return NULL;
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119

    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);
1120 1121 1122 1123
        if (!dev) {
            pciDeviceListFree(conn, list);
            return NULL;
        }
1124

1125
        if (pciDeviceListAdd(conn, list, dev) < 0) {
1126
            pciFreeDevice(conn, dev);
1127 1128
            pciDeviceListFree(conn, list);
            return NULL;
1129 1130
        }

1131
        pciDeviceSetManaged(dev, hostdev->managed);
1132 1133
    }

1134 1135 1136 1137
    return list;
}

static int
1138 1139 1140 1141
qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                            virDomainDefPtr def)
{
    pciDeviceList *pcidevs;
1142
    int ret = -1;
1143 1144 1145 1146 1147 1148 1149

    if (!def->nhostdevs)
        return 0;

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

1150 1151
    while (pciDeviceListCount(pcidevs) > 0) {
        pciDevice *dev = pciDeviceListSteal(NULL, pcidevs, 0);
1152 1153
        if (pciDeviceListAdd(NULL,
                             driver->activePciHostdevs,
1154 1155 1156
                             dev) < 0) {
            pciFreeDevice(NULL, dev);
            goto cleanup;
1157 1158 1159
        }
    }

1160 1161 1162
    ret = 0;

cleanup:
1163 1164 1165 1166 1167 1168 1169 1170
    pciDeviceListFree(NULL, pcidevs);
    return ret;
}

static int
qemuPrepareHostDevices(virConnectPtr conn,
                       struct qemud_driver *driver,
                       virDomainDefPtr def)
1171 1172 1173
{
    pciDeviceList *pcidevs;
    int i;
1174
    int ret = -1;
1175 1176 1177 1178 1179 1180 1181

    if (!def->nhostdevs)
        return 0;

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

1182
    /* We have to use 3 loops here. *All* devices must
1183 1184
     * be detached before we reset any of them, because
     * in some cases you have to reset the whole PCI,
1185 1186
     * which impacts all devices on it. Also, all devices
     * must be reset before being marked as active.
1187 1188 1189 1190 1191 1192 1193
     */

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

1194 1195 1196 1197 1198 1199
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        if (pciDeviceGetManaged(dev) &&
            pciDettachDevice(conn, dev) < 0)
            goto cleanup;
    }
1200 1201 1202

    /* Now that all the PCI hostdevs have be dettached, we can safely
     * reset them */
1203 1204 1205
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        if (pciResetDevice(conn, dev,
1206
                           driver->activePciHostdevs) < 0)
1207 1208
            goto cleanup;
    }
1209

1210
    /* Now mark all the devices as active */
1211 1212 1213
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        pciDeviceListSteal(NULL, pcidevs, dev);
1214 1215
        if (pciDeviceListAdd(conn,
                             driver->activePciHostdevs,
1216 1217 1218 1219
                             dev) < 0) {
            pciFreeDevice(NULL, dev);
            goto cleanup;
        }
1220 1221
    }

1222
    ret = 0;
1223

1224
cleanup:
1225
    pciDeviceListFree(conn, pcidevs);
1226
    return ret;
1227 1228
}

1229
static void
1230 1231 1232
qemuDomainReAttachHostDevices(virConnectPtr conn,
                              struct qemud_driver *driver,
                              virDomainDefPtr def)
1233
{
1234
    pciDeviceList *pcidevs;
1235 1236
    int i;

1237 1238
    if (!def->nhostdevs)
        return;
1239

1240 1241 1242 1243 1244 1245
    if (!(pcidevs = qemuGetPciHostDeviceList(conn, def))) {
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to allocate pciDeviceList: %s\n"),
                  err ? err->message : "");
        virResetError(err);
        return;
1246 1247
    }

1248 1249
    /* Again 3 loops; mark all devices as inactive before reset
     * them and reset all the devices before re-attach */
1250

1251 1252 1253 1254
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        pciDeviceListDel(conn, driver->activePciHostdevs, dev);
    }
1255

1256 1257 1258
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        if (pciResetDevice(conn, dev,
1259
                           driver->activePciHostdevs) < 0) {
1260
            virErrorPtr err = virGetLastError();
1261
            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
1262 1263 1264
                      err ? err->message : "");
            virResetError(err);
        }
1265
    }
1266

1267 1268 1269 1270
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        if (pciDeviceGetManaged(dev) &&
            pciReAttachDevice(NULL, dev) < 0) {
1271
            virErrorPtr err = virGetLastError();
1272
            VIR_ERROR(_("Failed to re-attach PCI device: %s\n"),
1273 1274 1275
                      err ? err->message : "");
            virResetError(err);
        }
1276
    }
1277

1278
    pciDeviceListFree(conn, pcidevs);
1279 1280
}

1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
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

1291 1292 1293 1294 1295 1296
static int qemuSetupCgroup(virConnectPtr conn,
                           struct qemud_driver *driver,
                           virDomainObjPtr vm)
{
    virCgroupPtr cgroup = NULL;
    int rc;
1297
    unsigned int i;
1298 1299 1300 1301
    const char *const *deviceACL =
        driver->cgroupDeviceACL ?
        (const char *const *)driver->cgroupDeviceACL :
        defaultDeviceACL;
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313

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

1314 1315
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        rc = virCgroupDenyAllDevices(cgroup);
1316
        if (rc != 0) {
1317 1318 1319 1320 1321
            if (rc == -EPERM) {
                VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
                goto done;
            }

1322
            virReportSystemError(conn, -rc,
1323
                                 _("Unable to deny all devices for %s"), vm->def->name);
1324 1325 1326
            goto cleanup;
        }

1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
        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;
            }
        }
1341

1342
        rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
1343 1344
        if (rc != 0) {
            virReportSystemError(conn, -rc, "%s",
1345
                                 _("unable to allow /dev/pts/ devices"));
1346 1347 1348
            goto cleanup;
        }

1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
        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;
            }
1368 1369 1370 1371
        }
    }

done:
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 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
    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;
}


1441 1442 1443 1444 1445 1446 1447 1448 1449
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;
}

1450 1451

#ifdef __linux__
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462
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;

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

1465 1466 1467 1468 1469 1470 1471 1472
    if (chown(file, owner->uid, owner->gid) < 0) {
        virReportSystemError(conn, errno, _("cannot set ownership on %s"), file);
        return -1;
    }

    return 0;
}

1473 1474 1475 1476
static int qemuDomainSetHostdevUSBOwnership(virConnectPtr conn,
                                            virDomainHostdevDefPtr def,
                                            uid_t uid, gid_t gid)
{
1477 1478
    struct qemuFileOwner owner = { uid, gid };
    int ret = -1;
1479 1480 1481 1482 1483 1484

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

1485 1486 1487 1488 1489 1490 1491 1492 1493
    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);
1494

1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
    usbFreeDevice(conn, dev);
cleanup:
    return ret;
}

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

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

1508 1509
    if (chown(file, owner->uid, owner->gid) < 0) {
        virReportSystemError(conn, errno, _("cannot set ownership on %s"), file);
1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
        return -1;
    }

    return 0;
}

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

1523 1524 1525 1526 1527
    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);
1528

1529
    if (!dev)
1530 1531
        goto cleanup;

1532 1533
    ret = pciDeviceFileIterate(conn, dev,
                               qemuDomainSetHostdevPCIOwnershipActor, &owner);
1534

1535
    pciFreeDevice(conn, dev);
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
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 已提交
1560
    qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s",
1561 1562 1563 1564 1565 1566
                     _("unable to set host device ownership on this platform"));
    return -1;
#endif

}

1567 1568
static int qemuDomainSetFileOwnership(virConnectPtr conn,
                                      const char *path,
1569 1570 1571
                                      uid_t uid, gid_t gid)
{

1572
    if (!path)
1573 1574
        return 0;

1575 1576
    VIR_DEBUG("Setting ownership on %s to %d:%d", path, uid, gid);
    if (chown(path, uid, gid) < 0) {
1577
        virReportSystemError(conn, errno, _("cannot set ownership on %s"),
1578
                             path);
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607
        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;

1608
        return qemuDomainSetFileOwnership(conn, def->data.disk->src, uid, gid);
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

    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;

1636 1637 1638 1639
    if (qemuDomainSetFileOwnership(conn, def->os.kernel, uid, gid) < 0 ||
        qemuDomainSetFileOwnership(conn, def->os.initrd, uid, gid) < 0)
        return -1;

1640 1641 1642 1643 1644
    for (i = 0 ; i < def->ndisks ; i++) {
        if (restore &&
            (def->disks[i]->readonly || def->disks[i]->shared))
            continue;

1645
        if (qemuDomainSetFileOwnership(conn, def->disks[i]->src, uid, gid) < 0)
1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656
            return -1;
    }

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

    return 0;
}

1657 1658 1659
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
                                            const char *name);

1660 1661 1662 1663
struct qemudHookData {
    virConnectPtr conn;
    virDomainObjPtr vm;
    struct qemud_driver *driver;
1664 1665 1666
};

static int qemudSecurityHook(void *data) {
1667 1668 1669 1670
    struct qemudHookData *h = data;

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

1672
    if (qemudDomainSetSecurityLabel(h->conn, h->driver, h->vm) < 0)
1673 1674 1675 1676 1677
        return -1;

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

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

1681 1682 1683 1684 1685
        if (h->driver->group) {
            if (setregid(h->driver->group, h->driver->group) < 0) {
                virReportSystemError(NULL, errno,
                                     _("cannot change to '%d' group"),
                                     h->driver->group);
1686
                return -1;
1687
            }
1688
        }
1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699
        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;
1700 1701
}

1702 1703 1704 1705 1706 1707
static int
qemuPrepareMonitorChr(virConnectPtr conn,
                      struct qemud_driver *driver,
                      virDomainChrDefPtr monitor_chr,
                      const char *vm)
{
1708 1709
    monitor_chr->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_MONITOR;

1710 1711 1712 1713
    monitor_chr->type = VIR_DOMAIN_CHR_TYPE_UNIX;
    monitor_chr->data.nix.listen = 1;

    if (virAsprintf(&monitor_chr->data.nix.path, "%s/%s.monitor",
1714
                    driver->libDir, vm) < 0) {
1715 1716 1717 1718 1719 1720 1721
        virReportOOMError(conn);
        return -1;
    }

    return 0;
}

1722 1723
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
1724
                              virDomainObjPtr vm,
1725 1726
                              const char *migrateFrom,
                              int stdin_fd) {
1727
    const char **argv = NULL, **tmp;
1728
    const char **progenv = NULL;
1729
    int i, ret;
1730
    struct stat sb;
1731 1732
    int *tapfds = NULL;
    int ntapfds = 0;
1733
    unsigned int qemuCmdFlags;
1734
    fd_set keepfd;
1735
    const char *emulator;
G
Guido Günther 已提交
1736
    pid_t child;
1737
    int pos = -1;
1738
    char ebuf[1024];
1739
    char *pidfile = NULL;
1740
    int logfile;
1741

1742
    struct qemudHookData hookData;
1743 1744 1745 1746
    hookData.conn = conn;
    hookData.vm = vm;
    hookData.driver = driver;

1747
    FD_ZERO(&keepfd);
1748

D
Daniel P. Berrange 已提交
1749
    if (virDomainObjIsActive(vm)) {
1750
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_INVALID,
1751
                         "%s", _("VM is already active"));
1752 1753 1754
        return -1;
    }

1755 1756 1757 1758 1759 1760 1761 1762
    /* 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;

1763 1764 1765
    /* Ensure no historical cgroup for this VM is lieing around bogus settings */
    qemuRemoveCgroup(conn, driver, vm);

1766 1767 1768
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        vm->def->graphics[0]->data.vnc.autoport) {
1769
        int port = qemudNextFreeVNCPort(driver);
1770
        if (port < 0) {
1771
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
1772
                             "%s", _("Unable to find an unused VNC port"));
1773
            goto cleanup;
1774
        }
1775
        vm->def->graphics[0]->data.vnc.port = port;
1776
    }
1777

1778
    if (virFileMakePath(driver->logDir) < 0) {
1779 1780 1781
        virReportSystemError(conn, errno,
                             _("cannot create log directory %s"),
                             driver->logDir);
1782
        goto cleanup;
1783 1784
    }

1785
    if ((logfile = qemudLogFD(conn, driver, vm->def->name)) < 0)
1786
        goto cleanup;
1787

1788 1789
    emulator = vm->def->emulator;

1790 1791 1792 1793
    /* 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
     */
1794
    if (stat(emulator, &sb) < 0) {
1795 1796 1797
        virReportSystemError(conn, errno,
                             _("Cannot find QEMU binary %s"),
                             emulator);
1798
        goto cleanup;
1799 1800
    }

1801
    if (qemudExtractVersionInfo(emulator,
1802
                                NULL,
1803
                                &qemuCmdFlags) < 0)
1804
        goto cleanup;
1805

1806 1807 1808
    if (qemuSetupCgroup(conn, driver, vm) < 0)
        goto cleanup;

1809
    if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
1810
        goto cleanup;
1811

1812 1813 1814 1815 1816
    if (VIR_ALLOC(vm->monitor_chr) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }

1817 1818
    if (qemuPrepareMonitorChr(conn, driver, vm->monitor_chr, vm->def->name) < 0)
        goto cleanup;
1819

D
Daniel P. Berrange 已提交
1820 1821 1822 1823 1824 1825 1826
    if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
        virReportSystemError(conn, ret,
                             _("Cannot remove stale PID file for %s"),
                             vm->def->name);
        goto cleanup;
    }

1827 1828 1829 1830 1831
    if (!(pidfile = virFilePid(driver->stateDir, vm->def->name))) {
        virReportSystemError(conn, errno,
                             "%s", _("Failed to build pidfile path."));
        goto cleanup;
    }
D
Daniel P. Berrange 已提交
1832

1833
    vm->def->id = driver->nextvmid++;
1834
    if (qemudBuildCommandLine(conn, driver, vm->def, vm->monitor_chr,
1835
                              qemuCmdFlags, &argv, &progenv,
1836 1837
                              &tapfds, &ntapfds, migrateFrom) < 0)
        goto cleanup;
1838

1839 1840
    tmp = progenv;
    while (*tmp) {
1841
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
1842
            VIR_WARN(_("Unable to write envv to logfile: %s\n"),
1843
                     virStrerror(errno, ebuf, sizeof ebuf));
1844
        if (safewrite(logfile, " ", 1) < 0)
1845
            VIR_WARN(_("Unable to write envv to logfile: %s\n"),
1846
                     virStrerror(errno, ebuf, sizeof ebuf));
1847 1848
        tmp++;
    }
1849 1850
    tmp = argv;
    while (*tmp) {
1851
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
1852
            VIR_WARN(_("Unable to write argv to logfile: %s\n"),
1853
                     virStrerror(errno, ebuf, sizeof ebuf));
1854
        if (safewrite(logfile, " ", 1) < 0)
1855
            VIR_WARN(_("Unable to write argv to logfile: %s\n"),
1856
                     virStrerror(errno, ebuf, sizeof ebuf));
1857 1858
        tmp++;
    }
1859
    if (safewrite(logfile, "\n", 1) < 0)
1860
        VIR_WARN(_("Unable to write argv to logfile: %s\n"),
1861
                 virStrerror(errno, ebuf, sizeof ebuf));
1862

1863
    if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
1864
        VIR_WARN(_("Unable to seek to end of logfile: %s\n"),
1865
                 virStrerror(errno, ebuf, sizeof ebuf));
1866

1867 1868 1869
    for (i = 0 ; i < ntapfds ; i++)
        FD_SET(tapfds[i], &keepfd);

1870
    ret = virExecDaemonize(conn, argv, progenv, &keepfd, &child,
1871
                           stdin_fd, &logfile, &logfile,
1872
                           VIR_EXEC_NONBLOCK | VIR_EXEC_CLEAR_CAPS,
1873 1874 1875
                           qemudSecurityHook, &hookData,
                           pidfile);
    VIR_FREE(pidfile);
G
Guido Günther 已提交
1876 1877 1878

    /* wait for qemu process to to show up */
    if (ret == 0) {
1879
        if (virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) {
1880
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
1881
                             _("Domain %s didn't show up\n"), vm->def->name);
1882
            ret = -1;
G
Guido Günther 已提交
1883
        }
1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894
    } 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;
    }
1895 1896

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

1898
    for (i = 0 ; argv[i] ; i++)
1899 1900
        VIR_FREE(argv[i]);
    VIR_FREE(argv);
1901

1902 1903 1904 1905
    for (i = 0 ; progenv[i] ; i++)
        VIR_FREE(progenv[i]);
    VIR_FREE(progenv);

1906 1907 1908
    if (tapfds) {
        for (i = 0 ; i < ntapfds ; i++) {
            close(tapfds[i]);
1909
        }
1910
        VIR_FREE(tapfds);
1911 1912
    }

1913 1914 1915 1916
    if (ret == -1)
        goto cleanup;

    if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) ||
1917
        (qemuDetectVcpuPIDs(conn, vm) < 0) ||
1918
        (qemudInitCpus(conn, vm, migrateFrom) < 0) ||
1919
        (qemuInitPasswords(driver, vm) < 0) ||
1920
        (qemuMonitorSetBalloon(vm, vm->def->memory) < 0) ||
1921
        (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)) {
1922 1923 1924
        qemudShutdownVMDaemon(conn, driver, vm);
        ret = -1;
        /* No need for 'goto cleanup' now since qemudShutdownVMDaemon does enough */
1925 1926
    }

1927 1928 1929
    if (logfile != -1)
        close(logfile);

1930
    return ret;
1931 1932 1933 1934 1935 1936 1937

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);
    }
1938
    qemuRemoveCgroup(conn, driver, vm);
1939 1940 1941 1942
    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;
1943 1944
    if (logfile != -1)
        close(logfile);
1945 1946
    vm->def->id = -1;
    return -1;
1947 1948 1949
}


1950
static void qemudShutdownVMDaemon(virConnectPtr conn,
1951 1952
                                  struct qemud_driver *driver,
                                  virDomainObjPtr vm) {
D
Daniel P. Berrange 已提交
1953
    int ret;
1954
    int retries = 0;
D
Daniel P. Berrange 已提交
1955

D
Daniel P. Berrange 已提交
1956
    if (!virDomainObjIsActive(vm))
1957
        return;
1958

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

1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976
    if (driver->macFilter) {
        int i;
        virDomainDefPtr def = vm->def;
        for (i = 0 ; i < def->nnets ; i++) {
            virDomainNetDefPtr net = def->nets[i];
            if (net->ifname == NULL)
                continue;
            if ((errno = networkDisallowMacOnPort(conn, driver, net->ifname,
                                                  net->mac))) {
                virReportSystemError(conn, errno,
             _("failed to remove ebtables rule to allow MAC address on  '%s'"),
                                     net->ifname);
            }
        }
    }

G
Guido Günther 已提交
1977 1978
    if (virKillProcess(vm->pid, 0) == 0 &&
        virKillProcess(vm->pid, SIGTERM) < 0)
1979 1980 1981
        virReportSystemError(conn, errno,
                             _("Failed to send SIGTERM to %s (%d)"),
                             vm->def->name, vm->pid);
1982

1983 1984 1985
    if (vm->monitorWatch != -1) {
        virEventRemoveHandle(vm->monitorWatch);
        vm->monitorWatch = -1;
1986
    }
1987 1988 1989 1990 1991

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

1992 1993 1994 1995 1996 1997 1998
    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 已提交
1999 2000
    /* shut it off for sure */
    virKillProcess(vm->pid, SIGKILL);
2001

2002 2003 2004 2005
    /* Reset Security Labels */
    if (driver->securityDriver)
        driver->securityDriver->domainRestoreSecurityLabel(conn, vm);

2006 2007 2008 2009 2010 2011 2012
    /* 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);
    }

2013 2014 2015 2016
    if (qemuDomainSetAllDeviceOwnership(conn, driver, vm->def, 1) < 0)
        VIR_WARN("Failed to restore all device ownership for %s",
                 vm->def->name);

2017
    qemuDomainReAttachHostDevices(conn, driver, vm->def);
2018

2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
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);
    }

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

2031
    vm->pid = -1;
2032
    vm->def->id = -1;
2033
    vm->state = VIR_DOMAIN_SHUTOFF;
2034
    VIR_FREE(vm->vcpupids);
2035
    vm->nvcpupids = 0;
2036 2037

    if (vm->newDef) {
2038
        virDomainDefFree(vm->def);
2039
        vm->def = vm->newDef;
2040
        vm->def->id = -1;
2041 2042 2043 2044 2045
        vm->newDef = NULL;
    }
}


2046
static void
2047
qemudDispatchVMEvent(int watch, int fd, int events, void *opaque) {
2048 2049
    struct qemud_driver *driver = qemu_driver;
    virDomainObjPtr vm = opaque;
2050
    virDomainEventPtr event = NULL;
2051
    int quit = 0, failed = 0;
2052

2053 2054 2055 2056 2057 2058
    /* 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... */
2059
    qemuDriverLock(driver);
2060 2061
    virDomainObjLock(vm);
    qemuDriverUnlock(driver);
2062

2063
    if (vm->monitor != fd || vm->monitorWatch != watch) {
2064 2065
        failed = 1;
    } else {
2066
        if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR))
2067
            quit = 1;
2068
        else {
2069 2070
            VIR_ERROR(_("unhandled fd event %d for %s"),
                      events, vm->def->name);
2071
            failed = 1;
2072
        }
2073 2074
    }

2075
    if (failed || quit) {
2076 2077 2078 2079 2080
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         quit ?
                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN :
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
2081 2082 2083 2084 2085 2086 2087 2088
        qemudShutdownVMDaemon(NULL, driver, vm);
        if (!vm->persistent) {
            virDomainRemoveInactive(&driver->domains,
                                    vm);
            vm = NULL;
        }
    }

2089 2090 2091
    virDomainObjUnlock(vm);
    if (event) {
        qemuDriverLock(driver);
2092
        qemuDomainEventQueue(driver, event);
2093 2094
        qemuDriverUnlock(driver);
    }
2095 2096
}

2097

2098

2099
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
2100
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
2101
                                  int flags ATTRIBUTE_UNUSED) {
2102
    if (conn->uri == NULL) {
2103 2104 2105
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

2106
        conn->uri = xmlParseURI(qemu_driver->privileged ?
2107 2108
                                "qemu:///system" :
                                "qemu:///session");
2109
        if (!conn->uri) {
2110
            virReportOOMError(conn);
2111 2112
            return VIR_DRV_OPEN_ERROR;
        }
2113 2114 2115 2116 2117 2118 2119 2120 2121 2122
    } 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;

2123 2124 2125 2126 2127 2128
        if (qemu_driver == NULL) {
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                             _("qemu state driver is not active"));
            return VIR_DRV_OPEN_ERROR;
        }

2129
        if (qemu_driver->privileged) {
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144
            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;
            }
        }
2145 2146 2147 2148 2149 2150 2151
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
2152
    struct qemud_driver *driver = conn->privateData;
2153 2154

    /* Get rid of callbacks registered for this conn */
2155
    qemuDriverLock(driver);
2156
    virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
2157
    qemuDriverUnlock(driver);
2158 2159 2160 2161 2162 2163

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
2164 2165 2166 2167 2168
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
2169 2170 2171 2172 2173
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
2174 2175 2176
    }
}

2177
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
2178
    return "QEMU";
2179 2180
}

2181 2182 2183 2184 2185

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

    int r, fd;
2186

2187 2188
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
2189 2190
        virReportSystemError(NULL, errno, _("Unable to open %s"), KVM_DEVICE);
        return -1;
2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201
    }

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

    close(fd);
    return maxvcpus;
}


2202
static int qemudGetMaxVCPUs(virConnectPtr conn, const char *type) {
2203 2204 2205
    if (!type)
        return 16;

2206
    if (STRCASEEQ(type, "qemu"))
2207 2208
        return 16;

2209
    if (STRCASEEQ(type, "kvm"))
2210
        return kvmGetMaxVCPUs();
2211

2212
    if (STRCASEEQ(type, "kqemu"))
2213
        return 1;
2214 2215 2216

    qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
                     _("unknown type '%s'"), type);
2217 2218 2219
    return -1;
}

2220

2221
static char *qemudGetCapabilities(virConnectPtr conn) {
2222
    struct qemud_driver *driver = conn->privateData;
2223
    virCapsPtr caps;
2224
    char *xml = NULL;
2225

2226
    qemuDriverLock(driver);
2227
    if ((caps = qemudCapsInit(qemu_driver->caps)) == NULL) {
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238
        virReportOOMError(conn);
        goto cleanup;
    }

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

2239
    virCapabilitiesFree(qemu_driver->caps);
2240 2241 2242
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
2243
        virReportOOMError(conn);
2244 2245

cleanup:
2246
    qemuDriverUnlock(driver);
2247

2248
    return xml;
2249 2250 2251
}


2252
static int qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid, int tid) {
D
Daniel P. Berrange 已提交
2253 2254
    char proc[PATH_MAX];
    FILE *pidinfo;
2255
    unsigned long long usertime, systime;
2256 2257
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
2258

2259 2260 2261 2262 2263 2264
    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 已提交
2265 2266 2267 2268
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
2269
        /*printf("cannot read pid info");*/
D
Daniel P. Berrange 已提交
2270
        /* VM probably shut down, so fake 0 */
2271 2272 2273 2274
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
D
Daniel P. Berrange 已提交
2275 2276 2277
        return 0;
    }

2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
    /* 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) {
2288
        fclose(pidinfo);
2289 2290
        VIR_WARN0("cannot parse process status data");
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
2291 2292 2293 2294 2295 2296 2297 2298
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
2299 2300 2301 2302 2303
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

D
Daniel P. Berrange 已提交
2304

2305 2306
    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
              pid, tid, usertime, systime, cpu);
D
Daniel P. Berrange 已提交
2307 2308 2309 2310 2311 2312 2313

    fclose(pidinfo);

    return 0;
}


2314
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
2315
                                          int id) {
2316 2317 2318 2319
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

2320
    qemuDriverLock(driver);
2321
    vm  = virDomainFindByID(&driver->domains, id);
2322
    qemuDriverUnlock(driver);
2323 2324

    if (!vm) {
2325 2326
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching id %d"), id);
2327
        goto cleanup;
2328 2329
    }

2330
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2331
    if (dom) dom->id = vm->def->id;
2332 2333

cleanup:
2334 2335
    if (vm)
        virDomainObjUnlock(vm);
2336 2337
    return dom;
}
2338

2339
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
2340
                                            const unsigned char *uuid) {
2341 2342 2343
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
2344

2345
    qemuDriverLock(driver);
2346
    vm = virDomainFindByUUID(&driver->domains, uuid);
2347 2348
    qemuDriverUnlock(driver);

2349
    if (!vm) {
2350 2351 2352
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN,
2353
                         _("no domain with matching uuid '%s'"), uuidstr);
2354
        goto cleanup;
2355 2356
    }

2357
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2358
    if (dom) dom->id = vm->def->id;
2359 2360

cleanup:
2361 2362
    if (vm)
        virDomainObjUnlock(vm);
2363 2364
    return dom;
}
2365

2366
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
2367
                                            const char *name) {
2368 2369 2370
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
2371

2372
    qemuDriverLock(driver);
2373
    vm = virDomainFindByName(&driver->domains, name);
2374 2375
    qemuDriverUnlock(driver);

2376
    if (!vm) {
2377 2378
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching name '%s'"), name);
2379
        goto cleanup;
2380 2381
    }

2382
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2383
    if (dom) dom->id = vm->def->id;
2384 2385

cleanup:
2386 2387
    if (vm)
        virDomainObjUnlock(vm);
2388 2389 2390
    return dom;
}

2391
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
2392 2393 2394
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

2395
    qemuDriverLock(driver);
2396
    if (qemudExtractVersion(conn, driver) < 0)
2397
        goto cleanup;
2398

2399
    *version = qemu_driver->qemuVersion;
2400 2401 2402
    ret = 0;

cleanup:
2403
    qemuDriverUnlock(driver);
2404
    return ret;
D
Daniel P. Berrange 已提交
2405 2406
}

2407
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
2408
    struct qemud_driver *driver = conn->privateData;
2409
    int n;
2410

2411
    qemuDriverLock(driver);
2412
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
2413
    qemuDriverUnlock(driver);
2414

2415
    return n;
D
Daniel P. Berrange 已提交
2416
}
2417

2418
static int qemudNumDomains(virConnectPtr conn) {
2419
    struct qemud_driver *driver = conn->privateData;
2420
    int n;
2421

2422
    qemuDriverLock(driver);
2423
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
2424
    qemuDriverUnlock(driver);
2425

2426
    return n;
D
Daniel P. Berrange 已提交
2427
}
2428

2429
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
2430
                                      unsigned int flags ATTRIBUTE_UNUSED) {
2431
    struct qemud_driver *driver = conn->privateData;
2432
    virDomainDefPtr def;
2433
    virDomainObjPtr vm = NULL;
2434
    virDomainPtr dom = NULL;
2435
    virDomainEventPtr event = NULL;
D
Daniel P. Berrange 已提交
2436

2437
    qemuDriverLock(driver);
2438 2439
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE)))
2440
        goto cleanup;
2441

2442 2443 2444
    if (virSecurityDriverVerify(conn, def) < 0)
        goto cleanup;

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

2448
    if (!(vm = virDomainAssignDef(conn,
2449
                                  driver->caps,
2450
                                  &driver->domains,
2451 2452 2453 2454
                                  def)))
        goto cleanup;

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

2456
    if (qemudStartVMDaemon(conn, driver, vm, NULL, -1) < 0) {
2457 2458
        virDomainRemoveInactive(&driver->domains,
                                vm);
2459
        vm = NULL;
2460
        goto cleanup;
D
Daniel P. Berrange 已提交
2461
    }
2462 2463 2464 2465

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

2467
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2468
    if (dom) dom->id = vm->def->id;
2469 2470 2471

cleanup:
    virDomainDefFree(def);
2472 2473
    if (vm)
        virDomainObjUnlock(vm);
2474 2475
    if (event)
        qemuDomainEventQueue(driver, event);
2476
    qemuDriverUnlock(driver);
2477
    return dom;
D
Daniel P. Berrange 已提交
2478 2479 2480
}


2481
static int qemudDomainSuspend(virDomainPtr dom) {
2482 2483 2484
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2485
    virDomainEventPtr event = NULL;
2486

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

D
Daniel P. Berrange 已提交
2490
    if (!vm) {
2491 2492 2493 2494
        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);
2495
        goto cleanup;
D
Daniel P. Berrange 已提交
2496
    }
D
Daniel P. Berrange 已提交
2497
    if (!virDomainObjIsActive(vm)) {
2498
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2499
                         "%s", _("domain is not running"));
2500
        goto cleanup;
D
Daniel P. Berrange 已提交
2501
    }
2502
    if (vm->state != VIR_DOMAIN_PAUSED) {
2503
        if (qemuMonitorStopCPUs(vm) < 0)
2504 2505
            goto cleanup;
        vm->state = VIR_DOMAIN_PAUSED;
2506 2507 2508
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
D
Daniel P. Berrange 已提交
2509
    }
2510
    if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
2511
        goto cleanup;
2512 2513 2514
    ret = 0;

cleanup:
2515 2516
    if (vm)
        virDomainObjUnlock(vm);
2517

2518
    if (event)
2519
        qemuDomainEventQueue(driver, event);
2520
    qemuDriverUnlock(driver);
2521
    return ret;
D
Daniel P. Berrange 已提交
2522 2523 2524
}


2525
static int qemudDomainResume(virDomainPtr dom) {
2526 2527 2528
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2529
    virDomainEventPtr event = NULL;
2530

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

D
Daniel P. Berrange 已提交
2534
    if (!vm) {
2535 2536 2537 2538
        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);
2539
        goto cleanup;
D
Daniel P. Berrange 已提交
2540
    }
D
Daniel P. Berrange 已提交
2541
    if (!virDomainObjIsActive(vm)) {
2542
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2543
                         "%s", _("domain is not running"));
2544
        goto cleanup;
D
Daniel P. Berrange 已提交
2545
    }
2546
    if (vm->state == VIR_DOMAIN_PAUSED) {
2547
        if (qemuMonitorStartCPUs(dom->conn, vm) < 0) {
2548 2549 2550
            if (virGetLastError() == NULL)
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("resume operation failed"));
2551 2552 2553
            goto cleanup;
        }
        vm->state = VIR_DOMAIN_RUNNING;
2554 2555 2556
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
2557
    }
2558
    if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
2559
        goto cleanup;
2560 2561 2562
    ret = 0;

cleanup:
2563 2564
    if (vm)
        virDomainObjUnlock(vm);
2565
    if (event)
2566
        qemuDomainEventQueue(driver, event);
2567
    qemuDriverUnlock(driver);
2568
    return ret;
D
Daniel P. Berrange 已提交
2569 2570 2571
}


2572
static int qemudDomainShutdown(virDomainPtr dom) {
2573 2574 2575
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2576

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

2581
    if (!vm) {
2582 2583 2584 2585
        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);
2586
        goto cleanup;
2587 2588
    }

D
Daniel P. Berrange 已提交
2589
    if (!virDomainObjIsActive(vm)) {
2590 2591 2592 2593 2594
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
        goto cleanup;
    }

2595
    if (qemuMonitorSystemPowerdown(vm) < 0)
2596
        goto cleanup;
2597

2598 2599 2600
    ret = 0;

cleanup:
2601 2602
    if (vm)
        virDomainObjUnlock(vm);
2603
    return ret;
2604 2605 2606
}


2607
static int qemudDomainDestroy(virDomainPtr dom) {
2608 2609 2610
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2611
    virDomainEventPtr event = NULL;
2612

2613
    qemuDriverLock(driver);
2614
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
2615
    if (!vm) {
2616 2617 2618 2619
        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);
2620
        goto cleanup;
D
Daniel P. Berrange 已提交
2621
    }
D
Daniel P. Berrange 已提交
2622
    if (!virDomainObjIsActive(vm)) {
2623
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2624 2625 2626
                         "%s", _("domain is not running"));
        goto cleanup;
    }
2627

2628
    qemudShutdownVMDaemon(dom->conn, driver, vm);
2629 2630 2631
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
2632
    if (!vm->persistent) {
2633 2634
        virDomainRemoveInactive(&driver->domains,
                                vm);
2635 2636
        vm = NULL;
    }
2637 2638 2639
    ret = 0;

cleanup:
2640 2641
    if (vm)
        virDomainObjUnlock(vm);
2642 2643
    if (event)
        qemuDomainEventQueue(driver, event);
2644
    qemuDriverUnlock(driver);
2645
    return ret;
D
Daniel P. Berrange 已提交
2646 2647 2648
}


2649
static char *qemudDomainGetOSType(virDomainPtr dom) {
2650 2651 2652
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
2653

2654
    qemuDriverLock(driver);
2655
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2656
    qemuDriverUnlock(driver);
2657
    if (!vm) {
2658 2659 2660 2661
        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);
2662
        goto cleanup;
2663 2664
    }

2665
    if (!(type = strdup(vm->def->os.type)))
2666
        virReportOOMError(dom->conn);
2667 2668

cleanup:
2669 2670
    if (vm)
        virDomainObjUnlock(vm);
2671 2672 2673
    return type;
}

2674 2675
/* Returns max memory in kb, 0 if error */
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
2676 2677 2678
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
2679

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

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

2692 2693 2694
    ret = vm->def->maxmem;

cleanup:
2695 2696
    if (vm)
        virDomainObjUnlock(vm);
2697
    return ret;
2698 2699 2700
}

static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
2701 2702 2703
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2704

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

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

    if (newmax < vm->def->memory) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
2719
                         "%s", _("cannot set max memory lower than current memory"));
2720
        goto cleanup;;
2721 2722 2723
    }

    vm->def->maxmem = newmax;
2724 2725 2726
    ret = 0;

cleanup:
2727 2728
    if (vm)
        virDomainObjUnlock(vm);
2729
    return ret;
2730 2731
}

2732

2733
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
2734 2735 2736
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2737

2738
    qemuDriverLock(driver);
2739
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2740
    qemuDriverUnlock(driver);
2741
    if (!vm) {
2742 2743
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2744
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
2745
                         _("no domain with matching uuid '%s'"), uuidstr);
2746
        goto cleanup;
2747 2748 2749 2750
    }

    if (newmem > vm->def->maxmem) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
2751
                         "%s", _("cannot set memory higher than max memory"));
2752
        goto cleanup;
2753 2754
    }

D
Daniel P. Berrange 已提交
2755
    if (virDomainObjIsActive(vm)) {
2756 2757 2758 2759 2760 2761
        int r = qemuMonitorSetBalloon(vm, newmem);
        if (r < 0)
            goto cleanup;

        /* Lack of balloon support is a fatal error */
        if (r == 0) {
2762 2763
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                             "%s", _("cannot set memory of an active domain"));
2764
            goto cleanup;
2765
        }
2766 2767 2768
    } else {
        vm->def->memory = newmem;
    }
2769
    ret = 0;
2770 2771

cleanup:
2772 2773
    if (vm)
        virDomainObjUnlock(vm);
2774
    return ret;
2775 2776
}

2777
static int qemudDomainGetInfo(virDomainPtr dom,
2778
                              virDomainInfoPtr info) {
2779 2780 2781
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2782 2783
    int err;
    unsigned long balloon;
2784

2785
    qemuDriverLock(driver);
2786
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2787
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
2788
    if (!vm) {
2789 2790 2791 2792
        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);
2793
        goto cleanup;
D
Daniel P. Berrange 已提交
2794 2795
    }

2796
    info->state = vm->state;
D
Daniel P. Berrange 已提交
2797

D
Daniel P. Berrange 已提交
2798
    if (!virDomainObjIsActive(vm)) {
2799
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2800
    } else {
2801
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
2802
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, ("cannot read cputime for domain"));
2803
            goto cleanup;
D
Daniel P. Berrange 已提交
2804 2805 2806
        }
    }

2807
    info->maxMem = vm->def->maxmem;
2808

D
Daniel P. Berrange 已提交
2809
    if (virDomainObjIsActive(vm)) {
2810
        err = qemuMonitorGetBalloonInfo(vm, &balloon);
2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
        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;
    }

2823
    info->nrVirtCpu = vm->def->vcpus;
2824 2825 2826
    ret = 0;

cleanup:
2827 2828
    if (vm)
        virDomainObjUnlock(vm);
2829
    return ret;
D
Daniel P. Berrange 已提交
2830 2831 2832
}


2833
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
2834 2835 2836
#define QEMUD_SAVE_VERSION 2

enum qemud_save_formats {
2837 2838 2839
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
2840 2841
    /*
     * Deprecated by xz and never used as part of a release
2842
     * QEMUD_SAVE_FORMAT_LZMA
2843 2844
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
2845
    QEMUD_SAVE_FORMAT_LZOP = 4,
2846 2847 2848
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2849 2850

    QEMUD_SAVE_FORMAT_LAST
2851
};
2852

2853 2854 2855 2856 2857
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
2858 2859
              "xz",
              "lzop")
2860

2861 2862 2863 2864 2865
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
    int version;
    int xml_len;
    int was_running;
2866 2867
    int compressed;
    int unused[15];
2868 2869
};

2870
static int qemudDomainSave(virDomainPtr dom,
2871 2872
                           const char *path)
{
2873
    struct qemud_driver *driver = dom->conn->privateData;
2874
    virDomainObjPtr vm = NULL;
2875 2876
    int fd = -1;
    char *xml = NULL;
2877
    struct qemud_save_header header;
2878
    int ret = -1;
2879
    virDomainEventPtr event = NULL;
2880 2881 2882 2883 2884

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

2885
    qemuDriverLock(driver);
2886 2887 2888
    if (driver->saveImageFormat == NULL)
        header.compressed = QEMUD_SAVE_FORMAT_RAW;
    else {
2889 2890 2891 2892 2893 2894
        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"));
2895
            goto cleanup;
2896
        }
2897 2898
    }

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

D
Daniel P. Berrange 已提交
2901
    if (!vm) {
2902 2903 2904 2905
        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);
2906
        goto cleanup;
D
Daniel P. Berrange 已提交
2907
    }
2908

D
Daniel P. Berrange 已提交
2909
    if (!virDomainObjIsActive(vm)) {
2910
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2911
                         "%s", _("domain is not running"));
2912
        goto cleanup;
D
Daniel P. Berrange 已提交
2913
    }
2914 2915 2916 2917

    /* Pause */
    if (vm->state == VIR_DOMAIN_RUNNING) {
        header.was_running = 1;
2918
        if (qemuMonitorStopCPUs(vm) < 0)
2919
            goto cleanup;
2920
        vm->state = VIR_DOMAIN_PAUSED;
2921 2922 2923
    }

    /* Get XML for the domain */
2924
    xml = virDomainDefFormat(dom->conn, vm->def, VIR_DOMAIN_XML_SECURE);
2925 2926
    if (!xml) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
2927
                         "%s", _("failed to get domain xml"));
2928
        goto cleanup;
2929 2930 2931 2932 2933 2934
    }
    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,
2935
                         _("failed to create '%s'"), path);
2936
        goto cleanup;
2937 2938 2939 2940
    }

    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
2941
                         "%s", _("failed to write save header"));
2942
        goto cleanup;
2943 2944 2945 2946
    }

    if (safewrite(fd, xml, header.xml_len) != header.xml_len) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
2947
                         "%s", _("failed to write xml"));
2948
        goto cleanup;
2949 2950
    }

2951
    if (close(fd) < 0) {
2952 2953 2954
        virReportSystemError(dom->conn, errno,
                             _("unable to save file %s"),
                             path);
2955 2956 2957
        goto cleanup;
    }
    fd = -1;
2958

2959 2960
    if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = { "cat", NULL };
2961
        ret = qemuMonitorMigrateToCommand(vm, 0, args, path);
2962
    } else {
2963
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
2964 2965 2966 2967 2968
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
2969
        ret = qemuMonitorMigrateToCommand(vm, 0, args, path);
2970 2971
    }

2972
    if (ret < 0)
2973
        goto cleanup;
2974

2975 2976
    /* Shut it down */
    qemudShutdownVMDaemon(dom->conn, driver, vm);
2977 2978 2979
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
2980
    if (!vm->persistent) {
2981 2982
        virDomainRemoveInactive(&driver->domains,
                                vm);
2983 2984
        vm = NULL;
    }
2985 2986 2987 2988 2989 2990 2991

cleanup:
    if (fd != -1)
        close(fd);
    VIR_FREE(xml);
    if (ret != 0)
        unlink(path);
2992 2993
    if (vm)
        virDomainObjUnlock(vm);
2994 2995
    if (event)
        qemuDomainEventQueue(driver, event);
2996
    qemuDriverUnlock(driver);
2997
    return ret;
D
Daniel P. Berrange 已提交
2998 2999 3000
}


P
Paolo Bonzini 已提交
3001 3002 3003 3004 3005 3006 3007
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;
3008 3009 3010 3011
    const char *args[] = {
        "cat",
        NULL,
    };
P
Paolo Bonzini 已提交
3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024

    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 已提交
3025
    if (!virDomainObjIsActive(vm)) {
P
Paolo Bonzini 已提交
3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037
        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) {
3038
        if (qemuMonitorStopCPUs(vm) < 0)
P
Paolo Bonzini 已提交
3039 3040 3041 3042
            goto cleanup;
        paused = 1;
    }

3043
    ret = qemuMonitorMigrateToCommand(vm, 0, args, path);
P
Paolo Bonzini 已提交
3044 3045 3046 3047 3048 3049 3050
    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) {
3051
        if (qemuMonitorStartCPUs(dom->conn, vm) < 0) {
3052 3053 3054
            if (virGetLastError() == NULL)
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3055 3056 3057 3058 3059 3060 3061 3062
        }
    }
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


3063
static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
3064 3065
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3066
    int max;
3067
    int ret = -1;
3068
    const char *type;
3069

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

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

D
Daniel P. Berrange 已提交
3082
    if (virDomainObjIsActive(vm)) {
3083
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID, "%s",
3084
                         _("cannot change vcpu count of an active domain"));
3085
        goto cleanup;
3086 3087
    }

3088 3089 3090 3091 3092 3093 3094 3095
    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) {
3096 3097
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                         _("could not determine max vcpus for the domain"));
3098
        goto cleanup;
3099 3100 3101 3102 3103 3104
    }

    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);
3105
        goto cleanup;
3106 3107 3108
    }

    vm->def->vcpus = nvcpus;
3109 3110 3111
    ret = 0;

cleanup:
3112 3113
    if (vm)
        virDomainObjUnlock(vm);
3114
    return ret;
3115 3116
}

3117 3118 3119 3120 3121 3122 3123

#if HAVE_SCHED_GETAFFINITY
static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
3124 3125
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3126
    cpu_set_t mask;
3127
    int i, maxcpu, hostcpus;
3128
    virNodeInfo nodeinfo;
3129
    int ret = -1;
3130

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

3135 3136 3137 3138 3139 3140 3141 3142
    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 已提交
3143
    if (!virDomainObjIsActive(vm)) {
3144
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3145
                         "%s",_("cannot pin vcpus on an inactive domain"));
3146
        goto cleanup;
3147 3148 3149 3150 3151 3152
    }

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

3156
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
3157
        goto cleanup;
3158

3159
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
3160
    maxcpu = maplen * 8;
3161 3162
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
3163 3164 3165

    CPU_ZERO(&mask);
    for (i = 0 ; i < maxcpu ; i++) {
3166
        if (VIR_CPU_USABLE(cpumap, maplen, 0, i))
3167 3168 3169 3170 3171
            CPU_SET(i, &mask);
    }

    if (vm->vcpupids != NULL) {
        if (sched_setaffinity(vm->vcpupids[vcpu], sizeof(mask), &mask) < 0) {
3172 3173
            virReportSystemError(dom->conn, errno, "%s",
                                 _("cannot set affinity"));
3174
            goto cleanup;
3175 3176 3177 3178
        }
    } else {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         "%s", _("cpu affinity is not supported"));
3179
        goto cleanup;
3180
    }
3181
    ret = 0;
3182

3183
cleanup:
3184 3185
    if (vm)
        virDomainObjUnlock(vm);
3186
    return ret;
3187 3188 3189 3190 3191 3192 3193 3194
}

static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
3195 3196
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3197
    virNodeInfo nodeinfo;
3198
    int i, v, maxcpu, hostcpus;
3199
    int ret = -1;
3200

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

3205 3206 3207 3208 3209 3210 3211 3212
    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 已提交
3213
    if (!virDomainObjIsActive(vm)) {
3214
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3215 3216
                         "%s",
                         _("cannot list vcpu pinning for an inactive domain"));
3217
        goto cleanup;
3218 3219
    }

3220
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
3221
        goto cleanup;
3222

3223
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
3224
    maxcpu = maplen * 8;
3225 3226
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
3227 3228 3229 3230 3231

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

3232 3233 3234 3235 3236 3237
    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;
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247

                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;
                }
3248
            }
3249 3250
        }

3251 3252 3253 3254 3255 3256 3257 3258 3259
        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) {
3260 3261
                        virReportSystemError(dom->conn, errno, "%s",
                                             _("cannot get affinity"));
3262 3263 3264 3265 3266 3267
                        goto cleanup;
                    }

                    for (i = 0 ; i < maxcpu ; i++)
                        if (CPU_ISSET(i, &mask))
                            VIR_USE_CPU(cpumap, i);
3268
                }
3269 3270 3271 3272
            } else {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                                 "%s", _("cpu affinity is not available"));
                goto cleanup;
3273 3274 3275
            }
        }
    }
3276
    ret = maxinfo;
3277

3278
cleanup:
3279 3280
    if (vm)
        virDomainObjUnlock(vm);
3281
    return ret;
3282 3283 3284 3285
}
#endif /* HAVE_SCHED_GETAFFINITY */


3286
static int qemudDomainGetMaxVcpus(virDomainPtr dom) {
3287 3288
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3289
    const char *type;
3290
    int ret = -1;
3291

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

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

3304
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
3305 3306 3307
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("unknown virt type in domain definition '%d'"),
                         vm->def->virtType);
3308
        goto cleanup;
3309 3310
    }

3311
    ret = qemudGetMaxVCPUs(dom->conn, type);
3312

3313
cleanup:
3314 3315
    if (vm)
        virDomainObjUnlock(vm);
3316 3317 3318
    return ret;
}

3319 3320 3321 3322 3323 3324 3325 3326 3327 3328
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);

3329 3330
    memset(seclabel, 0, sizeof(*seclabel));

3331 3332 3333
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3334
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359
                         _("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 已提交
3360
    if (virDomainObjIsActive(vm)) {
3361 3362 3363
        if (driver->securityDriver && driver->securityDriver->domainGetSecurityLabel) {
            if (driver->securityDriver->domainGetSecurityLabel(dom->conn, vm, seclabel) == -1) {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
3364
                                 "%s", _("Failed to get security label"));
3365 3366 3367 3368 3369 3370 3371 3372 3373 3374
                goto cleanup;
            }
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
3375
    qemuDriverUnlock(driver);
3376 3377 3378
    return ret;
}

3379 3380
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
3381 3382 3383
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
3384
    int ret = 0;
3385

3386 3387
    qemuDriverLock(driver);
    if (!driver->securityDriver) {
3388
        memset(secmodel, 0, sizeof (*secmodel));
3389 3390
        goto cleanup;
    }
3391

3392 3393 3394 3395 3396
    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);
3397 3398
        ret = -1;
        goto cleanup;
3399 3400 3401 3402 3403 3404 3405 3406
    }
    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);
3407 3408
        ret = -1;
        goto cleanup;
3409 3410
    }
    strcpy(secmodel->doi, p);
3411 3412 3413 3414

cleanup:
    qemuDriverUnlock(driver);
    return ret;
3415 3416 3417
}

/* TODO: check seclabel restore */
3418
static int qemudDomainRestore(virConnectPtr conn,
3419 3420 3421
                              const char *path) {
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
3422
    virDomainObjPtr vm = NULL;
3423 3424 3425
    int fd = -1;
    int ret = -1;
    char *xml = NULL;
3426
    struct qemud_save_header header;
3427
    virDomainEventPtr event = NULL;
3428 3429 3430
    int intermediatefd = -1;
    pid_t intermediate_pid = -1;
    int childstat;
3431

3432
    qemuDriverLock(driver);
3433 3434 3435
    /* Verify the header and read the XML */
    if ((fd = open(path, O_RDONLY)) < 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3436
                         "%s", _("cannot read domain image"));
3437
        goto cleanup;
3438 3439 3440 3441
    }

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3442
                         "%s", _("failed to read qemu header"));
3443
        goto cleanup;
3444 3445 3446 3447
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3448
                         "%s", _("image magic is incorrect"));
3449
        goto cleanup;
3450 3451 3452 3453
    }

    if (header.version > QEMUD_SAVE_VERSION) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3454
                         _("image version is not supported (%d > %d)"),
3455
                         header.version, QEMUD_SAVE_VERSION);
3456
        goto cleanup;
3457 3458
    }

3459
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
3460
        virReportOOMError(conn);
3461
        goto cleanup;
3462 3463 3464 3465
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3466
                         "%s", _("failed to read XML"));
3467
        goto cleanup;
3468 3469 3470
    }

    /* Create a domain from this XML */
3471 3472
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE))) {
3473
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3474
                         "%s", _("failed to parse XML"));
3475
        goto cleanup;
3476 3477
    }

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

3481
    if (!(vm = virDomainAssignDef(conn,
3482
                                  driver->caps,
3483 3484
                                  &driver->domains,
                                  def))) {
3485
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3486
                         "%s", _("failed to assign new VM"));
3487
        goto cleanup;
3488
    }
3489
    def = NULL;
3490

3491 3492
    if (header.version == 2) {
        const char *intermediate_argv[3] = { NULL, "-dc", NULL };
3493 3494
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
        if (prog == NULL) {
3495
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3496
                             _("Invalid compressed save format %d"),
3497 3498 3499
                             header.compressed);
            goto cleanup;
        }
3500

3501
        if (header.compressed != QEMUD_SAVE_FORMAT_RAW) {
3502
            intermediate_argv[0] = prog;
3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513
            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;
            }
        }
    }
3514
    /* Set the migration source and start it up. */
3515
    ret = qemudStartVMDaemon(conn, driver, vm, "stdio", fd);
3516 3517 3518 3519 3520 3521 3522
    if (intermediate_pid != -1) {
        /* Wait for intermediate process to exit */
        while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
               errno == EINTR);
    }
    if (intermediatefd != -1)
        close(intermediatefd);
3523
    close(fd);
3524
    fd = -1;
3525
    if (ret < 0) {
3526
        if (!vm->persistent) {
3527 3528
            virDomainRemoveInactive(&driver->domains,
                                    vm);
3529 3530
            vm = NULL;
        }
3531
        goto cleanup;
3532 3533
    }

3534 3535 3536
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
3537

3538 3539
    /* If it was running before, resume it now. */
    if (header.was_running) {
3540
        if (qemuMonitorStartCPUs(conn, vm) < 0) {
3541 3542 3543
            if (virGetLastError() == NULL)
                qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("failed to resume domain"));
3544
            goto cleanup;
3545 3546
        }
        vm->state = VIR_DOMAIN_RUNNING;
3547
        virDomainSaveStatus(conn, driver->stateDir, vm);
3548
    }
3549
    ret = 0;
3550

3551 3552 3553 3554 3555
cleanup:
    virDomainDefFree(def);
    VIR_FREE(xml);
    if (fd != -1)
        close(fd);
3556 3557
    if (vm)
        virDomainObjUnlock(vm);
3558 3559
    if (event)
        qemuDomainEventQueue(driver, event);
3560
    qemuDriverUnlock(driver);
3561
    return ret;
D
Daniel P. Berrange 已提交
3562 3563 3564
}


3565
static char *qemudDomainDumpXML(virDomainPtr dom,
3566
                                int flags) {
3567 3568 3569
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
3570 3571
    unsigned long balloon;
    int err;
3572

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

D
Daniel P. Berrange 已提交
3577
    if (!vm) {
3578 3579 3580 3581
        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);
3582
        goto cleanup;
D
Daniel P. Berrange 已提交
3583 3584
    }

3585
    /* Refresh current memory based on balloon info */
D
Daniel P. Berrange 已提交
3586
    if (virDomainObjIsActive(vm)) {
3587 3588 3589 3590 3591 3592 3593
        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 */
    }
3594

3595 3596 3597 3598 3599 3600
    ret = virDomainDefFormat(dom->conn,
                             (flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
                             vm->newDef : vm->def,
                             flags);

cleanup:
3601 3602
    if (vm)
        virDomainObjUnlock(vm);
3603
    return ret;
D
Daniel P. Berrange 已提交
3604 3605 3606
}


3607 3608 3609 3610
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
                                     unsigned int flags ATTRIBUTE_UNUSED) {
3611
    struct qemud_driver *driver = conn->privateData;
3612 3613 3614 3615 3616 3617 3618 3619 3620
    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;
    }

3621
    qemuDriverLock(driver);
3622
    def = qemuParseCommandLineString(conn, driver->caps, config);
3623
    qemuDriverUnlock(driver);
3624 3625 3626 3627 3628 3629 3630 3631 3632 3633
    if (!def)
        goto cleanup;

    xml = virDomainDefFormat(conn, def, VIR_DOMAIN_XML_INACTIVE);

cleanup:
    virDomainDefFree(def);
    return xml;
}

3634 3635 3636 3637 3638 3639
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;
3640
    virDomainChrDef monitor_chr;
3641 3642 3643 3644 3645 3646 3647 3648 3649 3650
    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;

3651 3652
    qemuDriverLock(driver);

3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718
    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;
    }

3719 3720
    if (qemuPrepareMonitorChr(conn, driver, &monitor_chr, def->name) < 0)
        goto cleanup;
3721 3722

    if (qemudBuildCommandLine(conn, driver, def,
3723
                              &monitor_chr, qemuCmdFlags,
3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748
                              &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:
3749
    qemuDriverUnlock(driver);
3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762
    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;
}


3763
static int qemudListDefinedDomains(virConnectPtr conn,
3764
                            char **const names, int nnames) {
3765
    struct qemud_driver *driver = conn->privateData;
3766
    int n;
3767

3768
    qemuDriverLock(driver);
3769
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
3770
    qemuDriverUnlock(driver);
3771
    return n;
D
Daniel P. Berrange 已提交
3772 3773
}

3774
static int qemudNumDefinedDomains(virConnectPtr conn) {
3775
    struct qemud_driver *driver = conn->privateData;
3776
    int n;
3777

3778
    qemuDriverLock(driver);
3779
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
3780
    qemuDriverUnlock(driver);
3781

3782
    return n;
D
Daniel P. Berrange 已提交
3783 3784 3785
}


3786
static int qemudDomainStart(virDomainPtr dom) {
3787 3788 3789
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
3790
    virDomainEventPtr event = NULL;
3791

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

3795
    if (!vm) {
3796 3797 3798 3799
        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);
3800
        goto cleanup;
3801 3802
    }

3803
    ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL, -1);
3804
    if (ret != -1)
3805 3806 3807
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
3808 3809

cleanup:
3810 3811
    if (vm)
        virDomainObjUnlock(vm);
3812
    if (event)
3813
        qemuDomainEventQueue(driver, event);
3814
    qemuDriverUnlock(driver);
3815
    return ret;
D
Daniel P. Berrange 已提交
3816 3817
}

3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832
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;

3833
        if (STRNEQ(def->os.machine, machine->name))
3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846
            continue;

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

        break;
    }

    return 0;
}

3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861
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;

3862
        if (STRNEQ(def->os.machine, machines[i]->name))
3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

3875 3876
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
3877 3878 3879 3880 3881 3882
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
3883
        virCapsGuestDomainInfoPtr info;
3884 3885 3886
        int j;

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

3889 3890 3891 3892 3893 3894 3895 3896 3897
            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;
3898 3899
        }

3900 3901 3902 3903
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
3904 3905 3906 3907
                return -1;
            goto out;
        }
    }
3908 3909 3910 3911

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

3912 3913 3914 3915 3916 3917 3918
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
3919

3920
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
3921
    struct qemud_driver *driver = conn->privateData;
3922
    virDomainDefPtr def;
3923
    virDomainObjPtr vm = NULL;
3924
    virDomainPtr dom = NULL;
3925
    virDomainEventPtr event = NULL;
3926
    int dupVM;
3927

3928
    qemuDriverLock(driver);
3929 3930
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE)))
3931
        goto cleanup;
3932

3933 3934 3935
    if (virSecurityDriverVerify(conn, def) < 0)
        goto cleanup;

3936 3937
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
3938

3939
    if (qemudCanonicalizeMachine(driver, def) < 0)
3940 3941
        goto cleanup;

3942
    if (!(vm = virDomainAssignDef(conn,
3943
                                  driver->caps,
3944 3945
                                  &driver->domains,
                                  def))) {
3946
        goto cleanup;
3947
    }
3948
    def = NULL;
3949
    vm->persistent = 1;
3950

3951 3952
    if (virDomainSaveConfig(conn,
                            driver->configDir,
3953
                            vm->newDef ? vm->newDef : vm->def) < 0) {
3954 3955
        virDomainRemoveInactive(&driver->domains,
                                vm);
3956
        vm = NULL;
3957
        goto cleanup;
3958 3959
    }

3960 3961
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
3962
                                     !dupVM ?
3963 3964
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
3965

3966
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
3967
    if (dom) dom->id = vm->def->id;
3968 3969

cleanup:
3970
    virDomainDefFree(def);
3971 3972
    if (vm)
        virDomainObjUnlock(vm);
3973 3974
    if (event)
        qemuDomainEventQueue(driver, event);
3975
    qemuDriverUnlock(driver);
3976
    return dom;
D
Daniel P. Berrange 已提交
3977 3978
}

3979
static int qemudDomainUndefine(virDomainPtr dom) {
3980 3981
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3982
    virDomainEventPtr event = NULL;
3983
    int ret = -1;
D
Daniel P. Berrange 已提交
3984

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

D
Daniel P. Berrange 已提交
3988
    if (!vm) {
3989 3990 3991 3992
        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);
3993
        goto cleanup;
D
Daniel P. Berrange 已提交
3994 3995
    }

D
Daniel P. Berrange 已提交
3996
    if (virDomainObjIsActive(vm)) {
3997
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3998
                         "%s", _("cannot delete active domain"));
3999
        goto cleanup;
D
Daniel P. Berrange 已提交
4000 4001
    }

4002 4003 4004
    if (!vm->persistent) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot undefine transient domain"));
4005
        goto cleanup;
4006 4007 4008
    }

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

4011 4012 4013
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
4014

4015 4016
    virDomainRemoveInactive(&driver->domains,
                            vm);
4017
    vm = NULL;
4018
    ret = 0;
D
Daniel P. Berrange 已提交
4019

4020
cleanup:
4021 4022
    if (vm)
        virDomainObjUnlock(vm);
4023 4024
    if (event)
        qemuDomainEventQueue(driver, event);
4025
    qemuDriverUnlock(driver);
4026
    return ret;
D
Daniel P. Berrange 已提交
4027 4028
}

4029
/* Return the disks name for use in monitor commands */
4030
static char *qemudDiskDeviceName(const virConnectPtr conn,
4031
                                 const virDomainDiskDefPtr disk) {
4032 4033 4034 4035 4036 4037

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

    if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0) {
4038
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
4039 4040 4041 4042 4043 4044 4045
                         _("cannot convert disk '%s' to bus/device index"),
                         disk->dst);
        return NULL;
    }

    switch (disk->bus) {
        case VIR_DOMAIN_DISK_BUS_IDE:
4046
            if (disk->device== VIR_DOMAIN_DISK_DEVICE_DISK)
4047
                ret = virAsprintf(&devname, "ide%d-hd%d", busid, devid);
4048
            else
4049
                ret = virAsprintf(&devname, "ide%d-cd%d", busid, devid);
4050 4051
            break;
        case VIR_DOMAIN_DISK_BUS_SCSI:
4052
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
4053
                ret = virAsprintf(&devname, "scsi%d-hd%d", busid, devid);
4054
            else
4055
                ret = virAsprintf(&devname, "scsi%d-cd%d", busid, devid);
4056 4057
            break;
        case VIR_DOMAIN_DISK_BUS_FDC:
4058
            ret = virAsprintf(&devname, "floppy%d", devid);
4059 4060
            break;
        case VIR_DOMAIN_DISK_BUS_VIRTIO:
4061
            ret = virAsprintf(&devname, "virtio%d", devid);
4062 4063
            break;
        default:
4064
            qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
4065 4066 4067 4068 4069 4070
                             _("Unsupported disk name mapping for bus '%s'"),
                             virDomainDiskBusTypeToString(disk->bus));
            return NULL;
    }

    if (ret == -1) {
4071
        virReportOOMError(conn);
4072 4073 4074 4075 4076 4077
        return NULL;
    }

    return devname;
}

4078 4079
static int qemudDomainChangeEjectableMedia(virConnectPtr conn,
                                           virDomainObjPtr vm,
4080 4081
                                           virDomainDeviceDefPtr dev,
                                           unsigned int qemuCmdFlags)
4082
{
4083
    virDomainDiskDefPtr origdisk = NULL, newdisk;
4084
    char *devname = NULL;
4085
    int i;
4086
    int ret;
4087

4088
    origdisk = NULL;
4089
    newdisk = dev->data.disk;
4090 4091 4092 4093
    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];
4094
            break;
4095
        }
4096 4097 4098
    }

    if (!origdisk) {
4099
        qemudReportError(conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
4100 4101 4102 4103 4104 4105 4106
                         _("No device with bus '%s' and target '%s'"),
                         virDomainDiskBusTypeToString(newdisk->bus),
                         newdisk->dst);
        return -1;
    }

    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
4107
        if (!(devname = qemudDiskDeviceName(conn, newdisk)))
4108 4109 4110 4111 4112 4113 4114 4115 4116
            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 {
4117
            qemudReportError(conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
4118 4119 4120 4121 4122 4123 4124 4125
                             _("Emulator version does not support removable "
                               "media for device '%s' and target '%s'"),
                               virDomainDiskDeviceTypeToString(newdisk->device),
                               newdisk->dst);
            return -1;
        }

        if (!devname) {
4126
            virReportOOMError(conn);
4127 4128 4129
            return -1;
        }
    }
4130

4131
    if (newdisk->src) {
4132 4133 4134
        ret = qemuMonitorChangeMedia(vm, devname, newdisk->src);
    } else {
        ret = qemuMonitorEjectMedia(vm, devname);
4135
    }
4136

4137 4138 4139 4140 4141
    if (ret == 0) {
        VIR_FREE(origdisk->src);
        origdisk->src = newdisk->src;
        newdisk->src = NULL;
        origdisk->type = newdisk->type;
4142
    }
4143

4144
    return ret;
4145 4146
}

4147

4148 4149 4150
static int qemudDomainAttachPciDiskDevice(virConnectPtr conn,
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
4151
{
4152
    int i;
4153 4154 4155 4156
    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)) {
4157
            qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
4158 4159 4160 4161 4162 4163
                           _("target %s already exists"), dev->data.disk->dst);
            return -1;
        }
    }

    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
4164
        virReportOOMError(conn);
4165 4166 4167
        return -1;
    }

4168 4169 4170 4171 4172 4173
    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)
4174
        return -1;
4175

4176
    virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
4177 4178 4179

    return 0;
}
4180

4181 4182 4183
static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn,
                                                 virDomainObjPtr vm,
                                                 virDomainDeviceDefPtr dev)
4184
{
4185
    int i;
4186

4187 4188
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
4189
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4190 4191 4192 4193 4194
                           _("target %s already exists"), dev->data.disk->dst);
            return -1;
        }
    }

4195 4196 4197
    if (!dev->data.disk->src) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("disk source path is missing"));
4198 4199 4200
        return -1;
    }

4201
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
4202
        virReportOOMError(conn);
4203 4204 4205
        return -1;
    }

4206
    if (qemuMonitorAddUSBDisk(vm, dev->data.disk->src) < 0)
4207
        return -1;
4208

4209
    virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
4210

4211 4212 4213
    return 0;
}

M
Mark McLoughlin 已提交
4214
static int qemudDomainAttachNetDevice(virConnectPtr conn,
4215
                                      struct qemud_driver *driver,
M
Mark McLoughlin 已提交
4216 4217 4218 4219 4220
                                      virDomainObjPtr vm,
                                      virDomainDeviceDefPtr dev,
                                      unsigned int qemuCmdFlags)
{
    virDomainNetDefPtr net = dev->data.net;
4221
    char *tapfd_name = NULL;
4222
    int i, tapfd = -1;
4223
    char *nicstr = NULL;
4224
    char *netstr = NULL;
4225
    int ret = -1;
M
Mark McLoughlin 已提交
4226 4227 4228 4229 4230 4231 4232 4233 4234

    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) {
4235 4236 4237 4238 4239 4240 4241 4242 4243 4244
        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 已提交
4245 4246
    }

4247 4248
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
        goto no_memory;
M
Mark McLoughlin 已提交
4249 4250

    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) &&
4251 4252
        qemuAssignNetNames(vm->def, net) < 0)
        goto no_memory;
M
Mark McLoughlin 已提交
4253 4254 4255 4256 4257 4258 4259 4260 4261

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

4262 4263 4264 4265
    if (tapfd != -1) {
        if (virAsprintf(&tapfd_name, "fd-%s", net->hostnet_name) < 0)
            goto no_memory;

4266
        if (qemuMonitorSendFileHandle(vm, tapfd_name, tapfd) < 0)
4267 4268 4269
            goto cleanup;
    }

4270 4271
    if (qemuBuildHostNetStr(conn, net, ' ',
                            net->vlan, tapfd_name, &netstr) < 0)
4272
        goto try_tapfd_close;
M
Mark McLoughlin 已提交
4273

4274
    if (qemuMonitorAddHostNetwork(vm, netstr) < 0)
4275
        goto try_tapfd_close;
M
Mark McLoughlin 已提交
4276

4277 4278 4279
    if (tapfd != -1)
        close(tapfd);
    tapfd = -1;
M
Mark McLoughlin 已提交
4280

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

4284 4285 4286 4287
    if (qemuMonitorAddPCINetwork(vm, nicstr,
                                 &net->pci_addr.domain,
                                 &net->pci_addr.bus,
                                 &net->pci_addr.slot) < 0)
4288 4289
        goto try_remove;

4290
    ret = 0;
M
Mark McLoughlin 已提交
4291 4292 4293

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

4294 4295 4296 4297 4298 4299
cleanup:
    VIR_FREE(nicstr);
    VIR_FREE(netstr);
    VIR_FREE(tapfd_name);
    if (tapfd != -1)
        close(tapfd);
4300

4301
    return ret;
4302

4303 4304
try_remove:
    if (!net->hostnet_name || net->vlan == 0)
4305
        VIR_WARN0(_("Unable to remove network backend\n"));
4306 4307 4308
    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);
4309
    goto cleanup;
4310

4311
try_tapfd_close:
4312 4313 4314 4315
    if (tapfd_name &&
        qemuMonitorCloseFileHandle(vm, tapfd_name) < 0)
        VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_name);

4316 4317
    goto cleanup;

4318 4319
no_memory:
    virReportOOMError(conn);
4320
    goto cleanup;
M
Mark McLoughlin 已提交
4321 4322
}

4323
static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
4324
                                          struct qemud_driver *driver,
4325 4326 4327 4328
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
4329
    pciDevice *pci;
4330 4331 4332 4333 4334 4335

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

4336 4337 4338 4339 4340 4341 4342
    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;
4343

4344
    if ((hostdev->managed && pciDettachDevice(conn, pci) < 0) ||
4345 4346 4347 4348 4349 4350
        pciResetDevice(conn, pci, driver->activePciHostdevs) < 0) {
        pciFreeDevice(conn, pci);
        return -1;
    }

    if (pciDeviceListAdd(conn, driver->activePciHostdevs, pci) < 0) {
4351
        pciFreeDevice(conn, pci);
4352
        return -1;
4353 4354
    }

4355 4356 4357 4358 4359 4360 4361 4362
    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)
4363
        goto error;
4364 4365 4366 4367

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

    return 0;
4368 4369 4370 4371 4372

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

    return -1;
4373 4374
}

M
Mark McLoughlin 已提交
4375 4376 4377
static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
4378 4379 4380
{
    int ret;

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

4386
    if (dev->data.hostdev->source.subsys.u.usb.vendor) {
4387 4388 4389
        ret = qemuMonitorAddUSBDeviceMatch(vm,
                                           dev->data.hostdev->source.subsys.u.usb.vendor,
                                           dev->data.hostdev->source.subsys.u.usb.product);
4390
    } else {
4391 4392 4393
        ret = qemuMonitorAddUSBDeviceExact(vm,
                                           dev->data.hostdev->source.subsys.u.usb.bus,
                                           dev->data.hostdev->source.subsys.u.usb.device);
4394 4395
    }

4396 4397
    if (ret != -1)
        vm->def->hostdevs[vm->def->nhostdevs++] = dev->data.hostdev;
4398

4399
    return ret;
4400 4401
}

M
Mark McLoughlin 已提交
4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417
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;
4418 4419 4420
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
        return -1;
M
Mark McLoughlin 已提交
4421 4422

    switch (hostdev->source.subsys.type) {
4423
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
4424
        return qemudDomainAttachHostPciDevice(conn, driver, vm, dev);
M
Mark McLoughlin 已提交
4425 4426 4427 4428 4429 4430 4431 4432 4433 4434
    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;
    }
}

4435 4436
static int qemudDomainAttachDevice(virDomainPtr dom,
                                   const char *xml) {
4437 4438 4439
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
4440
    unsigned int qemuCmdFlags;
4441
    virCgroupPtr cgroup = NULL;
4442
    int ret = -1;
4443

4444
    qemuDriverLock(driver);
4445
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4446
    if (!vm) {
4447 4448 4449 4450
        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);
4451
        goto cleanup;
4452 4453
    }

D
Daniel P. Berrange 已提交
4454
    if (!virDomainObjIsActive(vm)) {
4455
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
4456
                         "%s", _("cannot attach device on inactive domain"));
4457
        goto cleanup;
4458 4459
    }

4460 4461
    dev = virDomainDeviceDefParse(dom->conn, driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
4462 4463 4464
    if (dev == NULL)
        goto cleanup;

4465 4466 4467 4468
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
        goto cleanup;
4469

4470
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
4471
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488
            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;
            }
        }

4489
        switch (dev->data.disk->device) {
4490 4491
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
4492 4493
            if (driver->securityDriver)
                driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
4494 4495 4496 4497

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

4498
            ret = qemudDomainChangeEjectableMedia(dom->conn, vm, dev, qemuCmdFlags);
4499
            break;
4500

4501
        case VIR_DOMAIN_DISK_DEVICE_DISK:
4502 4503
            if (driver->securityDriver)
                driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
4504 4505 4506 4507

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

4508
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
4509
                ret = qemudDomainAttachUsbMassstorageDevice(dom->conn, vm, dev);
4510 4511
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                       dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
4512
                ret = qemudDomainAttachPciDiskDevice(dom->conn, vm, dev);
4513 4514 4515 4516
            } else {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                                 _("disk bus '%s' cannot be hotplugged."),
                                 virDomainDiskBusTypeToString(dev->data.disk->bus));
4517
                /* fallthrough */
4518 4519
            }
            break;
4520

4521 4522
        default:
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
4523 4524
                             _("disk device type '%s' cannot be hotplugged"),
                             virDomainDiskDeviceTypeToString(dev->data.disk->device));
4525 4526 4527 4528 4529
            /* Fallthrough */
        }
        if (ret != 0) {
            virCgroupDenyDevicePath(cgroup,
                                    dev->data.disk->src);
4530
        }
M
Mark McLoughlin 已提交
4531
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
4532
        ret = qemudDomainAttachNetDevice(dom->conn, driver, vm, dev, qemuCmdFlags);
M
Mark McLoughlin 已提交
4533 4534
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        ret = qemudDomainAttachHostDevice(dom->conn, driver, vm, dev);
4535
    } else {
4536
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
4537 4538
                         _("device type '%s' cannot be attached"),
                         virDomainDeviceTypeToString(dev->type));
4539
        goto cleanup;
4540 4541
    }

4542
    if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
4543 4544
        ret = -1;

4545
cleanup:
4546 4547 4548
    if (cgroup)
        virCgroupFree(&cgroup);

4549
    if (ret < 0 && dev != NULL) {
4550 4551
        if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
            VIR_WARN0("Fail to restore disk device ownership");
G
Guido Günther 已提交
4552
        virDomainDeviceDefFree(dev);
4553
    }
4554 4555
    if (vm)
        virDomainObjUnlock(vm);
4556
    qemuDriverUnlock(driver);
4557 4558 4559
    return ret;
}

4560 4561
static int qemudDomainDetachPciDiskDevice(virConnectPtr conn,
                                          virDomainObjPtr vm, virDomainDeviceDefPtr dev)
4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573
{
    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) {
4574
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4575
                         _("disk %s not found"), dev->data.disk->dst);
4576
        goto cleanup;
4577 4578
    }

4579
    if (!virDiskHasValidPciAddr(detach)) {
4580
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4581 4582
                         _("disk %s cannot be detached - no PCI address for device"),
                           detach->dst);
4583
        goto cleanup;
4584 4585
    }

4586 4587 4588 4589
    if (qemuMonitorRemovePCIDevice(vm,
                                   detach->pci_addr.domain,
                                   detach->pci_addr.bus,
                                   detach->pci_addr.slot) < 0)
4590
        goto cleanup;
4591

4592 4593 4594 4595 4596 4597 4598 4599 4600 4601
    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 {
4602
        VIR_FREE(vm->def->disks);
4603
        vm->def->ndisks = 0;
4604
    }
4605
    virDomainDiskDefFree(detach);
4606

4607
    ret = 0;
4608 4609

cleanup:
4610 4611 4612
    return ret;
}

4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644
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;
    }

4645 4646 4647 4648
    if (qemuMonitorRemovePCIDevice(vm,
                                   detach->pci_addr.domain,
                                   detach->pci_addr.bus,
                                   detach->pci_addr.slot) < 0)
4649 4650
        goto cleanup;

4651
    if (qemuMonitorRemoveHostNetwork(vm, detach->vlan, detach->hostnet_name) < 0)
4652 4653
        goto cleanup;

4654 4655 4656 4657 4658 4659 4660 4661 4662 4663
    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 {
4664
        VIR_FREE(vm->def->nets);
4665
        vm->def->nnets = 0;
4666
    }
4667
    virDomainNetDefFree(detach);
4668

4669 4670 4671 4672 4673 4674
    ret = 0;

cleanup:
    return ret;
}

4675
static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
4676
                                          struct qemud_driver *driver,
4677 4678 4679
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
{
4680
    virDomainHostdevDefPtr detach = NULL;
4681
    int i, ret;
4682
    pciDevice *pci;
4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714

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

4715 4716 4717 4718
    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)
4719 4720 4721 4722
        return -1;

    ret = 0;

4723 4724 4725 4726 4727 4728 4729 4730
    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 {
4731 4732
        pciDeviceListDel(conn, driver->activePciHostdevs, pci);
        if (pciResetDevice(conn, pci, driver->activePciHostdevs) < 0)
4733 4734
            ret = -1;
        if (detach->managed && pciReAttachDevice(conn, pci) < 0)
4735
            ret = -1;
4736
        pciFreeDevice(conn, pci);
4737 4738
    }

4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750
    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;
4751
    }
4752
    virDomainHostdevDefFree(detach);
4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773

    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:
4774
        ret = qemudDomainDetachHostPciDevice(conn, driver, vm, dev);
4775
        break;
4776 4777 4778 4779 4780 4781 4782
    default:
        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         _("hostdev subsys type '%s' not supported"),
                         virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
        return -1;
    }

4783 4784 4785 4786
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
        VIR_WARN0("Failed to restore device labelling");

4787
    if (qemuDomainSetDeviceOwnership(conn, driver, dev, 1) < 0)
4788
        VIR_WARN0("Failed to restore device ownership");
4789 4790 4791 4792

    return ret;
}

4793 4794
static int qemudDomainDetachDevice(virDomainPtr dom,
                                   const char *xml) {
4795 4796 4797 4798
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;
4799

4800
    qemuDriverLock(driver);
4801
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4802
    if (!vm) {
4803 4804 4805 4806
        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);
4807
        goto cleanup;
4808 4809
    }

D
Daniel P. Berrange 已提交
4810
    if (!virDomainObjIsActive(vm)) {
4811
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
G
Guido Günther 已提交
4812
                         "%s", _("cannot detach device on inactive domain"));
4813
        goto cleanup;
4814 4815
    }

4816 4817
    dev = virDomainDeviceDefParse(dom->conn, driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
4818 4819 4820
    if (dev == NULL)
        goto cleanup;

4821 4822 4823 4824

    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 ||
4825
         dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)) {
4826
        ret = qemudDomainDetachPciDiskDevice(dom->conn, vm, dev);
4827
        if (driver->securityDriver)
4828
            driver->securityDriver->domainRestoreSecurityImageLabel(dom->conn, vm, dev->data.disk);
4829 4830
        if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
            VIR_WARN0("Fail to restore disk device ownership");
4831 4832
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
        ret = qemudDomainDetachNetDevice(dom->conn, vm, dev);
4833 4834
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        ret = qemudDomainDetachHostDevice(dom->conn, driver, vm, dev);
4835
    } else
4836 4837 4838
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         "%s", _("only SCSI or virtio disk device can be detached dynamically"));

4839
    if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
4840 4841
        ret = -1;

4842 4843
cleanup:
    virDomainDeviceDefFree(dev);
4844 4845
    if (vm)
        virDomainObjUnlock(vm);
4846
    qemuDriverUnlock(driver);
4847 4848 4849
    return ret;
}

4850
static int qemudDomainGetAutostart(virDomainPtr dom,
4851
                                   int *autostart) {
4852 4853 4854
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4855

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

4860
    if (!vm) {
4861 4862 4863 4864
        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);
4865
        goto cleanup;
4866 4867 4868
    }

    *autostart = vm->autostart;
4869
    ret = 0;
4870

4871
cleanup:
4872 4873
    if (vm)
        virDomainObjUnlock(vm);
4874
    return ret;
4875 4876
}

4877
static int qemudDomainSetAutostart(virDomainPtr dom,
4878
                                   int autostart) {
4879 4880
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4881 4882
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
4883

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

4887
    if (!vm) {
4888 4889 4890 4891
        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);
4892
        goto cleanup;
4893 4894
    }

4895 4896 4897
    if (!vm->persistent) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot set autostart for transient domain"));
4898
        goto cleanup;
4899 4900
    }

4901 4902
    autostart = (autostart != 0);

4903 4904 4905 4906 4907
    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;
4908

4909 4910
        if (autostart) {
            int err;
4911

4912
            if ((err = virFileMakePath(driver->autostartDir))) {
4913 4914 4915
                virReportSystemError(dom->conn, err,
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
4916 4917
                goto cleanup;
            }
4918

4919
            if (symlink(configFile, autostartLink) < 0) {
4920 4921 4922
                virReportSystemError(dom->conn, errno,
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
4923 4924 4925 4926
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4927 4928 4929
                virReportSystemError(dom->conn, errno,
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
4930 4931
                goto cleanup;
            }
4932 4933
        }

4934
        vm->autostart = autostart;
4935
    }
4936
    ret = 0;
4937

4938 4939 4940
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4941 4942
    if (vm)
        virDomainObjUnlock(vm);
4943
    qemuDriverUnlock(driver);
4944
    return ret;
4945 4946
}

4947 4948 4949 4950 4951

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

4954
    qemuDriverLock(driver);
4955
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
4956 4957
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
4958
        goto cleanup;
4959 4960 4961 4962 4963 4964 4965 4966
    }

    if (nparams)
        *nparams = 1;

    ret = strdup("posix");
    if (!ret)
        virReportOOMError(dom->conn);
4967 4968 4969

cleanup:
    qemuDriverUnlock(driver);
4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982
    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;

4983
    qemuDriverLock(driver);
4984
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
4985 4986
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
4987
        goto cleanup;
4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009
    }

    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 已提交
5010
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, "%s",
5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032
                                 _("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);
5033
    qemuDriverUnlock(driver);
5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047
    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;

5048
    qemuDriverLock(driver);
5049
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5050 5051
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
5052
        goto cleanup;
5053 5054 5055 5056 5057
    }

    if ((*nparams) != 1) {
        qemudReportError(dom->conn, domain, NULL, VIR_ERR_INVALID_ARG,
                         "%s", _("Invalid parameter count"));
5058
        goto cleanup;
5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082
    }

    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 已提交
5083 5084 5085 5086 5087
    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;
    }
5088 5089 5090 5091 5092 5093 5094

    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
5095
    qemuDriverUnlock(driver);
5096 5097 5098 5099
    return ret;
}


5100 5101 5102 5103 5104 5105 5106 5107 5108
/* 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)
{
5109
    struct qemud_driver *driver = dom->conn->privateData;
5110 5111
    const char *qemu_dev_name = NULL;
    int i, ret = -1;
5112
    virDomainObjPtr vm;
5113
    virDomainDiskDefPtr disk = NULL;
5114

5115
    qemuDriverLock(driver);
5116
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5117
    qemuDriverUnlock(driver);
5118
    if (!vm) {
5119 5120 5121 5122
        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);
5123
        goto cleanup;
5124
    }
D
Daniel P. Berrange 已提交
5125
    if (!virDomainObjIsActive (vm)) {
5126
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
5127
                          "%s", _("domain is not running"));
5128
        goto cleanup;
5129 5130
    }

5131 5132 5133 5134 5135 5136 5137 5138
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
5139 5140
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                          _("invalid path: %s"), path);
5141
        goto cleanup;
5142 5143
    }

5144
    qemu_dev_name = qemudDiskDeviceName(dom->conn, disk);
5145
    if (!qemu_dev_name)
5146
        goto cleanup;
5147

5148 5149 5150 5151 5152 5153
    if (qemuMonitorGetBlockStatsInfo(vm, qemu_dev_name,
                                     &stats->rd_req,
                                     &stats->rd_bytes,
                                     &stats->wr_req,
                                     &stats->wr_bytes,
                                     &stats->errs) < 0)
5154
        goto cleanup;
5155

5156
    ret = 0;
5157

5158
cleanup:
5159
    VIR_FREE(qemu_dev_name);
5160 5161
    if (vm)
        virDomainObjUnlock(vm);
5162
    return ret;
5163 5164
}

5165
#ifdef __linux__
5166 5167 5168 5169 5170
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
5171 5172
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5173
    int i;
5174
    int ret = -1;
5175

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

5180
    if (!vm) {
5181 5182 5183 5184
        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);
5185
        goto cleanup;
5186 5187
    }

D
Daniel P. Berrange 已提交
5188
    if (!virDomainObjIsActive(vm)) {
5189
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
5190
                         "%s", _("domain is not running"));
5191
        goto cleanup;
5192 5193 5194
    }

    /* Check the path is one of the domain's network interfaces. */
5195 5196
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
5197 5198 5199 5200
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
5201 5202
    }

5203 5204 5205 5206 5207
    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);
5208

5209
cleanup:
5210 5211
    if (vm)
        virDomainObjUnlock(vm);
5212 5213
    return ret;
}
5214
#else
5215 5216 5217 5218
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
5219 5220 5221 5222
    qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                      "%s", __FUNCTION__);
    return -1;
}
5223
#endif
5224

5225 5226 5227 5228 5229 5230 5231
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
5232 5233 5234
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
5235

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

5240
    if (!vm) {
5241 5242 5243 5244
        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);
5245
        goto cleanup;
5246 5247 5248 5249
    }

    if (!path || path[0] == '\0') {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
5250
                         "%s", _("NULL or empty path"));
5251
        goto cleanup;
5252 5253 5254
    }

    /* Check the path belongs to this domain. */
5255 5256
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
5257 5258 5259 5260
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
5261 5262
    }

5263 5264 5265 5266 5267
    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) {
5268 5269
            virReportSystemError (dom->conn, errno,
                                  _("%s: failed to open"), path);
5270 5271
            goto cleanup;
        }
5272

5273 5274 5275 5276 5277 5278
        /* 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) {
5279 5280
            virReportSystemError (dom->conn, errno,
                                  _("%s: failed to seek or read"), path);
5281 5282 5283 5284 5285 5286 5287
            goto cleanup;
        }

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

5290 5291 5292
cleanup:
    if (fd >= 0)
        close (fd);
5293 5294
    if (vm)
        virDomainObjUnlock(vm);
5295 5296 5297
    return ret;
}

R
Richard W.M. Jones 已提交
5298 5299 5300 5301 5302 5303
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
5304 5305
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5306
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
5307 5308
    int fd = -1, ret = -1;

5309
    qemuDriverLock(driver);
5310
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5311
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
5312 5313

    if (!vm) {
5314 5315 5316 5317
        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);
5318 5319 5320
        goto cleanup;
    }

5321
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
5322
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
5323
                     "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
5324
        goto cleanup;
R
Richard W.M. Jones 已提交
5325 5326
    }

D
Daniel P. Berrange 已提交
5327
    if (!virDomainObjIsActive(vm)) {
5328
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
R
Richard W.M. Jones 已提交
5329
                         "%s", _("domain is not running"));
5330
        goto cleanup;
R
Richard W.M. Jones 已提交
5331 5332
    }

5333 5334 5335 5336 5337
    if (virAsprintf(&tmp, driver->cacheDir,  "/qemu.mem.XXXXXX") < 0) {
        virReportOOMError(dom->conn);
        goto cleanup;
    }

R
Richard W.M. Jones 已提交
5338 5339
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
5340 5341
        virReportSystemError (dom->conn, errno,
                              _("mkstemp(\"%s\") failed"), tmp);
5342
        goto cleanup;
R
Richard W.M. Jones 已提交
5343 5344
    }

5345 5346 5347 5348 5349 5350
    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 已提交
5351 5352 5353 5354
    }

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
5355 5356 5357
        virReportSystemError (dom->conn, errno,
                              _("failed to read temporary file "
                                "created with template %s"), tmp);
5358
        goto cleanup;
R
Richard W.M. Jones 已提交
5359 5360 5361
    }

    ret = 0;
5362 5363

cleanup:
5364
    VIR_FREE(tmp);
R
Richard W.M. Jones 已提交
5365 5366
    if (fd >= 0) close (fd);
    unlink (tmp);
5367 5368
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
5369 5370 5371
    return ret;
}

5372

5373 5374
static int
qemudDomainEventRegister (virConnectPtr conn,
5375
                          virConnectDomainEventCallback callback,
5376 5377
                          void *opaque,
                          virFreeCallback freecb)
5378
{
5379 5380 5381
    struct qemud_driver *driver = conn->privateData;
    int ret;

5382
    qemuDriverLock(driver);
5383 5384
    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
                                        callback, opaque, freecb);
5385
    qemuDriverUnlock(driver);
5386

5387
    return ret;
5388 5389 5390 5391
}

static int
qemudDomainEventDeregister (virConnectPtr conn,
5392
                            virConnectDomainEventCallback callback)
5393
{
5394 5395 5396
    struct qemud_driver *driver = conn->privateData;
    int ret;

5397
    qemuDriverLock(driver);
5398 5399 5400 5401 5402 5403
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
                                               callback);
5404
    qemuDriverUnlock(driver);
5405

5406
    return ret;
5407 5408
}

5409 5410 5411 5412 5413
static void qemuDomainEventDispatchFunc(virConnectPtr conn,
                                        virDomainEventPtr event,
                                        virConnectDomainEventCallback cb,
                                        void *cbopaque,
                                        void *opaque)
5414
{
5415
    struct qemud_driver *driver = opaque;
5416

5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460
    /* 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);
5461 5462
}

D
Daniel Veillard 已提交
5463 5464
/* Migration support. */

C
Chris Lalancette 已提交
5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637
/* 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;

5638 5639
    if (VIR_ALLOC(qemust) < 0) {
        virReportOOMError(st->conn);
C
Chris Lalancette 已提交
5640
        return NULL;
5641
    }
C
Chris Lalancette 已提交
5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 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 5741 5742 5743 5744 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

    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;

5789 5790
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
C
Chris Lalancette 已提交
5791 5792

    if (!(vm = virDomainAssignDef(dconn,
5793
                                  driver->caps,
C
Chris Lalancette 已提交
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
                                  &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 已提交
5877 5878 5879 5880 5881 5882 5883 5884 5885 5886
/* 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 已提交
5887
                            unsigned long flags,
D
Daniel Veillard 已提交
5888 5889 5890 5891 5892
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
    static int port = 0;
5893 5894
    struct qemud_driver *driver = dconn->privateData;
    virDomainDefPtr def = NULL;
D
Daniel Veillard 已提交
5895 5896
    virDomainObjPtr vm = NULL;
    int this_port;
5897
    char *hostname;
D
Daniel Veillard 已提交
5898 5899
    char migrateFrom [64];
    const char *p;
5900
    virDomainEventPtr event = NULL;
5901
    int ret = -1;
5902
    int internalret;
5903 5904

    *uri_out = NULL;
D
Daniel Veillard 已提交
5905

5906
    qemuDriverLock(driver);
C
Chris Lalancette 已提交
5907 5908 5909 5910 5911 5912 5913 5914 5915
    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 已提交
5916 5917 5918
    if (!dom_xml) {
        qemudReportError (dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                          "%s", _("no domain XML passed"));
5919
        goto cleanup;
D
Daniel Veillard 已提交
5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936
    }

    /* 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 */
5937
        if ((hostname = virGetHostname(dconn)) == NULL)
5938
            goto cleanup;
D
Daniel Veillard 已提交
5939

5940 5941 5942 5943 5944
        /* 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 已提交
5945
        /* Caller frees */
5946 5947 5948
        internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
        VIR_FREE(hostname);
        if (internalret < 0) {
5949
            virReportOOMError (dconn);
5950
            goto cleanup;
D
Daniel Veillard 已提交
5951 5952 5953 5954 5955 5956
        }
    } 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.
         */
5957
        if (!STRPREFIX (uri_in, "tcp:")) {
D
Daniel Veillard 已提交
5958
            qemudReportError (dconn, NULL, NULL, VIR_ERR_INVALID_ARG,
5959
                  "%s", _("only tcp URIs are supported for KVM/QEMU migrations"));
5960
            goto cleanup;
D
Daniel Veillard 已提交
5961 5962 5963 5964
        }

        /* Get the port number. */
        p = strrchr (uri_in, ':');
5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984
        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 已提交
5985 5986 5987
        }
    }

5988 5989 5990
    if (uri_out && *uri_out)
        VIR_DEBUG("Generated uri_out=%s", *uri_out);

D
Daniel Veillard 已提交
5991
    /* Parse the domain XML. */
5992 5993
    if (!(def = virDomainDefParseString(dconn, driver->caps, dom_xml,
                                        VIR_DOMAIN_XML_INACTIVE))) {
D
Daniel Veillard 已提交
5994 5995
        qemudReportError (dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                          "%s", _("failed to parse XML"));
5996
        goto cleanup;
D
Daniel Veillard 已提交
5997 5998 5999 6000 6001
    }

    /* Target domain name, maybe renamed. */
    dname = dname ? dname : def->name;

6002 6003
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
6004 6005

    if (!(vm = virDomainAssignDef(dconn,
6006
                                  driver->caps,
D
Daniel Veillard 已提交
6007 6008 6009 6010
                                  &driver->domains,
                                  def))) {
        qemudReportError (dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                          "%s", _("failed to assign new VM"));
6011
        goto cleanup;
D
Daniel Veillard 已提交
6012
    }
6013
    def = NULL;
D
Daniel Veillard 已提交
6014 6015 6016 6017 6018 6019 6020 6021

    /* 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);
6022
    if (qemudStartVMDaemon (dconn, driver, vm, migrateFrom, -1) < 0) {
6023 6024 6025
        /* Note that we don't set an error here because qemudStartVMDaemon
         * should have already done that.
         */
6026
        if (!vm->persistent) {
D
Daniel Veillard 已提交
6027
            virDomainRemoveInactive(&driver->domains, vm);
6028 6029
            vm = NULL;
        }
6030
        goto cleanup;
D
Daniel Veillard 已提交
6031
    }
6032 6033 6034 6035

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_MIGRATED);
6036
    ret = 0;
D
Daniel Veillard 已提交
6037

6038 6039 6040 6041 6042
cleanup:
    virDomainDefFree(def);
    if (ret != 0) {
        VIR_FREE(*uri_out);
    }
6043 6044
    if (vm)
        virDomainObjUnlock(vm);
6045 6046
    if (event)
        qemuDomainEventQueue(driver, event);
6047
    qemuDriverUnlock(driver);
6048
    return ret;
C
Chris Lalancette 已提交
6049 6050 6051

}

6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063

/* 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;
6064
    xmlURIPtr uribits = NULL;
6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 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
    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;
}


6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138
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 已提交
6139
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s",
6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151
                             _("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 已提交
6152
static int doTunnelMigrate(virDomainPtr dom,
6153
                           virConnectPtr dconn,
C
Chris Lalancette 已提交
6154
                           virDomainObjPtr vm,
6155
                           const char *dom_xml,
C
Chris Lalancette 已提交
6156 6157 6158 6159 6160 6161
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
6162 6163
    int client_sock = -1;
    int qemu_sock = -1;
C
Chris Lalancette 已提交
6164 6165
    struct sockaddr_un sa_qemu, sa_client;
    socklen_t addrlen;
6166
    virDomainPtr ddomain = NULL;
C
Chris Lalancette 已提交
6167
    int retval = -1;
6168
    virStreamPtr st = NULL;
C
Chris Lalancette 已提交
6169 6170 6171 6172 6173 6174
    char *unixfile = NULL;
    int internalret;
    unsigned int qemuCmdFlags;
    int status;
    unsigned long long transferred, remaining, total;

6175 6176 6177 6178 6179 6180 6181 6182
    /*
     * 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 已提交
6183 6184
     */

6185

6186
    /* Stage 1. setup local support infrastructure */
C
Chris Lalancette 已提交
6187 6188 6189 6190

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
                    driver->stateDir, vm->def->name) < 0) {
        virReportOOMError(dom->conn);
6191
        goto cleanup;
C
Chris Lalancette 已提交
6192 6193 6194 6195 6196 6197
    }

    qemu_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (qemu_sock < 0) {
        virReportSystemError(dom->conn, errno, "%s",
                             _("cannot open tunnelled migration socket"));
6198
        goto cleanup;
C
Chris Lalancette 已提交
6199 6200 6201 6202 6203 6204 6205 6206
    }
    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);
6207
        goto cleanup;
C
Chris Lalancette 已提交
6208 6209 6210 6211 6212 6213
    }
    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);
6214
        goto cleanup;
C
Chris Lalancette 已提交
6215 6216 6217 6218 6219
    }
    if (listen(qemu_sock, 1) < 0) {
        virReportSystemError(dom->conn, errno,
                             _("Cannot listen on unix socket '%s' for tunnelled migration"),
                             unixfile);
6220
        goto cleanup;
C
Chris Lalancette 已提交
6221 6222 6223 6224 6225 6226 6227
    }

    /* 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);
6228 6229 6230 6231 6232 6233 6234 6235
        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 已提交
6236
    }
6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257


    /* 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 已提交
6258 6259 6260 6261 6262
    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");
6263 6264
    } else {
        internalret = -1;
C
Chris Lalancette 已提交
6265 6266 6267 6268
    }
    if (internalret < 0) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("tunnelled migration monitor command failed"));
6269
        goto finish;
C
Chris Lalancette 已提交
6270 6271
    }

6272 6273 6274
    /* From this point onwards we *must* call cancel to abort the
     * migration on source if anything goes wrong */

C
Chris Lalancette 已提交
6275 6276 6277 6278 6279 6280 6281
    /* 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) {
6282
        goto cancel;
C
Chris Lalancette 已提交
6283 6284 6285 6286 6287
    }

    if (status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s",_("migrate failed"));
6288
        goto cancel;
C
Chris Lalancette 已提交
6289 6290 6291 6292 6293 6294 6295 6296
    }

    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"));
6297
        goto cancel;
C
Chris Lalancette 已提交
6298 6299
    }

6300
    retval = doTunnelSendAll(dom, st, client_sock);
6301

6302
cancel:
C
Chris Lalancette 已提交
6303 6304 6305
    if (retval != 0)
        qemuMonitorMigrateCancel(vm);

6306
finish:
C
Chris Lalancette 已提交
6307 6308 6309
    dname = dname ? dname : dom->name;
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri, flags, retval);
6310 6311 6312 6313 6314 6315 6316

cleanup:
    if (client_sock != -1)
        close(client_sock);
    if (qemu_sock != -1)
        close(qemu_sock);

C
Chris Lalancette 已提交
6317 6318 6319
    if (ddomain)
        virUnrefDomain(ddomain);

6320 6321 6322 6323
    if (unixfile) {
        unlink(unixfile);
        VIR_FREE(unixfile);
    }
C
Chris Lalancette 已提交
6324

6325 6326 6327
    if (st)
        /* don't call virStreamFree(), because that resets any pending errors */
        virUnrefStream(st);
6328 6329 6330 6331
    return retval;
}


6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360
/* 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 已提交
6361
        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382
                         _("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;
}


6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404
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,
6405
                                  VIR_DRV_FEATURE_MIGRATION_P2P)) {
6406
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s",
6407
                         _("Destination libvirt does not support peer-to-peer migration protocol"));
6408 6409 6410 6411 6412 6413 6414 6415 6416 6417
        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;
    }

6418 6419 6420 6421
    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);
6422 6423 6424

cleanup:
    VIR_FREE(dom_xml);
C
Chris Lalancette 已提交
6425 6426 6427
    /* don't call virConnectClose(), because that resets any pending errors */
    virUnrefConnect(dconn);

6428
    return ret;
D
Daniel Veillard 已提交
6429 6430
}

6431

D
Daniel Veillard 已提交
6432 6433 6434 6435 6436 6437
/* 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,
6438
                           unsigned long flags,
6439
                           const char *dname,
D
Daniel Veillard 已提交
6440 6441
                           unsigned long resource)
{
6442 6443
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6444
    virDomainEventPtr event = NULL;
6445
    int ret = -1;
6446
    int paused = 0;
D
Daniel Veillard 已提交
6447

6448
    qemuDriverLock(driver);
6449
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
6450
    if (!vm) {
6451 6452 6453 6454
        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);
6455
        goto cleanup;
D
Daniel Veillard 已提交
6456 6457
    }

D
Daniel P. Berrange 已提交
6458
    if (!virDomainObjIsActive(vm)) {
6459
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
D
Daniel Veillard 已提交
6460
                          "%s", _("domain is not running"));
6461
        goto cleanup;
D
Daniel Veillard 已提交
6462 6463
    }

6464 6465
    if (!(flags & VIR_MIGRATE_LIVE)) {
        /* Pause domain for non-live migration */
6466
        if (qemuMonitorStopCPUs(vm) < 0)
6467 6468
            goto cleanup;
        paused = 1;
6469

6470 6471 6472 6473 6474 6475
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
        if (event)
            qemuDomainEventQueue(driver, event);
        event = NULL;
6476 6477
    }

6478
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
6479
        if (doPeer2PeerMigrate(dom, vm, uri, flags, dname, resource) < 0)
6480
            /* doPeer2PeerMigrate already set the error, so just get out */
C
Chris Lalancette 已提交
6481
            goto cleanup;
6482 6483 6484
    } else {
        if (doNativeMigrate(dom, vm, uri, flags, dname, resource) < 0)
            goto cleanup;
6485 6486
    }

D
Daniel Veillard 已提交
6487 6488
    /* Clean up the source domain. */
    qemudShutdownVMDaemon (dom->conn, driver, vm);
6489
    paused = 0;
6490 6491 6492 6493

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
C
Chris Lalancette 已提交
6494 6495
    if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
        virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm);
D
Daniel Veillard 已提交
6496
        virDomainRemoveInactive(&driver->domains, vm);
6497 6498
        vm = NULL;
    }
6499
    ret = 0;
D
Daniel Veillard 已提交
6500

6501
cleanup:
6502 6503
    if (paused) {
        /* we got here through some sort of failure; start the domain again */
6504
        if (qemuMonitorStartCPUs(dom->conn, vm) < 0) {
6505 6506 6507 6508
            /* 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
             */
6509 6510
            VIR_ERROR(_("Failed to resume guest %s after failure\n"),
                      vm->def->name);
6511 6512 6513 6514 6515 6516 6517
        }

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }

6518 6519
    if (vm)
        virDomainObjUnlock(vm);
6520 6521
    if (event)
        qemuDomainEventQueue(driver, event);
6522
    qemuDriverUnlock(driver);
6523
    return ret;
D
Daniel Veillard 已提交
6524 6525 6526 6527 6528 6529 6530 6531 6532
}

/* 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 已提交
6533
                           unsigned long flags,
D
Daniel Veillard 已提交
6534 6535
                           int retcode)
{
6536 6537 6538
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
6539
    virDomainEventPtr event = NULL;
C
Chris Lalancette 已提交
6540
    int newVM = 1;
D
Daniel Veillard 已提交
6541

6542
    qemuDriverLock(driver);
6543
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
6544
    if (!vm) {
6545 6546
        qemudReportError (dconn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                          _("no domain with matching name '%s'"), dname);
6547
        goto cleanup;
D
Daniel Veillard 已提交
6548 6549 6550 6551 6552 6553
    }

    /* 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 已提交
6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581
        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 已提交
6582
        dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
6583 6584 6585 6586 6587

        /* 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
         */
6588
        if (qemuMonitorStartCPUs(dconn, vm) < 0) {
6589 6590 6591
            if (virGetLastError() == NULL)
                qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("resume operation failed"));
6592 6593 6594
            goto cleanup;
        }

D
Daniel Veillard 已提交
6595
        vm->state = VIR_DOMAIN_RUNNING;
6596 6597 6598
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
D
Daniel Veillard 已提交
6599
        virDomainSaveStatus(dconn, driver->stateDir, vm);
D
Daniel Veillard 已提交
6600 6601
    } else {
        qemudShutdownVMDaemon (dconn, driver, vm);
6602 6603 6604
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
6605
        if (!vm->persistent) {
D
Daniel Veillard 已提交
6606
            virDomainRemoveInactive(&driver->domains, vm);
6607 6608
            vm = NULL;
        }
D
Daniel Veillard 已提交
6609
    }
6610 6611

cleanup:
6612 6613
    if (vm)
        virDomainObjUnlock(vm);
6614 6615
    if (event)
        qemuDomainEventQueue(driver, event);
6616
    qemuDriverUnlock(driver);
6617
    return dom;
D
Daniel Veillard 已提交
6618 6619
}

6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635
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;

6636
    def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
6637 6638 6639 6640 6641 6642 6643 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 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714
    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)
{
6715
    struct qemud_driver *driver = dev->conn->privateData;
6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726
    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;

6727 6728 6729
    qemuDriverLock(driver);

    if (pciResetDevice(dev->conn, pci, driver->activePciHostdevs) < 0)
6730 6731 6732 6733
        goto out;

    ret = 0;
out:
6734
    qemuDriverUnlock(driver);
6735 6736 6737 6738
    pciFreeDevice(dev->conn, pci);
    return ret;
}

6739 6740 6741 6742 6743
static virDriver qemuDriver = {
    VIR_DRV_QEMU,
    "QEMU",
    qemudOpen, /* open */
    qemudClose, /* close */
D
Daniel Veillard 已提交
6744
    qemudSupportsFeature, /* supports_feature */
6745 6746
    qemudGetType, /* type */
    qemudGetVersion, /* version */
6747
    virGetHostname, /* getHostname */
6748
    qemudGetMaxVCPUs, /* getMaxVcpus */
6749
    nodeGetInfo, /* nodeGetInfo */
6750 6751 6752
    qemudGetCapabilities, /* getCapabilities */
    qemudListDomains, /* listDomains */
    qemudNumDomains, /* numOfDomains */
6753
    qemudDomainCreate, /* domainCreateXML */
6754 6755 6756 6757 6758
    qemudDomainLookupByID, /* domainLookupByID */
    qemudDomainLookupByUUID, /* domainLookupByUUID */
    qemudDomainLookupByName, /* domainLookupByName */
    qemudDomainSuspend, /* domainSuspend */
    qemudDomainResume, /* domainResume */
6759
    qemudDomainShutdown, /* domainShutdown */
6760 6761 6762
    NULL, /* domainReboot */
    qemudDomainDestroy, /* domainDestroy */
    qemudDomainGetOSType, /* domainGetOSType */
6763 6764 6765
    qemudDomainGetMaxMemory, /* domainGetMaxMemory */
    qemudDomainSetMaxMemory, /* domainSetMaxMemory */
    qemudDomainSetMemory, /* domainSetMemory */
6766 6767 6768
    qemudDomainGetInfo, /* domainGetInfo */
    qemudDomainSave, /* domainSave */
    qemudDomainRestore, /* domainRestore */
P
Paolo Bonzini 已提交
6769
    qemudDomainCoreDump, /* domainCoreDump */
6770
    qemudDomainSetVcpus, /* domainSetVcpus */
6771 6772 6773 6774
#if HAVE_SCHED_GETAFFINITY
    qemudDomainPinVcpu, /* domainPinVcpu */
    qemudDomainGetVcpus, /* domainGetVcpus */
#else
6775 6776
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
6777
#endif
6778
    qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
6779 6780
    qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
    qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
6781
    qemudDomainDumpXML, /* domainDumpXML */
6782
    qemuDomainXMLFromNative, /* domainXmlFromNative */
6783
    qemuDomainXMLToNative, /* domainXMLToNative */
6784 6785
    qemudListDefinedDomains, /* listDefinedDomains */
    qemudNumDefinedDomains, /* numOfDefinedDomains */
6786 6787 6788
    qemudDomainStart, /* domainCreate */
    qemudDomainDefine, /* domainDefineXML */
    qemudDomainUndefine, /* domainUndefine */
6789
    qemudDomainAttachDevice, /* domainAttachDevice */
6790
    qemudDomainDetachDevice, /* domainDetachDevice */
6791 6792
    qemudDomainGetAutostart, /* domainGetAutostart */
    qemudDomainSetAutostart, /* domainSetAutostart */
6793 6794 6795
    qemuGetSchedulerType, /* domainGetSchedulerType */
    qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
    qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
6796 6797
    NULL, /* domainMigratePrepare (v1) */
    qemudDomainMigratePerform, /* domainMigratePerform */
6798
    NULL, /* domainMigrateFinish */
6799
    qemudDomainBlockStats, /* domainBlockStats */
6800
    qemudDomainInterfaceStats, /* domainInterfaceStats */
6801
    qemudDomainBlockPeek, /* domainBlockPeek */
R
Richard W.M. Jones 已提交
6802
    qemudDomainMemoryPeek, /* domainMemoryPeek */
6803 6804
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
6805 6806
    qemudDomainEventRegister, /* domainEventRegister */
    qemudDomainEventDeregister, /* domainEventDeregister */
D
Daniel Veillard 已提交
6807 6808
    qemudDomainMigratePrepare2, /* domainMigratePrepare2 */
    qemudDomainMigrateFinish2, /* domainMigrateFinish2 */
6809 6810 6811
    qemudNodeDeviceDettach, /* nodeDeviceDettach */
    qemudNodeDeviceReAttach, /* nodeDeviceReAttach */
    qemudNodeDeviceReset, /* nodeDeviceReset */
C
Chris Lalancette 已提交
6812
    qemudDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
6813 6814 6815
};


6816
static virStateDriver qemuStateDriver = {
6817
    .name = "QEMU",
6818 6819 6820 6821
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
6822
};
6823

6824
int qemuRegister(void) {
6825 6826 6827 6828
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
    return 0;
}