qemu_driver.c 231.7 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
#include <sys/types.h>
#include <sys/poll.h>
28
#include <sys/time.h>
D
Daniel P. Berrange 已提交
29 30 31
#include <dirent.h>
#include <limits.h>
#include <string.h>
32
#include <stdbool.h>
D
Daniel P. Berrange 已提交
33 34 35 36 37 38
#include <stdio.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
39
#include <sys/utsname.h>
40 41 42 43
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
44 45
#include <pwd.h>
#include <stdio.h>
46
#include <sys/wait.h>
47
#include <sys/ioctl.h>
48
#include <sys/un.h>
D
Daniel P. Berrange 已提交
49

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

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

79

80 81
#define VIR_FROM_THIS VIR_FROM_QEMU

82 83 84
typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate;
typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr;
struct _qemuDomainObjPrivate {
85 86 87 88 89
    virCond jobCond; /* Use in conjunction with main virDomainObjPtr lock */
    int jobActive; /* Non-zero if a job is active. Only 1 job is allowed at any time
                    * A job includes *all* monitor commands, even those just querying
                    * information, not merely actions */

90 91 92
    qemuMonitorPtr mon;
};

93 94
static int qemudShutdown(void);

95 96
static void qemuDriverLock(struct qemud_driver *driver)
{
97
    virMutexLock(&driver->lock);
98 99 100
}
static void qemuDriverUnlock(struct qemud_driver *driver)
{
101
    virMutexUnlock(&driver->lock);
102 103
}

104 105 106
static void qemuDomainEventFlush(int timer, void *opaque);
static void qemuDomainEventQueue(struct qemud_driver *driver,
                                 virDomainEventPtr event);
107

108 109
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
110
                              virDomainObjPtr vm,
111 112
                              const char *migrateFrom,
                              int stdin_fd);
113

114 115
static void qemudShutdownVMDaemon(virConnectPtr conn,
                                  struct qemud_driver *driver,
116
                                  virDomainObjPtr vm);
117

118
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
119

120
static int qemuDetectVcpuPIDs(virConnectPtr conn,
121
                              struct qemud_driver *driver,
122
                              virDomainObjPtr vm);
123

124 125 126
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                                       virDomainDefPtr def);

J
Jim Meyering 已提交
127
static struct qemud_driver *qemu_driver = NULL;
128

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

static void *qemuDomainObjPrivateAlloc(void)
{
    qemuDomainObjPrivatePtr priv;

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

    return priv;
}

static void qemuDomainObjPrivateFree(void *data)
{
    qemuDomainObjPrivatePtr priv = data;

    /* This should never be non-NULL if we get here, but just in case... */
    if (priv->mon) {
        VIR_ERROR0("Unexpected QEMU monitor still active during domain deletion");
        qemuMonitorClose(priv->mon);
    }
    VIR_FREE(priv);
}


153 154 155 156 157 158 159 160 161
/*
 * obj must be locked before calling, qemud_driver must NOT be locked
 *
 * This must be called by anything that will change the VM state
 * in any way, or anything that will use the QEMU monitor.
 *
 * Upon successful return, the object will have its ref count increased,
 * successful calls must be followed by EndJob eventually
 */
162 163 164 165

/* Give up waiting for mutex after 30 seconds */
#define QEMU_JOB_WAIT_TIME (1000ull * 30)

166 167 168 169
static int qemuDomainObjBeginJob(virDomainObjPtr obj) ATTRIBUTE_RETURN_CHECK;
static int qemuDomainObjBeginJob(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;
170 171 172 173 174 175 176 177 178 179
    struct timeval now;
    unsigned long long then;

    if (gettimeofday(&now, NULL) < 0) {
        virReportSystemError(NULL, errno, "%s",
                             _("cannot get time of day"));
        return -1;
    }
    then = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    then += QEMU_JOB_WAIT_TIME;
180 181 182 183

    virDomainObjRef(obj);

    while (priv->jobActive) {
184
        if (virCondWaitUntil(&priv->jobCond, &obj->lock, then) < 0) {
185
            virDomainObjUnref(obj);
186 187 188 189 190 191
            if (errno == ETIMEDOUT)
                qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_TIMEOUT,
                                 "%s", _("cannot acquire state change lock"));
            else
                virReportSystemError(NULL, errno,
                                     "%s", _("cannot acquire job mutex"));
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
            return -1;
        }
    }
    priv->jobActive = 1;

    return 0;
}

/*
 * obj must be locked before calling, qemud_driver must be locked
 *
 * This must be called by anything that will change the VM state
 * in any way, or anything that will use the QEMU monitor.
 */
static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver,
                                           virDomainObjPtr obj) ATTRIBUTE_RETURN_CHECK;
static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver,
                                           virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;
212 213 214 215 216 217 218 219 220 221
    struct timeval now;
    unsigned long long then;

    if (gettimeofday(&now, NULL) < 0) {
        virReportSystemError(NULL, errno, "%s",
                             _("cannot get time of day"));
        return -1;
    }
    then = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    then += QEMU_JOB_WAIT_TIME;
222 223 224 225 226

    virDomainObjRef(obj);
    qemuDriverUnlock(driver);

    while (priv->jobActive) {
227
        if (virCondWaitUntil(&priv->jobCond, &obj->lock, then) < 0) {
228
            virDomainObjUnref(obj);
229 230 231 232 233 234
            if (errno == ETIMEDOUT)
                qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_TIMEOUT,
                                 "%s", _("cannot acquire state change lock"));
            else
                virReportSystemError(NULL, errno,
                                     "%s", _("cannot acquire job mutex"));
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
            return -1;
        }
    }
    priv->jobActive = 1;

    virDomainObjUnlock(obj);
    qemuDriverLock(driver);
    virDomainObjLock(obj);

    return 0;
}

/*
 * obj must be locked before calling, qemud_driver does not matter
 *
 * To be called after completing the work associated with the
 * earlier  qemuDomainBeginJob() call
 */
static void qemuDomainObjEndJob(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    priv->jobActive = 0;
    virCondSignal(&priv->jobCond);

    virDomainObjUnref(obj);
}


/*
 * obj must be locked before calling, qemud_driver must be unlocked
 *
 * To be called immediately before any QEMU monitor API call
 * Must have alrady called qemuDomainObjBeginJob().
 *
 * To be followed with qemuDomainObjExitMonitor() once complete
 */
272 273 274 275 276
static void qemuDomainObjEnterMonitor(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    qemuMonitorLock(priv->mon);
277
    virDomainObjUnlock(obj);
278 279 280
}


281 282 283 284
/* obj must NOT be locked before calling, qemud_driver must be unlocked
 *
 * Should be paired with an earlier  qemuDomainObjEnterMonitor() call
 */
285 286 287 288 289
static void qemuDomainObjExitMonitor(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    qemuMonitorUnlock(priv->mon);
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    virDomainObjLock(obj);
}


/*
 * obj must be locked before calling, qemud_driver must be locked
 *
 * To be called immediately before any QEMU monitor API call
 * Must have alrady called qemuDomainObjBeginJob().
 *
 * To be followed with qemuDomainObjExitMonitorWithDriver() once complete
 */
static void qemuDomainObjEnterMonitorWithDriver(struct qemud_driver *driver, virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    qemuMonitorLock(priv->mon);
    virDomainObjUnlock(obj);
    qemuDriverUnlock(driver);
}


/* obj must NOT be locked before calling, qemud_driver must be unlocked,
 * and will be locked after returning
 *
 * Should be paired with an earlier  qemuDomainObjEnterMonitor() call
 */
static void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver, virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    qemuMonitorUnlock(priv->mon);
    qemuDriverLock(driver);
    virDomainObjLock(obj);
324 325 326
}


327 328 329 330 331 332 333 334 335
static int qemuCgroupControllerActive(struct qemud_driver *driver,
                                      int controller)
{
    if (driver->cgroup == NULL)
        return 0;
    if (driver->cgroupControllers & (1 << controller))
        return 1;
    return 0;
}
336

337
static int
338
qemudLogFD(virConnectPtr conn, struct qemud_driver *driver, const char* name)
339 340 341
{
    char logfile[PATH_MAX];
    mode_t logmode;
G
Guido Günther 已提交
342
    int ret, fd = -1;
343

344 345
    if ((ret = snprintf(logfile, sizeof(logfile), "%s/%s.log",
                        driver->logDir, name))
G
Guido Günther 已提交
346
        < 0 || ret >= sizeof(logfile)) {
347
        virReportOOMError(conn);
348 349 350 351
        return -1;
    }

    logmode = O_CREAT | O_WRONLY;
352 353
    /* Only logrotate files in /var/log, so only append if running privileged */
    if (driver->privileged)
354
        logmode |= O_APPEND;
355 356 357
    else
        logmode |= O_TRUNC;

358
    if ((fd = open(logfile, logmode, S_IRUSR | S_IWUSR)) < 0) {
359 360 361
        virReportSystemError(conn, errno,
                             _("failed to create logfile %s"),
                             logfile);
362 363
        return -1;
    }
364
    if (virSetCloseExec(fd) < 0) {
365 366
        virReportSystemError(conn, errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
367 368 369 370 371 372 373
        close(fd);
        return -1;
    }
    return fd;
}


374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
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) {
391 392 393
        virReportSystemError(conn, errno,
                             _("failed to create logfile %s"),
                             logfile);
394 395
        return -1;
    }
396
    if (virSetCloseExec(fd) < 0) {
397 398
        virReportSystemError(conn, errno, "%s",
                             _("Unable to set VM logfile close-on-exec flag"));
399 400 401 402
        close(fd);
        return -1;
    }
    if (lseek(fd, pos, SEEK_SET) < 0) {
403 404 405
        virReportSystemError(conn, errno,
                             _("Unable to seek to %lld in %s"),
                             (long long) pos, logfile);
406 407 408 409 410 411
        close(fd);
    }
    return fd;
}


412 413 414 415 416 417 418 419 420 421 422 423
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 已提交
424
        !virDomainObjIsActive(vm)) {
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
        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);
}

446 447
static void
qemudAutostartConfigs(struct qemud_driver *driver) {
448 449 450 451 452
    /* 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
     */
453 454 455
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
456
    /* Ignoring NULL conn which is mostly harmless here */
457
    struct qemuAutostartData data = { driver, conn };
458

459
    qemuDriverLock(driver);
460
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
461
    qemuDriverUnlock(driver);
462

463 464
    if (conn)
        virConnectClose(conn);
465 466
}

467 468 469 470 471 472 473 474 475 476 477 478 479

/**
 * 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)
{
480
    char ebuf[1024];
481 482 483
    char *file = NULL;

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

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

493 494 495
    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)));
496

D
Daniel Veillard 已提交
497

498
    return 0;
499 500
}

501 502 503 504 505 506 507 508 509 510 511 512 513 514

/*
 * This is a callback registered with a qemuMonitorPtr  instance,
 * and to be invoked when the monitor console hits an end of file
 * condition, or error, thus indicating VM shutdown should be
 * performed
 */
static void
qemuHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                     virDomainObjPtr vm,
                     int hasError) {
    struct qemud_driver *driver = qemu_driver;
    virDomainEventPtr event = NULL;

515
    VIR_DEBUG("Received EOF on %p '%s'", vm, vm->def->name);
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
    virDomainObjLock(vm);

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     hasError ?
                                     VIR_DOMAIN_EVENT_STOPPED_FAILED :
                                     VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);

    qemudShutdownVMDaemon(NULL, driver, vm);
    if (!vm->persistent)
        virDomainRemoveInactive(&driver->domains, vm);
    else
        virDomainObjUnlock(vm);

    if (event) {
        qemuDriverLock(driver);
        qemuDomainEventQueue(driver, event);
        qemuDriverUnlock(driver);
    }
}


538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
static virStorageEncryptionPtr
findDomainDiskEncryption(virConnectPtr conn, virDomainObjPtr vm,
                         const char *path)
{
    bool seen_volume;
    int i;

    seen_volume = false;
    for (i = 0; i < vm->def->ndisks; i++) {
        virDomainDiskDefPtr disk;

        disk = vm->def->disks[i];
        if (disk->src != NULL && STREQ(disk->src, path)) {
            seen_volume = true;
            if (disk->encryption != NULL)
                return disk->encryption;
        }
    }
    if (seen_volume)
        qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
                         _("missing <encryption> for volume %s"), path);
    else
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("unexpected passphrase request for volume %s"),
                         path);
    return NULL;
}


static int
findVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                         virConnectPtr conn,
                         virDomainObjPtr vm,
                         const char *path,
                         char **secretRet,
                         size_t *secretLen)
{
    virStorageEncryptionPtr enc;
    virSecretPtr secret;
    char *passphrase;
    unsigned char *data;
    size_t size;
580 581
    int ret = -1;

582
    virDomainObjLock(vm);
583 584 585 586

    if (!conn) {
        qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT,
                         "%s", _("cannot find secrets without a connection"));
587
        goto cleanup;
588 589 590 591 592 593 594
    }

    if (conn->secretDriver == NULL ||
        conn->secretDriver->lookupByUUID == NULL ||
        conn->secretDriver->getValue == NULL) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s",
                         _("secret storage not supported"));
595
        goto cleanup;
596 597 598 599 600 601 602 603 604 605 606 607
    }

    enc = findDomainDiskEncryption(conn, vm, path);
    if (enc == NULL)
        return -1;

    if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW ||
        enc->nsecrets != 1 ||
        enc->secrets[0]->type !=
        VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
                         _("invalid <encryption> for volume %s"), path);
608
        goto cleanup;
609 610 611 612 613
    }

    secret = conn->secretDriver->lookupByUUID(conn,
                                              enc->secrets[0]->uuid);
    if (secret == NULL)
614
        goto cleanup;
615 616 617 618
    data = conn->secretDriver->getValue(secret, &size,
                                        VIR_SECRET_GET_VALUE_INTERNAL_CALL);
    virUnrefSecret(secret);
    if (data == NULL)
619
        goto cleanup;
620 621 622 623 624 625 626

    if (memchr(data, '\0', size) != NULL) {
        memset(data, 0, size);
        VIR_FREE(data);
        qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_SECRET,
                         _("format='qcow' passphrase for %s must not contain a "
                           "'\\0'"), path);
627
        goto cleanup;
628 629 630 631 632 633
    }

    if (VIR_ALLOC_N(passphrase, size + 1) < 0) {
        memset(data, 0, size);
        VIR_FREE(data);
        virReportOOMError(conn);
634
        goto cleanup;
635 636 637 638 639 640 641 642 643 644
    }
    memcpy(passphrase, data, size);
    passphrase[size] = '\0';

    memset(data, 0, size);
    VIR_FREE(data);

    *secretRet = passphrase;
    *secretLen = size;

645 646 647
    ret = 0;

cleanup:
648 649
    virDomainObjUnlock(vm);

650
    return ret;
651 652
}

653
static int
654
qemuConnectMonitor(virDomainObjPtr vm)
655
{
656
    qemuDomainObjPrivatePtr priv = vm->privateData;
657

658
    if ((priv->mon = qemuMonitorOpen(vm, qemuHandleMonitorEOF)) == NULL) {
659
        VIR_ERROR(_("Failed to connect monitor for %s\n"), vm->def->name);
660
        return -1;
661
    }
662

663 664 665
    qemuMonitorRegisterDiskSecretLookup(priv->mon,
                                        findVolumeQcowPassphrase);

666 667
    return 0;
}
668 669 670 671

/*
 * Open an existing VM's monitor, re-detect VCPU threads
 * and re-reserve the security labels in use
672
 */
673 674
static void
qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
675
{
676 677 678 679
    virDomainObjPtr obj = payload;
    struct qemud_driver *driver = opaque;

    virDomainObjLock(obj);
680

681 682 683 684
    VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name);

    /* XXX check PID liveliness & EXE path */
    if (qemuConnectMonitor(obj) < 0)
685
        goto error;
686

687 688 689 690
    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
        goto error;
    }

691 692 693 694
    if (obj->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        driver->securityDriver &&
        driver->securityDriver->domainReserveSecurityLabel &&
        driver->securityDriver->domainReserveSecurityLabel(NULL, obj) < 0)
695
        goto error;
696

697 698
    if (obj->def->id >= driver->nextvmid)
        driver->nextvmid = obj->def->id + 1;
699

700 701
    virDomainObjUnlock(obj);
    return;
702

703
error:
704 705 706 707
    /* 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);
708 709 710 711
    if (!obj->persistent)
        virDomainRemoveInactive(&driver->domains, obj);
    else
        virDomainObjUnlock(obj);
712
}
713

714
/**
715
 * qemudReconnectDomains
716 717 718 719 720 721 722
 *
 * Try to re-open the resources for live VMs that we care
 * about.
 */
static void
qemuReconnectDomains(struct qemud_driver *driver)
{
723
    virHashForEach(driver->domains.objs, qemuReconnectDomain, driver);
724 725
}

726 727 728 729 730 731 732 733 734 735 736 737

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) {
738
        virReportOOMError(NULL);
739 740 741 742 743
        return -1;
    }

    caps->host.secModel.doi = strdup(doi);
    if (!caps->host.secModel.doi) {
744
        virReportOOMError(NULL);
745 746 747 748 749 750 751 752 753 754
        return -1;
    }

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

    return 0;
}


755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
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;

775
    VIR_INFO("Initialized security driver %s", security_drv->name);
776 777 778 779 780

    /*
     * Add security policy host caps now that the security driver is
     * initialized.
     */
781 782
    return qemudSecurityCapsInit(security_drv, qemud_drv->caps);
}
783 784


785

786 787 788 789 790 791
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
792
qemudStartup(int privileged) {
793
    char *base = NULL;
D
Daniel P. Berrange 已提交
794
    char driverConf[PATH_MAX];
795
    int rc;
796

797
    if (VIR_ALLOC(qemu_driver) < 0)
798 799
        return -1;

800
    if (virMutexInit(&qemu_driver->lock) < 0) {
801
        VIR_ERROR("%s", _("cannot initialize mutex"));
802 803 804
        VIR_FREE(qemu_driver);
        return -1;
    }
805
    qemuDriverLock(qemu_driver);
806
    qemu_driver->privileged = privileged;
807

808 809 810
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;

811 812 813
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;

814
    /* Init callback list */
815
    if (VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
816
        goto out_of_memory;
817 818 819 820 821 822
    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
        goto out_of_memory;

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

824
    if (privileged) {
825 826
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1)
827
            goto out_of_memory;
828

D
Daniel P. Berrange 已提交
829
        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
830
            goto out_of_memory;
831 832

        if (virAsprintf(&qemu_driver->stateDir,
833
                      "%s/run/libvirt/qemu", LOCAL_STATE_DIR) == -1)
834
            goto out_of_memory;
835 836 837 838 839 840 841 842

        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;
843
    } else {
844
        uid_t uid = geteuid();
845 846
        char *userdir = virGetUserDirectory(NULL, uid);
        if (!userdir)
847
            goto error;
848

849
        if (virAsprintf(&qemu_driver->logDir,
850 851
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
852
            goto out_of_memory;
853
        }
854

855 856
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
857
            goto out_of_memory;
858 859
        }
        VIR_FREE(userdir);
860 861 862

        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
            goto out_of_memory;
863 864 865 866
        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;
867 868 869
    }

    if (virFileMakePath(qemu_driver->stateDir) < 0) {
870
        char ebuf[1024];
871 872
        VIR_ERROR(_("Failed to create state dir '%s': %s\n"),
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
873
        goto error;
874
    }
875 876 877 878 879 880 881 882 883 884 885 886
    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;
    }
887 888 889 890

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

895
    if (virAsprintf(&qemu_driver->configDir, "%s/qemu", base) == -1)
896 897
        goto out_of_memory;

898
    if (virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1)
899 900
        goto out_of_memory;

901
    VIR_FREE(base);
902

903 904 905 906 907 908 909
    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)));
    }

910
    if ((qemu_driver->caps = qemudCapsInit(NULL)) == NULL)
911
        goto out_of_memory;
D
Daniel P. Berrange 已提交
912

913 914 915
    qemu_driver->caps->privateDataAllocFunc = qemuDomainObjPrivateAlloc;
    qemu_driver->caps->privateDataFreeFunc = qemuDomainObjPrivateFree;

916 917 918
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew(NULL)) == NULL)
        goto error;

919
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
920 921 922
        goto error;
    }

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

938
    if (qemudSecurityInit(qemu_driver) < 0) {
939
        goto error;
D
Daniel P. Berrange 已提交
940 941
    }

942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
    /* 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;
    }

973 974 975 976 977 978 979 980 981 982 983 984
    /* 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 */
985 986 987 988
    if (virDomainLoadAllConfigs(NULL,
                                qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->configDir,
989
                                qemu_driver->autostartDir,
990
                                0, NULL, NULL) < 0)
991
        goto error;
992 993
    qemuDriverUnlock(qemu_driver);

994 995
    qemudAutostartConfigs(qemu_driver);

996

997 998
    return 0;

999
out_of_memory:
1000
    virReportOOMError(NULL);
1001 1002 1003
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
1004
    VIR_FREE(base);
1005
    qemudShutdown();
1006 1007 1008
    return -1;
}

1009 1010 1011 1012
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;

1013 1014 1015 1016 1017 1018 1019 1020
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }
1021 1022
}

1023 1024 1025 1026 1027 1028 1029 1030
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
1031 1032 1033
    if (!qemu_driver)
        return 0;

1034
    qemuDriverLock(qemu_driver);
1035 1036 1037 1038
    virDomainLoadAllConfigs(NULL,
                            qemu_driver->caps,
                            &qemu_driver->domains,
                            qemu_driver->configDir,
1039
                            qemu_driver->autostartDir,
1040
                            0, qemudNotifyLoadDomain, qemu_driver);
1041
    qemuDriverUnlock(qemu_driver);
1042

1043
    qemudAutostartConfigs(qemu_driver);
1044 1045

    return 0;
1046 1047
}

1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
/**
 * 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) {
1058
    int active = 0;
1059

1060 1061 1062
    if (!qemu_driver)
        return 0;

1063
    /* XXX having to iterate here is not great because it requires many locks */
1064
    qemuDriverLock(qemu_driver);
1065
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
1066 1067
    qemuDriverUnlock(qemu_driver);
    return active;
1068 1069
}

1070 1071 1072 1073 1074 1075 1076
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
1077

1078
    if (!qemu_driver)
1079
        return -1;
1080

1081
    qemuDriverLock(qemu_driver);
1082
    pciDeviceListFree(NULL, qemu_driver->activePciHostdevs);
1083 1084
    virCapabilitiesFree(qemu_driver->caps);

1085
    virDomainObjListDeinit(&qemu_driver->domains);
1086

1087
    VIR_FREE(qemu_driver->securityDriverName);
1088
    VIR_FREE(qemu_driver->logDir);
1089 1090
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
1091
    VIR_FREE(qemu_driver->stateDir);
1092 1093
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
1094
    VIR_FREE(qemu_driver->vncTLSx509certdir);
J
Jim Meyering 已提交
1095
    VIR_FREE(qemu_driver->vncListen);
1096
    VIR_FREE(qemu_driver->vncPassword);
1097
    VIR_FREE(qemu_driver->vncSASLdir);
1098
    VIR_FREE(qemu_driver->saveImageFormat);
1099 1100
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
D
Daniel P. Berrange 已提交
1101

1102 1103
    /* Free domain callback list */
    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
1104 1105 1106 1107
    virDomainEventQueueFree(qemu_driver->domainEventQueue);

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

1109 1110 1111
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);

1112 1113
    virCgroupFree(&qemu_driver->cgroup);

1114
    qemuDriverUnlock(qemu_driver);
1115
    virMutexDestroy(&qemu_driver->lock);
1116
    VIR_FREE(qemu_driver);
1117 1118

    return 0;
1119 1120
}

1121 1122 1123 1124
typedef int qemuLogHandleOutput(virConnectPtr conn,
                                virDomainObjPtr vm,
                                const char *output,
                                int fd);
1125 1126 1127 1128 1129 1130 1131 1132 1133

/*
 * Returns -1 for error, 0 on success
 */
static int
qemudReadLogOutput(virConnectPtr conn,
                   virDomainObjPtr vm,
                   int fd,
                   char *buf,
G
Guido Günther 已提交
1134
                   size_t buflen,
1135
                   qemuLogHandleOutput func,
1136 1137 1138
                   const char *what,
                   int timeout)
{
1139
    int retries = (timeout*10);
1140
    int got = 0;
1141 1142 1143
    buf[0] = '\0';

    while (retries) {
1144
        ssize_t func_ret, ret;
1145
        int isdead = 0;
G
Guido Günther 已提交
1146

1147 1148
        func_ret = func(conn, vm, buf, fd);

1149 1150
        if (kill(vm->pid, 0) == -1 && errno == ESRCH)
            isdead = 1;
1151

1152 1153
        /* Any failures should be detected before we read the log, so we
         * always have something useful to report on failure. */
1154 1155
        ret = saferead(fd, buf+got, buflen-got-1);
        if (ret < 0) {
1156 1157 1158 1159 1160 1161
            virReportSystemError(conn, errno,
                                 _("Failure while reading %s log output"),
                                 what);
            return -1;
        }

1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
        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;
        }

1178 1179
        if (func_ret <= 0)
            return func_ret;
1180 1181 1182 1183

        usleep(100*1000);
        retries--;
    }
1184 1185 1186

    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                     _("Timed out while reading %s log output"), what);
1187 1188 1189
    return -1;
}

1190

1191 1192 1193 1194 1195 1196 1197 1198
/*
 * 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
 */
1199
static int
1200 1201 1202 1203
qemudExtractTTYPath(virConnectPtr conn,
                    const char *haystack,
                    size_t *offset,
                    char **path)
1204
{
1205
    static const char needle[] = "char device redirected to";
1206
    char *tmp, *dev;
1207

1208
    VIR_FREE(*path);
1209
    /* First look for our magic string */
1210 1211 1212 1213 1214
    if (!(tmp = strstr(haystack + *offset, needle))) {
        return 1;
    }
    tmp += sizeof(needle);
    dev = tmp;
1215

1216 1217 1218 1219 1220
    /*
     * And look for first whitespace character and nul terminate
     * to mark end of the pty path
     */
    while (*tmp) {
1221
        if (c_isspace(*tmp)) {
1222 1223
            *path = strndup(dev, tmp-dev);
            if (*path == NULL) {
1224
                virReportOOMError(conn);
1225 1226
                return -1;
            }
1227

1228
            /* ... now further update offset till we get EOL */
1229
            *offset = tmp - haystack;
1230 1231
            return 0;
        }
1232
        tmp++;
1233 1234 1235 1236 1237
    }

    /*
     * We found a path, but didn't find any whitespace,
     * so it must be still incomplete - we should at
1238 1239
     * least see a \n - indicate that we want to carry
     * on trying again
1240
     */
1241
    return 1;
1242 1243 1244
}

static int
1245
qemudFindCharDevicePTYs(virConnectPtr conn,
1246
                        virDomainObjPtr vm,
1247 1248
                        const char *output,
                        int fd ATTRIBUTE_UNUSED)
1249
{
1250
    size_t offset = 0;
1251
    int ret, i;
1252 1253

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

1257
    /* first comes the serial devices */
1258 1259
    for (i = 0 ; i < vm->def->nserials ; i++) {
        virDomainChrDefPtr chr = vm->def->serials[i];
1260
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
1261 1262
            if ((ret = qemudExtractTTYPath(conn, output, &offset,
                                           &chr->data.file.path)) != 0)
1263
                return ret;
1264 1265 1266
        }
    }

1267
    /* then the parallel devices */
1268 1269
    for (i = 0 ; i < vm->def->nparallels ; i++) {
        virDomainChrDefPtr chr = vm->def->parallels[i];
1270
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
1271 1272
            if ((ret = qemudExtractTTYPath(conn, output, &offset,
                                           &chr->data.file.path)) != 0)
1273
                return ret;
1274 1275 1276
        }
    }

1277
    return 0;
1278 1279
}

1280 1281 1282 1283
static int
qemudWaitForMonitor(virConnectPtr conn,
                    struct qemud_driver* driver,
                    virDomainObjPtr vm, off_t pos)
1284
{
1285
    char buf[4096]; /* Plenty of space to get startup greeting */
1286 1287 1288 1289 1290
    int logfd;
    int ret;

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

1293 1294 1295
    ret = qemudReadLogOutput(conn, vm, logfd, buf, sizeof(buf),
                             qemudFindCharDevicePTYs,
                             "console", 3);
1296
    if (close(logfd) < 0) {
1297
        char ebuf[4096];
1298
        VIR_WARN(_("Unable to close logfile: %s\n"),
1299 1300
                 virStrerror(errno, ebuf, sizeof ebuf));
    }
1301

1302 1303 1304 1305 1306 1307
    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;
    }
1308

1309 1310
    VIR_DEBUG("Connect monitor to %p '%s'", vm, vm->def->name);
    if (qemuConnectMonitor(vm) < 0)
1311 1312 1313
        return -1;

    return 0;
1314 1315
}

1316
static int
1317
qemuDetectVcpuPIDs(virConnectPtr conn,
1318
                   struct qemud_driver *driver,
1319 1320 1321
                   virDomainObjPtr vm) {
    pid_t *cpupids = NULL;
    int ncpupids;
1322
    qemuDomainObjPrivatePtr priv = vm->privateData;
1323

1324
    if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
1325 1326 1327 1328 1329
        vm->nvcpupids = 1;
        if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) {
            virReportOOMError(conn);
            return -1;
        }
1330 1331 1332 1333
        vm->vcpupids[0] = vm->pid;
        return 0;
    }

1334
    /* What follows is now all KVM specific */
1335

1336
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
1337
    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) < 0) {
1338
        qemuDomainObjExitMonitorWithDriver(driver, vm);
1339
        return -1;
1340
    }
1341
    qemuDomainObjExitMonitorWithDriver(driver, vm);
1342

1343 1344 1345
    /* Treat failure to get VCPU<->PID mapping as non-fatal */
    if (ncpupids == 0)
        return 0;
1346

1347 1348 1349 1350 1351 1352 1353
    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;
    }
1354

1355 1356
    vm->nvcpupids = ncpupids;
    vm->vcpupids = cpupids;
1357 1358 1359
    return 0;
}

1360 1361
static int
qemudInitCpus(virConnectPtr conn,
1362
              struct qemud_driver *driver,
D
Daniel Veillard 已提交
1363 1364
              virDomainObjPtr vm,
              const char *migrateFrom) {
1365 1366
#if HAVE_SCHED_GETAFFINITY
    cpu_set_t mask;
1367
    int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN;
1368
    virNodeInfo nodeinfo;
1369
    qemuDomainObjPrivatePtr priv = vm->privateData;
1370

1371
    if (nodeGetInfo(conn, &nodeinfo) < 0)
1372 1373 1374 1375
        return -1;

    /* setaffinity fails if you set bits for CPUs which
     * aren't present, so we have to limit ourselves */
1376 1377 1378
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
1379 1380

    CPU_ZERO(&mask);
D
Daniel P. Berrange 已提交
1381 1382 1383 1384 1385 1386
    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++)
1387
            CPU_SET(i, &mask);
D
Daniel P. Berrange 已提交
1388
    }
1389 1390 1391 1392

    for (i = 0 ; i < vm->nvcpupids ; i++) {
        if (sched_setaffinity(vm->vcpupids[i],
                              sizeof(mask), &mask) < 0) {
1393 1394
            virReportSystemError(conn, errno, "%s",
                                 _("failed to set CPU affinity"));
1395 1396 1397 1398 1399
            return -1;
        }
    }
#endif /* HAVE_SCHED_GETAFFINITY */

1400
    /* XXX This resume doesn't really belong here. Move it up to caller */
D
Daniel Veillard 已提交
1401 1402
    if (migrateFrom == NULL) {
        /* Allow the CPUS to start executing */
1403
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
1404
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
1405 1406 1407
            if (virGetLastError() == NULL)
                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("resume operation failed"));
1408
            qemuDomainObjExitMonitorWithDriver(driver, vm);
D
Daniel Veillard 已提交
1409 1410
            return -1;
        }
1411
        qemuDomainObjExitMonitorWithDriver(driver, vm);
1412 1413 1414 1415 1416 1417
    }

    return 0;
}


1418
static int
1419 1420
qemuInitPasswords(struct qemud_driver *driver,
                  virDomainObjPtr vm) {
1421
    int ret = 0;
1422
    qemuDomainObjPrivatePtr priv = vm->privateData;
1423

1424 1425 1426
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) {
1427

1428
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
1429
        ret = qemuMonitorSetVNCPassword(priv->mon,
1430 1431 1432
                                        vm->def->graphics[0]->data.vnc.passwd ?
                                        vm->def->graphics[0]->data.vnc.passwd :
                                        driver->vncPassword);
1433
        qemuDomainObjExitMonitorWithDriver(driver, vm);
1434 1435
    }

1436
    return ret;
1437 1438 1439
}


1440
static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475
    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;
}

1476 1477 1478 1479 1480
static pciDeviceList *
qemuGetPciHostDeviceList(virConnectPtr conn,
                         virDomainDefPtr def)
{
    pciDeviceList *list;
1481 1482
    int i;

1483 1484
    if (!(list = pciDeviceListNew(conn)))
        return NULL;
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499

    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);
1500 1501 1502 1503
        if (!dev) {
            pciDeviceListFree(conn, list);
            return NULL;
        }
1504

1505
        if (pciDeviceListAdd(conn, list, dev) < 0) {
1506
            pciFreeDevice(conn, dev);
1507 1508
            pciDeviceListFree(conn, list);
            return NULL;
1509 1510
        }

1511
        pciDeviceSetManaged(dev, hostdev->managed);
1512 1513
    }

1514 1515 1516 1517
    return list;
}

static int
1518 1519 1520 1521
qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                            virDomainDefPtr def)
{
    pciDeviceList *pcidevs;
1522
    int ret = -1;
1523 1524 1525 1526 1527 1528 1529

    if (!def->nhostdevs)
        return 0;

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

1530 1531
    while (pciDeviceListCount(pcidevs) > 0) {
        pciDevice *dev = pciDeviceListSteal(NULL, pcidevs, 0);
1532 1533
        if (pciDeviceListAdd(NULL,
                             driver->activePciHostdevs,
1534 1535 1536
                             dev) < 0) {
            pciFreeDevice(NULL, dev);
            goto cleanup;
1537 1538 1539
        }
    }

1540 1541 1542
    ret = 0;

cleanup:
1543 1544 1545 1546 1547 1548 1549 1550
    pciDeviceListFree(NULL, pcidevs);
    return ret;
}

static int
qemuPrepareHostDevices(virConnectPtr conn,
                       struct qemud_driver *driver,
                       virDomainDefPtr def)
1551 1552 1553
{
    pciDeviceList *pcidevs;
    int i;
1554
    int ret = -1;
1555 1556 1557 1558 1559 1560 1561

    if (!def->nhostdevs)
        return 0;

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

1562
    /* We have to use 3 loops here. *All* devices must
1563 1564
     * be detached before we reset any of them, because
     * in some cases you have to reset the whole PCI,
1565 1566
     * which impacts all devices on it. Also, all devices
     * must be reset before being marked as active.
1567 1568 1569 1570 1571 1572 1573
     */

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

1574 1575 1576 1577 1578 1579
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        if (pciDeviceGetManaged(dev) &&
            pciDettachDevice(conn, dev) < 0)
            goto cleanup;
    }
1580 1581 1582

    /* Now that all the PCI hostdevs have be dettached, we can safely
     * reset them */
1583 1584 1585
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        if (pciResetDevice(conn, dev,
1586
                           driver->activePciHostdevs) < 0)
1587 1588
            goto cleanup;
    }
1589

1590
    /* Now mark all the devices as active */
1591 1592 1593
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        pciDeviceListSteal(NULL, pcidevs, dev);
1594 1595
        if (pciDeviceListAdd(conn,
                             driver->activePciHostdevs,
1596 1597 1598 1599
                             dev) < 0) {
            pciFreeDevice(NULL, dev);
            goto cleanup;
        }
1600 1601
    }

1602
    ret = 0;
1603

1604
cleanup:
1605
    pciDeviceListFree(conn, pcidevs);
1606
    return ret;
1607 1608
}

1609
static void
1610 1611 1612
qemuDomainReAttachHostDevices(virConnectPtr conn,
                              struct qemud_driver *driver,
                              virDomainDefPtr def)
1613
{
1614
    pciDeviceList *pcidevs;
1615 1616
    int i;

1617 1618
    if (!def->nhostdevs)
        return;
1619

1620 1621 1622 1623 1624 1625
    if (!(pcidevs = qemuGetPciHostDeviceList(conn, def))) {
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to allocate pciDeviceList: %s\n"),
                  err ? err->message : "");
        virResetError(err);
        return;
1626 1627
    }

1628 1629
    /* Again 3 loops; mark all devices as inactive before reset
     * them and reset all the devices before re-attach */
1630

1631 1632 1633 1634
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        pciDeviceListDel(conn, driver->activePciHostdevs, dev);
    }
1635

1636 1637 1638
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        if (pciResetDevice(conn, dev,
1639
                           driver->activePciHostdevs) < 0) {
1640
            virErrorPtr err = virGetLastError();
1641
            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
1642 1643 1644
                      err ? err->message : "");
            virResetError(err);
        }
1645
    }
1646

1647 1648 1649 1650
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
        if (pciDeviceGetManaged(dev) &&
            pciReAttachDevice(NULL, dev) < 0) {
1651
            virErrorPtr err = virGetLastError();
1652
            VIR_ERROR(_("Failed to re-attach PCI device: %s\n"),
1653 1654 1655
                      err ? err->message : "");
            virResetError(err);
        }
1656
    }
1657

1658
    pciDeviceListFree(conn, pcidevs);
1659 1660
}

1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
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

1671 1672 1673 1674 1675 1676
static int qemuSetupCgroup(virConnectPtr conn,
                           struct qemud_driver *driver,
                           virDomainObjPtr vm)
{
    virCgroupPtr cgroup = NULL;
    int rc;
1677
    unsigned int i;
1678 1679 1680 1681
    const char *const *deviceACL =
        driver->cgroupDeviceACL ?
        (const char *const *)driver->cgroupDeviceACL :
        defaultDeviceACL;
1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693

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

1694 1695
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        rc = virCgroupDenyAllDevices(cgroup);
1696
        if (rc != 0) {
1697 1698 1699 1700 1701
            if (rc == -EPERM) {
                VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
                goto done;
            }

1702
            virReportSystemError(conn, -rc,
1703
                                 _("Unable to deny all devices for %s"), vm->def->name);
1704 1705 1706
            goto cleanup;
        }

1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720
        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;
            }
        }
1721

1722
        rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
1723 1724
        if (rc != 0) {
            virReportSystemError(conn, -rc, "%s",
1725
                                 _("unable to allow /dev/pts/ devices"));
1726 1727 1728
            goto cleanup;
        }

1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747
        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;
            }
1748 1749 1750 1751
        }
    }

done:
1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820
    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;
}


1821 1822 1823 1824 1825 1826 1827 1828 1829
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;
}

1830 1831

#ifdef __linux__
1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
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;

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

1845 1846 1847 1848 1849 1850 1851 1852
    if (chown(file, owner->uid, owner->gid) < 0) {
        virReportSystemError(conn, errno, _("cannot set ownership on %s"), file);
        return -1;
    }

    return 0;
}

1853 1854 1855 1856
static int qemuDomainSetHostdevUSBOwnership(virConnectPtr conn,
                                            virDomainHostdevDefPtr def,
                                            uid_t uid, gid_t gid)
{
1857 1858
    struct qemuFileOwner owner = { uid, gid };
    int ret = -1;
1859 1860 1861 1862 1863 1864

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

1865 1866 1867 1868 1869 1870 1871 1872 1873
    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);
1874

1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
    usbFreeDevice(conn, dev);
cleanup:
    return ret;
}

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

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

1888 1889
    if (chown(file, owner->uid, owner->gid) < 0) {
        virReportSystemError(conn, errno, _("cannot set ownership on %s"), file);
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899
        return -1;
    }

    return 0;
}

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

1903 1904 1905 1906 1907
    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);
1908

1909
    if (!dev)
1910 1911
        goto cleanup;

1912 1913
    ret = pciDeviceFileIterate(conn, dev,
                               qemuDomainSetHostdevPCIOwnershipActor, &owner);
1914

1915
    pciFreeDevice(conn, dev);
1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939
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 已提交
1940
    qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s",
1941 1942 1943 1944 1945 1946
                     _("unable to set host device ownership on this platform"));
    return -1;
#endif

}

1947 1948
static int qemuDomainSetFileOwnership(virConnectPtr conn,
                                      const char *path,
1949 1950 1951
                                      uid_t uid, gid_t gid)
{

1952
    if (!path)
1953 1954
        return 0;

1955 1956
    VIR_DEBUG("Setting ownership on %s to %d:%d", path, uid, gid);
    if (chown(path, uid, gid) < 0) {
1957
        virReportSystemError(conn, errno, _("cannot set ownership on %s"),
1958
                             path);
1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987
        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;

1988
        return qemuDomainSetFileOwnership(conn, def->data.disk->src, uid, gid);
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015

    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;

2016 2017 2018 2019
    if (qemuDomainSetFileOwnership(conn, def->os.kernel, uid, gid) < 0 ||
        qemuDomainSetFileOwnership(conn, def->os.initrd, uid, gid) < 0)
        return -1;

2020 2021 2022 2023 2024
    for (i = 0 ; i < def->ndisks ; i++) {
        if (restore &&
            (def->disks[i]->readonly || def->disks[i]->shared))
            continue;

2025
        if (qemuDomainSetFileOwnership(conn, def->disks[i]->src, uid, gid) < 0)
2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036
            return -1;
    }

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

    return 0;
}

2037 2038 2039
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
                                            const char *name);

2040 2041 2042 2043
struct qemudHookData {
    virConnectPtr conn;
    virDomainObjPtr vm;
    struct qemud_driver *driver;
2044 2045 2046
};

static int qemudSecurityHook(void *data) {
2047 2048 2049 2050
    struct qemudHookData *h = data;

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

2052
    if (qemudDomainSetSecurityLabel(h->conn, h->driver, h->vm) < 0)
2053 2054 2055 2056 2057
        return -1;

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

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

2061 2062 2063 2064 2065
        if (h->driver->group) {
            if (setregid(h->driver->group, h->driver->group) < 0) {
                virReportSystemError(NULL, errno,
                                     _("cannot change to '%d' group"),
                                     h->driver->group);
2066
                return -1;
2067
            }
2068
        }
2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079
        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;
2080 2081
}

2082 2083 2084 2085 2086 2087
static int
qemuPrepareMonitorChr(virConnectPtr conn,
                      struct qemud_driver *driver,
                      virDomainChrDefPtr monitor_chr,
                      const char *vm)
{
2088 2089
    monitor_chr->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_MONITOR;

2090 2091 2092 2093
    monitor_chr->type = VIR_DOMAIN_CHR_TYPE_UNIX;
    monitor_chr->data.nix.listen = 1;

    if (virAsprintf(&monitor_chr->data.nix.path, "%s/%s.monitor",
2094
                    driver->libDir, vm) < 0) {
2095 2096 2097 2098 2099 2100 2101
        virReportOOMError(conn);
        return -1;
    }

    return 0;
}

2102 2103
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
2104
                              virDomainObjPtr vm,
2105 2106
                              const char *migrateFrom,
                              int stdin_fd) {
2107
    const char **argv = NULL, **tmp;
2108
    const char **progenv = NULL;
2109
    int i, ret;
2110
    struct stat sb;
2111 2112
    int *tapfds = NULL;
    int ntapfds = 0;
2113
    unsigned int qemuCmdFlags;
2114
    fd_set keepfd;
2115
    const char *emulator;
G
Guido Günther 已提交
2116
    pid_t child;
2117
    int pos = -1;
2118
    char ebuf[1024];
2119
    char *pidfile = NULL;
2120
    int logfile;
2121
    qemuDomainObjPrivatePtr priv = vm->privateData;
2122

2123
    struct qemudHookData hookData;
2124 2125 2126 2127
    hookData.conn = conn;
    hookData.vm = vm;
    hookData.driver = driver;

2128
    FD_ZERO(&keepfd);
2129

D
Daniel P. Berrange 已提交
2130
    if (virDomainObjIsActive(vm)) {
2131
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_INVALID,
2132
                         "%s", _("VM is already active"));
2133 2134 2135
        return -1;
    }

2136 2137 2138 2139 2140 2141 2142 2143
    /* 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;

2144 2145 2146
    /* Ensure no historical cgroup for this VM is lieing around bogus settings */
    qemuRemoveCgroup(conn, driver, vm);

2147 2148 2149
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        vm->def->graphics[0]->data.vnc.autoport) {
2150
        int port = qemudNextFreeVNCPort(driver);
2151
        if (port < 0) {
2152
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
2153
                             "%s", _("Unable to find an unused VNC port"));
2154
            goto cleanup;
2155
        }
2156
        vm->def->graphics[0]->data.vnc.port = port;
2157
    }
2158

2159
    if (virFileMakePath(driver->logDir) < 0) {
2160 2161 2162
        virReportSystemError(conn, errno,
                             _("cannot create log directory %s"),
                             driver->logDir);
2163
        goto cleanup;
2164 2165
    }

2166
    if ((logfile = qemudLogFD(conn, driver, vm->def->name)) < 0)
2167
        goto cleanup;
2168

2169 2170
    emulator = vm->def->emulator;

2171 2172 2173 2174
    /* 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
     */
2175
    if (stat(emulator, &sb) < 0) {
2176 2177 2178
        virReportSystemError(conn, errno,
                             _("Cannot find QEMU binary %s"),
                             emulator);
2179
        goto cleanup;
2180 2181
    }

2182
    if (qemudExtractVersionInfo(emulator,
2183
                                NULL,
2184
                                &qemuCmdFlags) < 0)
2185
        goto cleanup;
2186

2187 2188 2189
    if (qemuSetupCgroup(conn, driver, vm) < 0)
        goto cleanup;

2190
    if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
2191
        goto cleanup;
2192

2193 2194 2195 2196 2197
    if (VIR_ALLOC(vm->monitor_chr) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }

2198 2199
    if (qemuPrepareMonitorChr(conn, driver, vm->monitor_chr, vm->def->name) < 0)
        goto cleanup;
2200

D
Daniel P. Berrange 已提交
2201 2202 2203 2204 2205 2206 2207
    if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
        virReportSystemError(conn, ret,
                             _("Cannot remove stale PID file for %s"),
                             vm->def->name);
        goto cleanup;
    }

2208 2209 2210 2211 2212
    if (!(pidfile = virFilePid(driver->stateDir, vm->def->name))) {
        virReportSystemError(conn, errno,
                             "%s", _("Failed to build pidfile path."));
        goto cleanup;
    }
D
Daniel P. Berrange 已提交
2213

2214
    vm->def->id = driver->nextvmid++;
2215
    if (qemudBuildCommandLine(conn, driver, vm->def, vm->monitor_chr,
2216
                              qemuCmdFlags, &argv, &progenv,
2217 2218
                              &tapfds, &ntapfds, migrateFrom) < 0)
        goto cleanup;
2219

2220 2221
    tmp = progenv;
    while (*tmp) {
2222
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
2223
            VIR_WARN(_("Unable to write envv to logfile: %s\n"),
2224
                     virStrerror(errno, ebuf, sizeof ebuf));
2225
        if (safewrite(logfile, " ", 1) < 0)
2226
            VIR_WARN(_("Unable to write envv to logfile: %s\n"),
2227
                     virStrerror(errno, ebuf, sizeof ebuf));
2228 2229
        tmp++;
    }
2230 2231
    tmp = argv;
    while (*tmp) {
2232
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
2233
            VIR_WARN(_("Unable to write argv to logfile: %s\n"),
2234
                     virStrerror(errno, ebuf, sizeof ebuf));
2235
        if (safewrite(logfile, " ", 1) < 0)
2236
            VIR_WARN(_("Unable to write argv to logfile: %s\n"),
2237
                     virStrerror(errno, ebuf, sizeof ebuf));
2238 2239
        tmp++;
    }
2240
    if (safewrite(logfile, "\n", 1) < 0)
2241
        VIR_WARN(_("Unable to write argv to logfile: %s\n"),
2242
                 virStrerror(errno, ebuf, sizeof ebuf));
2243

2244
    if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
2245
        VIR_WARN(_("Unable to seek to end of logfile: %s\n"),
2246
                 virStrerror(errno, ebuf, sizeof ebuf));
2247

2248 2249 2250
    for (i = 0 ; i < ntapfds ; i++)
        FD_SET(tapfds[i], &keepfd);

2251
    ret = virExecDaemonize(conn, argv, progenv, &keepfd, &child,
2252
                           stdin_fd, &logfile, &logfile,
2253
                           VIR_EXEC_NONBLOCK | VIR_EXEC_CLEAR_CAPS,
2254 2255 2256
                           qemudSecurityHook, &hookData,
                           pidfile);
    VIR_FREE(pidfile);
G
Guido Günther 已提交
2257 2258 2259

    /* wait for qemu process to to show up */
    if (ret == 0) {
2260
        if (virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) {
2261
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
2262
                             _("Domain %s didn't show up\n"), vm->def->name);
2263
            ret = -1;
G
Guido Günther 已提交
2264
        }
2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275
    } 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;
    }
2276 2277

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

2279
    for (i = 0 ; argv[i] ; i++)
2280 2281
        VIR_FREE(argv[i]);
    VIR_FREE(argv);
2282

2283 2284 2285 2286
    for (i = 0 ; progenv[i] ; i++)
        VIR_FREE(progenv[i]);
    VIR_FREE(progenv);

2287 2288 2289
    if (tapfds) {
        for (i = 0 ; i < ntapfds ; i++) {
            close(tapfds[i]);
2290
        }
2291
        VIR_FREE(tapfds);
2292 2293
    }

2294
    if (ret == -1) /* The VM failed to start */
2295 2296
        goto cleanup;

2297 2298 2299
    if (qemudWaitForMonitor(conn, driver, vm, pos) < 0)
        goto abort;

2300
    if (qemuDetectVcpuPIDs(conn, driver, vm) < 0)
2301 2302
        goto abort;

2303
    if (qemudInitCpus(conn, driver, vm, migrateFrom) < 0)
2304 2305 2306 2307 2308
        goto abort;

    if (qemuInitPasswords(driver, vm) < 0)
        goto abort;

2309
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2310
    if (qemuMonitorSetBalloon(priv->mon, vm->def->memory) < 0) {
2311
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2312
        goto abort;
2313
    }
2314
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2315

2316 2317
    if (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)
        goto abort;
2318

2319
    return 0;
2320 2321

cleanup:
2322 2323 2324
    /* We jump here if we failed to start the VM for any reason
     * XXX investigate if we can kill this block and safely call
     * qemudShutdownVMDaemon even though no PID is running */
2325 2326 2327 2328 2329
    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);
    }
2330
    qemuRemoveCgroup(conn, driver, vm);
2331 2332 2333 2334
    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;
2335 2336
    if (logfile != -1)
        close(logfile);
2337 2338
    vm->def->id = -1;
    return -1;
2339 2340 2341 2342 2343 2344 2345 2346 2347 2348

abort:
    /* We jump here if we failed to initialize the now running VM
     * killing it off and pretend we never started it */
    qemudShutdownVMDaemon(conn, driver, vm);

    if (logfile != -1)
        close(logfile);

    return -1;
2349 2350 2351
}


2352
static void qemudShutdownVMDaemon(virConnectPtr conn,
2353 2354
                                  struct qemud_driver *driver,
                                  virDomainObjPtr vm) {
D
Daniel P. Berrange 已提交
2355
    int ret;
2356
    int retries = 0;
2357
    qemuDomainObjPrivatePtr priv = vm->privateData;
D
Daniel P. Berrange 已提交
2358

D
Daniel P. Berrange 已提交
2359
    if (!virDomainObjIsActive(vm))
2360
        return;
2361

2362
    VIR_DEBUG("Shutting down VM '%s'", vm->def->name);
2363

2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379
    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 已提交
2380 2381
    if (virKillProcess(vm->pid, 0) == 0 &&
        virKillProcess(vm->pid, SIGTERM) < 0)
2382 2383 2384
        virReportSystemError(conn, errno,
                             _("Failed to send SIGTERM to %s (%d)"),
                             vm->def->name, vm->pid);
2385

2386 2387 2388
    if (priv->mon) {
        qemuMonitorClose(priv->mon);
        priv->mon = NULL;
2389
    }
2390

2391 2392 2393 2394 2395 2396 2397
    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 已提交
2398 2399
    /* shut it off for sure */
    virKillProcess(vm->pid, SIGKILL);
2400

2401 2402 2403 2404
    /* Reset Security Labels */
    if (driver->securityDriver)
        driver->securityDriver->domainRestoreSecurityLabel(conn, vm);

2405 2406 2407 2408 2409 2410 2411
    /* 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);
    }

2412 2413 2414 2415
    if (qemuDomainSetAllDeviceOwnership(conn, driver, vm->def, 1) < 0)
        VIR_WARN("Failed to restore all device ownership for %s",
                 vm->def->name);

2416
    qemuDomainReAttachHostDevices(conn, driver, vm->def);
2417

2418 2419 2420 2421 2422 2423 2424 2425 2426 2427
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);
    }

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

2430
    vm->pid = -1;
2431
    vm->def->id = -1;
2432
    vm->state = VIR_DOMAIN_SHUTOFF;
2433
    VIR_FREE(vm->vcpupids);
2434
    vm->nvcpupids = 0;
2435 2436

    if (vm->newDef) {
2437
        virDomainDefFree(vm->def);
2438
        vm->def = vm->newDef;
2439
        vm->def->id = -1;
2440 2441 2442 2443 2444
        vm->newDef = NULL;
    }
}


2445
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
2446
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
2447
                                  int flags ATTRIBUTE_UNUSED) {
2448
    if (conn->uri == NULL) {
2449 2450 2451
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

2452
        conn->uri = xmlParseURI(qemu_driver->privileged ?
2453 2454
                                "qemu:///system" :
                                "qemu:///session");
2455
        if (!conn->uri) {
2456
            virReportOOMError(conn);
2457 2458
            return VIR_DRV_OPEN_ERROR;
        }
2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
    } 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;

2469 2470 2471 2472 2473 2474
        if (qemu_driver == NULL) {
            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                             _("qemu state driver is not active"));
            return VIR_DRV_OPEN_ERROR;
        }

2475
        if (qemu_driver->privileged) {
2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490
            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;
            }
        }
2491 2492 2493 2494 2495 2496 2497
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
2498
    struct qemud_driver *driver = conn->privateData;
2499 2500

    /* Get rid of callbacks registered for this conn */
2501
    qemuDriverLock(driver);
2502
    virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
2503
    qemuDriverUnlock(driver);
2504 2505 2506 2507 2508 2509

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
2510 2511 2512 2513 2514
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
2515 2516 2517 2518 2519
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
2520 2521 2522
    }
}

2523
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
2524
    return "QEMU";
2525 2526
}

2527

2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540
static int qemuIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}

static int qemuIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


2541 2542 2543 2544
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
2545

2546 2547
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
2548 2549
        virReportSystemError(NULL, errno, _("Unable to open %s"), KVM_DEVICE);
        return -1;
2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560
    }

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

    close(fd);
    return maxvcpus;
}


2561
static int qemudGetMaxVCPUs(virConnectPtr conn, const char *type) {
2562 2563 2564
    if (!type)
        return 16;

2565
    if (STRCASEEQ(type, "qemu"))
2566 2567
        return 16;

2568
    if (STRCASEEQ(type, "kvm"))
2569
        return kvmGetMaxVCPUs();
2570

2571
    if (STRCASEEQ(type, "kqemu"))
2572
        return 1;
2573 2574 2575

    qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
                     _("unknown type '%s'"), type);
2576 2577 2578
    return -1;
}

2579

2580
static char *qemudGetCapabilities(virConnectPtr conn) {
2581
    struct qemud_driver *driver = conn->privateData;
2582
    virCapsPtr caps;
2583
    char *xml = NULL;
2584

2585
    qemuDriverLock(driver);
2586
    if ((caps = qemudCapsInit(qemu_driver->caps)) == NULL) {
2587 2588 2589 2590
        virReportOOMError(conn);
        goto cleanup;
    }

2591 2592 2593
    caps->privateDataAllocFunc = qemuDomainObjPrivateAlloc;
    caps->privateDataFreeFunc = qemuDomainObjPrivateFree;

2594 2595 2596 2597 2598 2599 2600
    if (qemu_driver->securityDriver &&
        qemudSecurityCapsInit(qemu_driver->securityDriver, caps) < 0) {
        virCapabilitiesFree(caps);
        virReportOOMError(conn);
        goto cleanup;
    }

2601
    virCapabilitiesFree(qemu_driver->caps);
2602 2603 2604
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
2605
        virReportOOMError(conn);
2606 2607

cleanup:
2608
    qemuDriverUnlock(driver);
2609

2610
    return xml;
2611 2612 2613
}


2614
static int qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid, int tid) {
D
Daniel P. Berrange 已提交
2615 2616
    char proc[PATH_MAX];
    FILE *pidinfo;
2617
    unsigned long long usertime, systime;
2618 2619
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
2620

2621 2622 2623 2624 2625 2626
    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 已提交
2627 2628 2629 2630
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
2631
        /*printf("cannot read pid info");*/
D
Daniel P. Berrange 已提交
2632
        /* VM probably shut down, so fake 0 */
2633 2634 2635 2636
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
D
Daniel P. Berrange 已提交
2637 2638 2639
        return 0;
    }

2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
    /* 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) {
2650
        fclose(pidinfo);
2651 2652
        VIR_WARN0("cannot parse process status data");
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
2653 2654 2655 2656 2657 2658 2659 2660
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
2661 2662 2663 2664 2665
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

D
Daniel P. Berrange 已提交
2666

2667 2668
    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
              pid, tid, usertime, systime, cpu);
D
Daniel P. Berrange 已提交
2669 2670 2671 2672 2673 2674 2675

    fclose(pidinfo);

    return 0;
}


2676
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
2677
                                          int id) {
2678 2679 2680 2681
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

2682
    qemuDriverLock(driver);
2683
    vm  = virDomainFindByID(&driver->domains, id);
2684
    qemuDriverUnlock(driver);
2685 2686

    if (!vm) {
2687 2688
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching id %d"), id);
2689
        goto cleanup;
2690 2691
    }

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

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

2701
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
2702
                                            const unsigned char *uuid) {
2703 2704 2705
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
2706

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

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

2719
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2720
    if (dom) dom->id = vm->def->id;
2721 2722

cleanup:
2723 2724
    if (vm)
        virDomainObjUnlock(vm);
2725 2726
    return dom;
}
2727

2728
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
2729
                                            const char *name) {
2730 2731 2732
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
2733

2734
    qemuDriverLock(driver);
2735
    vm = virDomainFindByName(&driver->domains, name);
2736 2737
    qemuDriverUnlock(driver);

2738
    if (!vm) {
2739 2740
        qemudReportError(conn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                         _("no domain with matching name '%s'"), name);
2741
        goto cleanup;
2742 2743
    }

2744
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2745
    if (dom) dom->id = vm->def->id;
2746 2747

cleanup:
2748 2749
    if (vm)
        virDomainObjUnlock(vm);
2750 2751 2752
    return dom;
}

2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796

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

    qemuDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!obj) {
        qemudReportError(dom->conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

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

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

    qemuDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!obj) {
        qemudReportError(dom->conn, NULL, NULL, VIR_ERR_NO_DOMAIN, NULL);
        goto cleanup;
    }
    ret = obj->persistent;

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


2797
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
2798 2799 2800
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

2801
    qemuDriverLock(driver);
2802
    if (qemudExtractVersion(conn, driver) < 0)
2803
        goto cleanup;
2804

2805
    *version = qemu_driver->qemuVersion;
2806 2807 2808
    ret = 0;

cleanup:
2809
    qemuDriverUnlock(driver);
2810
    return ret;
D
Daniel P. Berrange 已提交
2811 2812
}

2813
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
2814
    struct qemud_driver *driver = conn->privateData;
2815
    int n;
2816

2817
    qemuDriverLock(driver);
2818
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
2819
    qemuDriverUnlock(driver);
2820

2821
    return n;
D
Daniel P. Berrange 已提交
2822
}
2823

2824
static int qemudNumDomains(virConnectPtr conn) {
2825
    struct qemud_driver *driver = conn->privateData;
2826
    int n;
2827

2828
    qemuDriverLock(driver);
2829
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
2830
    qemuDriverUnlock(driver);
2831

2832
    return n;
D
Daniel P. Berrange 已提交
2833
}
2834

2835
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
2836
                                      unsigned int flags ATTRIBUTE_UNUSED) {
2837
    struct qemud_driver *driver = conn->privateData;
2838
    virDomainDefPtr def;
2839
    virDomainObjPtr vm = NULL;
2840
    virDomainPtr dom = NULL;
2841
    virDomainEventPtr event = NULL;
D
Daniel P. Berrange 已提交
2842

2843
    qemuDriverLock(driver);
2844 2845
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE)))
2846
        goto cleanup;
2847

2848 2849 2850
    if (virSecurityDriverVerify(conn, def) < 0)
        goto cleanup;

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

2854
    if (!(vm = virDomainAssignDef(conn,
2855
                                  driver->caps,
2856
                                  &driver->domains,
2857 2858 2859 2860
                                  def)))
        goto cleanup;

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

2862 2863 2864
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup; /* XXXX free the 'vm' we created ? */

2865
    if (qemudStartVMDaemon(conn, driver, vm, NULL, -1) < 0) {
2866
        qemuDomainObjEndJob(vm);
2867 2868
        virDomainRemoveInactive(&driver->domains,
                                vm);
2869
        vm = NULL;
2870
        goto endjob;
D
Daniel P. Berrange 已提交
2871
    }
2872 2873 2874 2875

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

2877
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
2878
    if (dom) dom->id = vm->def->id;
2879

2880 2881 2882 2883
endjob:
    if (vm)
        qemuDomainObjEndJob(vm);

2884 2885
cleanup:
    virDomainDefFree(def);
2886 2887
    if (vm)
        virDomainObjUnlock(vm);
2888 2889
    if (event)
        qemuDomainEventQueue(driver, event);
2890
    qemuDriverUnlock(driver);
2891
    return dom;
D
Daniel P. Berrange 已提交
2892 2893 2894
}


2895
static int qemudDomainSuspend(virDomainPtr dom) {
2896 2897 2898
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2899
    virDomainEventPtr event = NULL;
2900

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

D
Daniel P. Berrange 已提交
2904
    if (!vm) {
2905 2906 2907 2908
        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);
2909
        goto cleanup;
D
Daniel P. Berrange 已提交
2910
    }
2911 2912 2913
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
2914
    if (!virDomainObjIsActive(vm)) {
2915
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2916
                         "%s", _("domain is not running"));
2917
        goto endjob;
D
Daniel P. Berrange 已提交
2918
    }
2919
    if (vm->state != VIR_DOMAIN_PAUSED) {
2920
        qemuDomainObjPrivatePtr priv = vm->privateData;
2921
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
2922
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
2923 2924
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto endjob;
2925
        }
2926
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2927
        vm->state = VIR_DOMAIN_PAUSED;
2928 2929 2930
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
D
Daniel P. Berrange 已提交
2931
    }
2932
    if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
2933
        goto endjob;
2934 2935
    ret = 0;

2936 2937 2938
endjob:
    qemuDomainObjEndJob(vm);

2939
cleanup:
2940 2941
    if (vm)
        virDomainObjUnlock(vm);
2942

2943
    if (event)
2944
        qemuDomainEventQueue(driver, event);
2945
    qemuDriverUnlock(driver);
2946
    return ret;
D
Daniel P. Berrange 已提交
2947 2948 2949
}


2950
static int qemudDomainResume(virDomainPtr dom) {
2951 2952 2953
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2954
    virDomainEventPtr event = NULL;
2955

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

D
Daniel P. Berrange 已提交
2959
    if (!vm) {
2960 2961 2962 2963
        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);
2964
        goto cleanup;
D
Daniel P. Berrange 已提交
2965
    }
2966 2967 2968 2969

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

D
Daniel P. Berrange 已提交
2970
    if (!virDomainObjIsActive(vm)) {
2971
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
2972
                         "%s", _("domain is not running"));
2973
        goto endjob;
D
Daniel P. Berrange 已提交
2974
    }
2975
    if (vm->state == VIR_DOMAIN_PAUSED) {
2976
        qemuDomainObjPrivatePtr priv = vm->privateData;
2977
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
2978
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
2979
            qemuDomainObjExitMonitorWithDriver(driver, vm);
2980 2981 2982
            if (virGetLastError() == NULL)
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("resume operation failed"));
2983
            goto endjob;
2984
        }
2985
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2986
        vm->state = VIR_DOMAIN_RUNNING;
2987 2988 2989
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
2990
    }
2991
    if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
2992
        goto endjob;
2993 2994
    ret = 0;

2995 2996 2997
endjob:
    qemuDomainObjEndJob(vm);

2998
cleanup:
2999 3000
    if (vm)
        virDomainObjUnlock(vm);
3001
    if (event)
3002
        qemuDomainEventQueue(driver, event);
3003
    qemuDriverUnlock(driver);
3004
    return ret;
D
Daniel P. Berrange 已提交
3005 3006 3007
}


3008
static int qemudDomainShutdown(virDomainPtr dom) {
3009 3010 3011
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
3012

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

3017
    if (!vm) {
3018 3019 3020 3021
        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);
3022
        goto cleanup;
3023 3024
    }

3025 3026 3027
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3028
    if (!virDomainObjIsActive(vm)) {
3029 3030
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
3031
        goto endjob;
3032 3033
    }

3034
    qemuDomainObjPrivatePtr priv = vm->privateData;
3035 3036 3037
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorSystemPowerdown(priv->mon);
    qemuDomainObjExitMonitor(vm);
3038

3039 3040 3041
endjob:
    qemuDomainObjEndJob(vm);

3042
cleanup:
3043 3044
    if (vm)
        virDomainObjUnlock(vm);
3045
    return ret;
3046 3047 3048
}


3049
static int qemudDomainDestroy(virDomainPtr dom) {
3050 3051 3052
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
3053
    virDomainEventPtr event = NULL;
3054

3055
    qemuDriverLock(driver);
3056
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
3057
    if (!vm) {
3058 3059 3060 3061
        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);
3062
        goto cleanup;
D
Daniel P. Berrange 已提交
3063
    }
3064 3065 3066 3067

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

D
Daniel P. Berrange 已提交
3068
    if (!virDomainObjIsActive(vm)) {
3069
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3070
                         "%s", _("domain is not running"));
3071
        goto endjob;
3072
    }
3073

3074
    qemudShutdownVMDaemon(dom->conn, driver, vm);
3075 3076 3077
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
3078
    if (!vm->persistent) {
3079
        qemuDomainObjEndJob(vm);
3080 3081
        virDomainRemoveInactive(&driver->domains,
                                vm);
3082 3083
        vm = NULL;
    }
3084 3085
    ret = 0;

3086 3087 3088 3089
endjob:
    if (vm)
        qemuDomainObjEndJob(vm);

3090
cleanup:
3091 3092
    if (vm)
        virDomainObjUnlock(vm);
3093 3094
    if (event)
        qemuDomainEventQueue(driver, event);
3095
    qemuDriverUnlock(driver);
3096
    return ret;
D
Daniel P. Berrange 已提交
3097 3098 3099
}


3100
static char *qemudDomainGetOSType(virDomainPtr dom) {
3101 3102 3103
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
3104

3105
    qemuDriverLock(driver);
3106
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3107
    qemuDriverUnlock(driver);
3108
    if (!vm) {
3109 3110 3111 3112
        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);
3113
        goto cleanup;
3114 3115
    }

3116
    if (!(type = strdup(vm->def->os.type)))
3117
        virReportOOMError(dom->conn);
3118 3119

cleanup:
3120 3121
    if (vm)
        virDomainObjUnlock(vm);
3122 3123 3124
    return type;
}

3125 3126
/* Returns max memory in kb, 0 if error */
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
3127 3128 3129
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
3130

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

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

3143 3144 3145
    ret = vm->def->maxmem;

cleanup:
3146 3147
    if (vm)
        virDomainObjUnlock(vm);
3148
    return ret;
3149 3150 3151
}

static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
3152 3153 3154
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
3155

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

3160
    if (!vm) {
3161 3162
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3163
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
3164
                         _("no domain with matching uuid '%s'"), uuidstr);
3165
        goto cleanup;
3166 3167 3168 3169
    }

    if (newmax < vm->def->memory) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
3170
                         "%s", _("cannot set max memory lower than current memory"));
3171
        goto cleanup;;
3172 3173 3174
    }

    vm->def->maxmem = newmax;
3175 3176 3177
    ret = 0;

cleanup:
3178 3179
    if (vm)
        virDomainObjUnlock(vm);
3180
    return ret;
3181 3182
}

3183

3184
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
3185 3186 3187
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
3188

3189
    qemuDriverLock(driver);
3190
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3191
    qemuDriverUnlock(driver);
3192
    if (!vm) {
3193 3194
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3195
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
3196
                         _("no domain with matching uuid '%s'"), uuidstr);
3197
        goto cleanup;
3198 3199 3200 3201
    }

    if (newmem > vm->def->maxmem) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
3202
                         "%s", _("cannot set memory higher than max memory"));
3203
        goto cleanup;
3204 3205
    }

3206 3207 3208
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3209
    if (virDomainObjIsActive(vm)) {
3210
        qemuDomainObjPrivatePtr priv = vm->privateData;
3211
        qemuDomainObjEnterMonitor(vm);
3212
        int r = qemuMonitorSetBalloon(priv->mon, newmem);
3213
        qemuDomainObjExitMonitor(vm);
3214
        if (r < 0)
3215
            goto endjob;
3216 3217 3218

        /* Lack of balloon support is a fatal error */
        if (r == 0) {
3219 3220
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                             "%s", _("cannot set memory of an active domain"));
3221
            goto endjob;
3222
        }
3223 3224 3225
    } else {
        vm->def->memory = newmem;
    }
3226
    ret = 0;
3227

3228 3229 3230
endjob:
    qemuDomainObjEndJob(vm);

3231
cleanup:
3232 3233
    if (vm)
        virDomainObjUnlock(vm);
3234
    return ret;
3235 3236
}

3237
static int qemudDomainGetInfo(virDomainPtr dom,
3238
                              virDomainInfoPtr info) {
3239 3240 3241
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
3242 3243
    int err;
    unsigned long balloon;
3244

3245
    qemuDriverLock(driver);
3246
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3247
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
3248
    if (!vm) {
3249 3250 3251 3252
        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);
3253
        goto cleanup;
D
Daniel P. Berrange 已提交
3254 3255
    }

3256
    info->state = vm->state;
D
Daniel P. Berrange 已提交
3257

D
Daniel P. Berrange 已提交
3258
    if (!virDomainObjIsActive(vm)) {
3259
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
3260
    } else {
3261
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
3262
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, ("cannot read cputime for domain"));
3263
            goto cleanup;
D
Daniel P. Berrange 已提交
3264 3265 3266
        }
    }

3267
    info->maxMem = vm->def->maxmem;
3268

D
Daniel P. Berrange 已提交
3269
    if (virDomainObjIsActive(vm)) {
3270
        qemuDomainObjPrivatePtr priv = vm->privateData;
3271 3272 3273
        if (!priv->jobActive) {
            if (qemuDomainObjBeginJob(vm) < 0)
                goto cleanup;
3274

3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292
            qemuDomainObjEnterMonitor(vm);
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
            qemuDomainObjExitMonitor(vm);
            if (err < 0) {
                qemuDomainObjEndJob(vm);
                goto cleanup;
            }

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

            qemuDomainObjEndJob(vm);
        } else {
            info->memory = vm->def->memory;
        }
3293 3294 3295 3296
    } else {
        info->memory = vm->def->memory;
    }

3297
    info->nrVirtCpu = vm->def->vcpus;
3298 3299 3300
    ret = 0;

cleanup:
3301 3302
    if (vm)
        virDomainObjUnlock(vm);
3303
    return ret;
D
Daniel P. Berrange 已提交
3304 3305 3306
}


3307
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
3308 3309 3310
#define QEMUD_SAVE_VERSION 2

enum qemud_save_formats {
3311 3312 3313
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
3314 3315
    /*
     * Deprecated by xz and never used as part of a release
3316
     * QEMUD_SAVE_FORMAT_LZMA
3317 3318
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
3319
    QEMUD_SAVE_FORMAT_LZOP = 4,
3320 3321 3322
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
3323 3324

    QEMUD_SAVE_FORMAT_LAST
3325
};
3326

3327 3328 3329 3330 3331
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
3332 3333
              "xz",
              "lzop")
3334

3335 3336 3337 3338 3339
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
    int version;
    int xml_len;
    int was_running;
3340 3341
    int compressed;
    int unused[15];
3342 3343
};

3344
static int qemudDomainSave(virDomainPtr dom,
3345 3346
                           const char *path)
{
3347
    struct qemud_driver *driver = dom->conn->privateData;
3348
    virDomainObjPtr vm = NULL;
3349 3350
    int fd = -1;
    char *xml = NULL;
3351
    struct qemud_save_header header;
3352
    int ret = -1;
3353
    int rc;
3354
    virDomainEventPtr event = NULL;
3355 3356 3357 3358 3359

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

3360
    qemuDriverLock(driver);
3361 3362 3363
    if (driver->saveImageFormat == NULL)
        header.compressed = QEMUD_SAVE_FORMAT_RAW;
    else {
3364 3365 3366 3367 3368 3369
        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"));
3370
            goto cleanup;
3371
        }
3372 3373
    }

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

D
Daniel P. Berrange 已提交
3376
    if (!vm) {
3377 3378 3379 3380
        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);
3381
        goto cleanup;
D
Daniel P. Berrange 已提交
3382
    }
3383

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

D
Daniel P. Berrange 已提交
3387
    if (!virDomainObjIsActive(vm)) {
3388
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3389
                         "%s", _("domain is not running"));
3390
        goto endjob;
D
Daniel P. Berrange 已提交
3391
    }
3392 3393 3394

    /* Pause */
    if (vm->state == VIR_DOMAIN_RUNNING) {
3395
        qemuDomainObjPrivatePtr priv = vm->privateData;
3396
        header.was_running = 1;
3397
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
3398
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
3399 3400
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto endjob;
3401
        }
3402
        qemuDomainObjExitMonitorWithDriver(driver, vm);
3403
        vm->state = VIR_DOMAIN_PAUSED;
3404 3405 3406
    }

    /* Get XML for the domain */
3407
    xml = virDomainDefFormat(dom->conn, vm->def, VIR_DOMAIN_XML_SECURE);
3408 3409
    if (!xml) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
3410
                         "%s", _("failed to get domain xml"));
3411
        goto endjob;
3412 3413 3414 3415 3416 3417
    }
    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,
3418
                         _("failed to create '%s'"), path);
3419
        goto endjob;
3420 3421 3422 3423
    }

    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
3424
                         "%s", _("failed to write save header"));
3425
        goto endjob;
3426 3427 3428 3429
    }

    if (safewrite(fd, xml, header.xml_len) != header.xml_len) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
3430
                         "%s", _("failed to write xml"));
3431
        goto endjob;
3432 3433
    }

3434
    if (close(fd) < 0) {
3435 3436 3437
        virReportSystemError(dom->conn, errno,
                             _("unable to save file %s"),
                             path);
3438
        goto endjob;
3439 3440
    }
    fd = -1;
3441

3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454
    if (driver->privileged &&
        chown(path, driver->user, driver->group) < 0) {
        virReportSystemError(NULL, errno,
                             _("unable to set ownership of '%s' to user %d:%d"),
                             path, driver->user, driver->group);
        goto endjob;
    }

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSavedStateLabel &&
        driver->securityDriver->domainSetSavedStateLabel(dom->conn, vm, path) == -1)
        goto endjob;

3455 3456
    if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = { "cat", NULL };
3457
        qemuDomainObjPrivatePtr priv = vm->privateData;
3458
        qemuDomainObjEnterMonitor(vm);
3459
        rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
3460
        qemuDomainObjExitMonitor(vm);
3461
    } else {
3462
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
3463
        qemuDomainObjPrivatePtr priv = vm->privateData;
3464 3465 3466 3467 3468
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
3469
        qemuDomainObjEnterMonitor(vm);
3470
        rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
3471
        qemuDomainObjExitMonitor(vm);
3472 3473
    }

3474
    if (rc < 0)
3475
        goto endjob;
3476

3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491
    if (driver->privileged &&
        chown(path, 0, 0) < 0) {
        virReportSystemError(NULL, errno,
                             _("unable to set ownership of '%s' to user %d:%d"),
                             path, 0, 0);
        goto endjob;
    }

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSavedStateLabel &&
        driver->securityDriver->domainRestoreSavedStateLabel(dom->conn, path) == -1)
        goto endjob;

    ret = 0;

3492 3493
    /* Shut it down */
    qemudShutdownVMDaemon(dom->conn, driver, vm);
3494 3495 3496
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
3497
    if (!vm->persistent) {
3498
        qemuDomainObjEndJob(vm);
3499 3500
        virDomainRemoveInactive(&driver->domains,
                                vm);
3501 3502
        vm = NULL;
    }
3503

3504 3505 3506 3507
endjob:
    if (vm)
        qemuDomainObjEndJob(vm);

3508 3509 3510 3511 3512 3513
cleanup:
    if (fd != -1)
        close(fd);
    VIR_FREE(xml);
    if (ret != 0)
        unlink(path);
3514 3515
    if (vm)
        virDomainObjUnlock(vm);
3516 3517
    if (event)
        qemuDomainEventQueue(driver, event);
3518
    qemuDriverUnlock(driver);
3519
    return ret;
D
Daniel P. Berrange 已提交
3520 3521 3522
}


P
Paolo Bonzini 已提交
3523 3524 3525 3526 3527 3528 3529
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;
3530 3531 3532 3533
    const char *args[] = {
        "cat",
        NULL,
    };
P
Paolo Bonzini 已提交
3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546

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

3547 3548 3549
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3550
    if (!virDomainObjIsActive(vm)) {
P
Paolo Bonzini 已提交
3551 3552
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
3553
        goto endjob;
P
Paolo Bonzini 已提交
3554 3555 3556 3557 3558 3559 3560
    }

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

3561 3562
    qemuDomainObjPrivatePtr priv = vm->privateData;

P
Paolo Bonzini 已提交
3563 3564
    /* Pause domain for non-live dump */
    if (vm->state == VIR_DOMAIN_RUNNING) {
3565 3566 3567
        qemuDomainObjEnterMonitor(vm);
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
            qemuDomainObjExitMonitor(vm);
3568
            goto endjob;
3569 3570
        }
        qemuDomainObjExitMonitor(vm);
P
Paolo Bonzini 已提交
3571 3572 3573
        paused = 1;
    }

3574
    qemuDomainObjEnterMonitor(vm);
3575
    ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
3576
    qemuDomainObjExitMonitor(vm);
P
Paolo Bonzini 已提交
3577 3578 3579 3580 3581 3582
    paused = 1;

    /* 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) {
3583
        qemuDomainObjEnterMonitor(vm);
3584
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
3585 3586 3587
            if (virGetLastError() == NULL)
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3588
        }
3589
        qemuDomainObjExitMonitor(vm);
P
Paolo Bonzini 已提交
3590
    }
3591 3592 3593 3594 3595

endjob:
    qemuDomainObjEndJob(vm);

cleanup:
P
Paolo Bonzini 已提交
3596 3597 3598 3599 3600 3601
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


3602
static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
3603 3604
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3605
    int max;
3606
    int ret = -1;
3607
    const char *type;
3608

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

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

3621 3622 3623
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3624
    if (virDomainObjIsActive(vm)) {
3625
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID, "%s",
3626
                         _("cannot change vcpu count of an active domain"));
3627
        goto endjob;
3628 3629
    }

3630 3631 3632 3633
    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);
3634
        goto endjob;
3635 3636 3637
    }

    if ((max = qemudGetMaxVCPUs(dom->conn, type)) < 0) {
3638 3639
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
                         _("could not determine max vcpus for the domain"));
3640
        goto endjob;
3641 3642 3643 3644 3645 3646
    }

    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);
3647
        goto endjob;
3648 3649 3650
    }

    vm->def->vcpus = nvcpus;
3651 3652
    ret = 0;

3653 3654 3655
endjob:
    qemuDomainObjEndJob(vm);

3656
cleanup:
3657 3658
    if (vm)
        virDomainObjUnlock(vm);
3659
    return ret;
3660 3661
}

3662 3663 3664 3665 3666 3667 3668

#if HAVE_SCHED_GETAFFINITY
static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
3669 3670
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3671
    cpu_set_t mask;
3672
    int i, maxcpu, hostcpus;
3673
    virNodeInfo nodeinfo;
3674
    int ret = -1;
3675

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

3680 3681 3682 3683 3684 3685 3686 3687
    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 已提交
3688
    if (!virDomainObjIsActive(vm)) {
3689
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3690
                         "%s",_("cannot pin vcpus on an inactive domain"));
3691
        goto cleanup;
3692 3693 3694 3695 3696 3697
    }

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

3701
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
3702
        goto cleanup;
3703

3704
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
3705
    maxcpu = maplen * 8;
3706 3707
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
3708 3709 3710

    CPU_ZERO(&mask);
    for (i = 0 ; i < maxcpu ; i++) {
3711
        if (VIR_CPU_USABLE(cpumap, maplen, 0, i))
3712 3713 3714 3715 3716
            CPU_SET(i, &mask);
    }

    if (vm->vcpupids != NULL) {
        if (sched_setaffinity(vm->vcpupids[vcpu], sizeof(mask), &mask) < 0) {
3717 3718
            virReportSystemError(dom->conn, errno, "%s",
                                 _("cannot set affinity"));
3719
            goto cleanup;
3720 3721 3722 3723
        }
    } else {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         "%s", _("cpu affinity is not supported"));
3724
        goto cleanup;
3725
    }
3726
    ret = 0;
3727

3728
cleanup:
3729 3730
    if (vm)
        virDomainObjUnlock(vm);
3731
    return ret;
3732 3733 3734 3735 3736 3737 3738 3739
}

static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
3740 3741
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3742
    virNodeInfo nodeinfo;
3743
    int i, v, maxcpu, hostcpus;
3744
    int ret = -1;
3745

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

3750 3751 3752 3753 3754 3755 3756 3757
    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 已提交
3758
    if (!virDomainObjIsActive(vm)) {
3759
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
3760 3761
                         "%s",
                         _("cannot list vcpu pinning for an inactive domain"));
3762
        goto cleanup;
3763 3764
    }

3765
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
3766
        goto cleanup;
3767

3768
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
3769
    maxcpu = maplen * 8;
3770 3771
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
3772 3773 3774 3775 3776

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

3777 3778 3779 3780 3781 3782
    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;
3783 3784 3785 3786 3787 3788 3789 3790 3791 3792

                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;
                }
3793
            }
3794 3795
        }

3796 3797 3798 3799 3800 3801 3802 3803 3804
        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) {
3805 3806
                        virReportSystemError(dom->conn, errno, "%s",
                                             _("cannot get affinity"));
3807 3808 3809 3810 3811 3812
                        goto cleanup;
                    }

                    for (i = 0 ; i < maxcpu ; i++)
                        if (CPU_ISSET(i, &mask))
                            VIR_USE_CPU(cpumap, i);
3813
                }
3814 3815 3816 3817
            } else {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                                 "%s", _("cpu affinity is not available"));
                goto cleanup;
3818 3819 3820
            }
        }
    }
3821
    ret = maxinfo;
3822

3823
cleanup:
3824 3825
    if (vm)
        virDomainObjUnlock(vm);
3826
    return ret;
3827 3828 3829 3830
}
#endif /* HAVE_SCHED_GETAFFINITY */


3831
static int qemudDomainGetMaxVcpus(virDomainPtr dom) {
3832 3833
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3834
    const char *type;
3835
    int ret = -1;
3836

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

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

3849
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
3850 3851 3852
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         _("unknown virt type in domain definition '%d'"),
                         vm->def->virtType);
3853
        goto cleanup;
3854 3855
    }

3856
    ret = qemudGetMaxVCPUs(dom->conn, type);
3857

3858
cleanup:
3859 3860
    if (vm)
        virDomainObjUnlock(vm);
3861 3862 3863
    return ret;
}

3864 3865 3866 3867 3868 3869 3870 3871 3872 3873
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);

3874 3875
    memset(seclabel, 0, sizeof(*seclabel));

3876 3877 3878
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3879
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904
                         _("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 已提交
3905
    if (virDomainObjIsActive(vm)) {
3906 3907 3908
        if (driver->securityDriver && driver->securityDriver->domainGetSecurityLabel) {
            if (driver->securityDriver->domainGetSecurityLabel(dom->conn, vm, seclabel) == -1) {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
3909
                                 "%s", _("Failed to get security label"));
3910 3911 3912 3913 3914 3915 3916 3917 3918 3919
                goto cleanup;
            }
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
3920
    qemuDriverUnlock(driver);
3921 3922 3923
    return ret;
}

3924 3925
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
3926 3927 3928
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
3929
    int ret = 0;
3930

3931 3932
    qemuDriverLock(driver);
    if (!driver->securityDriver) {
3933
        memset(secmodel, 0, sizeof (*secmodel));
3934 3935
        goto cleanup;
    }
3936

3937 3938 3939 3940 3941
    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);
3942 3943
        ret = -1;
        goto cleanup;
3944 3945 3946 3947 3948 3949 3950 3951
    }
    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);
3952 3953
        ret = -1;
        goto cleanup;
3954 3955
    }
    strcpy(secmodel->doi, p);
3956 3957 3958 3959

cleanup:
    qemuDriverUnlock(driver);
    return ret;
3960 3961 3962
}

/* TODO: check seclabel restore */
3963
static int qemudDomainRestore(virConnectPtr conn,
3964 3965 3966
                              const char *path) {
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
3967
    virDomainObjPtr vm = NULL;
3968 3969 3970
    int fd = -1;
    int ret = -1;
    char *xml = NULL;
3971
    struct qemud_save_header header;
3972
    virDomainEventPtr event = NULL;
3973 3974 3975
    int intermediatefd = -1;
    pid_t intermediate_pid = -1;
    int childstat;
3976

3977
    qemuDriverLock(driver);
3978 3979 3980
    /* Verify the header and read the XML */
    if ((fd = open(path, O_RDONLY)) < 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3981
                         "%s", _("cannot read domain image"));
3982
        goto cleanup;
3983 3984 3985 3986
    }

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3987
                         "%s", _("failed to read qemu header"));
3988
        goto cleanup;
3989 3990 3991 3992
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3993
                         "%s", _("image magic is incorrect"));
3994
        goto cleanup;
3995 3996 3997 3998
    }

    if (header.version > QEMUD_SAVE_VERSION) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
3999
                         _("image version is not supported (%d > %d)"),
4000
                         header.version, QEMUD_SAVE_VERSION);
4001
        goto cleanup;
4002 4003
    }

4004
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
4005
        virReportOOMError(conn);
4006
        goto cleanup;
4007 4008 4009 4010
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4011
                         "%s", _("failed to read XML"));
4012
        goto cleanup;
4013 4014 4015
    }

    /* Create a domain from this XML */
4016 4017
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE))) {
4018
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4019
                         "%s", _("failed to parse XML"));
4020
        goto cleanup;
4021 4022
    }

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

4026
    if (!(vm = virDomainAssignDef(conn,
4027
                                  driver->caps,
4028 4029
                                  &driver->domains,
                                  def))) {
4030
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4031
                         "%s", _("failed to assign new VM"));
4032
        goto cleanup;
4033
    }
4034
    def = NULL;
4035

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

4039 4040
    if (header.version == 2) {
        const char *intermediate_argv[3] = { NULL, "-dc", NULL };
4041 4042
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
        if (prog == NULL) {
4043
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4044
                             _("Invalid compressed save format %d"),
4045
                             header.compressed);
4046
            goto endjob;
4047
        }
4048

4049
        if (header.compressed != QEMUD_SAVE_FORMAT_RAW) {
4050
            intermediate_argv[0] = prog;
4051 4052 4053 4054 4055 4056 4057
            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]);
4058
                goto endjob;
4059 4060 4061
            }
        }
    }
4062
    /* Set the migration source and start it up. */
4063
    ret = qemudStartVMDaemon(conn, driver, vm, "stdio", fd);
4064 4065 4066 4067 4068 4069 4070
    if (intermediate_pid != -1) {
        /* Wait for intermediate process to exit */
        while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
               errno == EINTR);
    }
    if (intermediatefd != -1)
        close(intermediatefd);
4071
    close(fd);
4072
    fd = -1;
4073
    if (ret < 0) {
4074
        if (!vm->persistent) {
4075
            qemuDomainObjEndJob(vm);
4076 4077
            virDomainRemoveInactive(&driver->domains,
                                    vm);
4078 4079
            vm = NULL;
        }
4080
        goto endjob;
4081 4082
    }

4083 4084 4085
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
4086

4087 4088
    /* If it was running before, resume it now. */
    if (header.was_running) {
4089
        qemuDomainObjPrivatePtr priv = vm->privateData;
4090
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4091
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
4092 4093 4094
            if (virGetLastError() == NULL)
                qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                                 "%s", _("failed to resume domain"));
4095 4096
            qemuDomainObjExitMonitorWithDriver(driver,vm);
            goto endjob;
4097
        }
4098
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4099
        vm->state = VIR_DOMAIN_RUNNING;
4100
        virDomainSaveStatus(conn, driver->stateDir, vm);
4101
    }
4102
    ret = 0;
4103

4104 4105 4106 4107
endjob:
    if (vm)
        qemuDomainObjEndJob(vm);

4108 4109 4110 4111 4112
cleanup:
    virDomainDefFree(def);
    VIR_FREE(xml);
    if (fd != -1)
        close(fd);
4113 4114
    if (vm)
        virDomainObjUnlock(vm);
4115 4116
    if (event)
        qemuDomainEventQueue(driver, event);
4117
    qemuDriverUnlock(driver);
4118
    return ret;
D
Daniel P. Berrange 已提交
4119 4120 4121
}


4122
static char *qemudDomainDumpXML(virDomainPtr dom,
4123
                                int flags) {
4124 4125 4126
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
4127 4128
    unsigned long balloon;
    int err;
4129

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

D
Daniel P. Berrange 已提交
4134
    if (!vm) {
4135 4136 4137 4138
        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);
4139
        goto cleanup;
D
Daniel P. Berrange 已提交
4140 4141
    }

4142
    /* Refresh current memory based on balloon info */
D
Daniel P. Berrange 已提交
4143
    if (virDomainObjIsActive(vm)) {
4144
        qemuDomainObjPrivatePtr priv = vm->privateData;
4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
        if (!priv->jobActive) {
            if (qemuDomainObjBeginJob(vm) < 0)
                goto cleanup;

            qemuDomainObjEnterMonitor(vm);
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
            qemuDomainObjExitMonitor(vm);
            qemuDomainObjEndJob(vm);
            if (err < 0)
                goto cleanup;
            if (err > 0)
                vm->def->memory = balloon;
            /* err == 0 indicates no balloon support, so ignore it */
        }
4161
    }
4162

4163 4164 4165 4166 4167 4168
    ret = virDomainDefFormat(dom->conn,
                             (flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef ?
                             vm->newDef : vm->def,
                             flags);

cleanup:
4169 4170
    if (vm)
        virDomainObjUnlock(vm);
4171
    return ret;
D
Daniel P. Berrange 已提交
4172 4173 4174
}


4175 4176 4177 4178
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
                                     unsigned int flags ATTRIBUTE_UNUSED) {
4179
    struct qemud_driver *driver = conn->privateData;
4180 4181 4182 4183 4184 4185 4186 4187 4188
    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;
    }

4189
    qemuDriverLock(driver);
4190
    def = qemuParseCommandLineString(conn, driver->caps, config);
4191
    qemuDriverUnlock(driver);
4192 4193 4194 4195 4196 4197 4198 4199 4200 4201
    if (!def)
        goto cleanup;

    xml = virDomainDefFormat(conn, def, VIR_DOMAIN_XML_INACTIVE);

cleanup:
    virDomainDefFree(def);
    return xml;
}

4202 4203 4204 4205 4206 4207
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;
4208
    virDomainChrDef monitor_chr;
4209 4210 4211 4212 4213 4214 4215 4216 4217 4218
    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;

4219 4220
    qemuDriverLock(driver);

4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286
    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;
    }

4287 4288
    if (qemuPrepareMonitorChr(conn, driver, &monitor_chr, def->name) < 0)
        goto cleanup;
4289 4290

    if (qemudBuildCommandLine(conn, driver, def,
4291
                              &monitor_chr, qemuCmdFlags,
4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316
                              &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:
4317
    qemuDriverUnlock(driver);
4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330
    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;
}


4331
static int qemudListDefinedDomains(virConnectPtr conn,
4332
                            char **const names, int nnames) {
4333
    struct qemud_driver *driver = conn->privateData;
4334
    int n;
4335

4336
    qemuDriverLock(driver);
4337
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
4338
    qemuDriverUnlock(driver);
4339
    return n;
D
Daniel P. Berrange 已提交
4340 4341
}

4342
static int qemudNumDefinedDomains(virConnectPtr conn) {
4343
    struct qemud_driver *driver = conn->privateData;
4344
    int n;
4345

4346
    qemuDriverLock(driver);
4347
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
4348
    qemuDriverUnlock(driver);
4349

4350
    return n;
D
Daniel P. Berrange 已提交
4351 4352 4353
}


4354
static int qemudDomainStart(virDomainPtr dom) {
4355 4356 4357
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4358
    virDomainEventPtr event = NULL;
4359

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

4363
    if (!vm) {
4364 4365 4366 4367
        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);
4368
        goto cleanup;
4369 4370
    }

4371 4372 4373 4374 4375 4376 4377 4378 4379
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is already running"));
        goto endjob;
    }

4380
    ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL, -1);
4381
    if (ret != -1)
4382 4383 4384
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
4385

4386 4387 4388
endjob:
    qemuDomainObjEndJob(vm);

4389
cleanup:
4390 4391
    if (vm)
        virDomainObjUnlock(vm);
4392
    if (event)
4393
        qemuDomainEventQueue(driver, event);
4394
    qemuDriverUnlock(driver);
4395
    return ret;
D
Daniel P. Berrange 已提交
4396 4397
}

4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412
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;

4413
        if (STRNEQ(def->os.machine, machine->name))
4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426
            continue;

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

        break;
    }

    return 0;
}

4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441
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;

4442
        if (STRNEQ(def->os.machine, machines[i]->name))
4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

4455 4456
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
4457 4458 4459 4460 4461 4462
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
4463
        virCapsGuestDomainInfoPtr info;
4464 4465 4466
        int j;

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

4469 4470 4471 4472 4473 4474 4475 4476 4477
            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;
4478 4479
        }

4480 4481 4482 4483
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
4484 4485 4486 4487
                return -1;
            goto out;
        }
    }
4488 4489 4490 4491

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

4492 4493 4494 4495 4496 4497 4498
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
4499

4500
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
4501
    struct qemud_driver *driver = conn->privateData;
4502
    virDomainDefPtr def;
4503
    virDomainObjPtr vm = NULL;
4504
    virDomainPtr dom = NULL;
4505
    virDomainEventPtr event = NULL;
4506
    int dupVM;
4507

4508
    qemuDriverLock(driver);
4509 4510
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE)))
4511
        goto cleanup;
4512

4513 4514 4515
    if (virSecurityDriverVerify(conn, def) < 0)
        goto cleanup;

4516 4517
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
4518

4519
    if (qemudCanonicalizeMachine(driver, def) < 0)
4520 4521
        goto cleanup;

4522
    if (!(vm = virDomainAssignDef(conn,
4523
                                  driver->caps,
4524 4525
                                  &driver->domains,
                                  def))) {
4526
        goto cleanup;
4527
    }
4528
    def = NULL;
4529
    vm->persistent = 1;
4530

4531 4532
    if (virDomainSaveConfig(conn,
                            driver->configDir,
4533
                            vm->newDef ? vm->newDef : vm->def) < 0) {
4534 4535
        virDomainRemoveInactive(&driver->domains,
                                vm);
4536
        vm = NULL;
4537
        goto cleanup;
4538 4539
    }

4540 4541
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
4542
                                     !dupVM ?
4543 4544
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
4545

4546
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4547
    if (dom) dom->id = vm->def->id;
4548 4549

cleanup:
4550
    virDomainDefFree(def);
4551 4552
    if (vm)
        virDomainObjUnlock(vm);
4553 4554
    if (event)
        qemuDomainEventQueue(driver, event);
4555
    qemuDriverUnlock(driver);
4556
    return dom;
D
Daniel P. Berrange 已提交
4557 4558
}

4559
static int qemudDomainUndefine(virDomainPtr dom) {
4560 4561
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4562
    virDomainEventPtr event = NULL;
4563
    int ret = -1;
D
Daniel P. Berrange 已提交
4564

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

D
Daniel P. Berrange 已提交
4568
    if (!vm) {
4569 4570 4571 4572
        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);
4573
        goto cleanup;
D
Daniel P. Berrange 已提交
4574 4575
    }

D
Daniel P. Berrange 已提交
4576
    if (virDomainObjIsActive(vm)) {
4577
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
4578
                         "%s", _("cannot delete active domain"));
4579
        goto cleanup;
D
Daniel P. Berrange 已提交
4580 4581
    }

4582 4583 4584
    if (!vm->persistent) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot undefine transient domain"));
4585
        goto cleanup;
4586 4587 4588
    }

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

4591 4592 4593
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
4594

4595 4596
    virDomainRemoveInactive(&driver->domains,
                            vm);
4597
    vm = NULL;
4598
    ret = 0;
D
Daniel P. Berrange 已提交
4599

4600
cleanup:
4601 4602
    if (vm)
        virDomainObjUnlock(vm);
4603 4604
    if (event)
        qemuDomainEventQueue(driver, event);
4605
    qemuDriverUnlock(driver);
4606
    return ret;
D
Daniel P. Berrange 已提交
4607 4608
}

4609
/* Return the disks name for use in monitor commands */
4610
static char *qemudDiskDeviceName(const virConnectPtr conn,
4611
                                 const virDomainDiskDefPtr disk) {
4612 4613 4614 4615 4616 4617

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

    if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0) {
4618
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
4619 4620 4621 4622 4623 4624 4625
                         _("cannot convert disk '%s' to bus/device index"),
                         disk->dst);
        return NULL;
    }

    switch (disk->bus) {
        case VIR_DOMAIN_DISK_BUS_IDE:
4626
            if (disk->device== VIR_DOMAIN_DISK_DEVICE_DISK)
4627
                ret = virAsprintf(&devname, "ide%d-hd%d", busid, devid);
4628
            else
4629
                ret = virAsprintf(&devname, "ide%d-cd%d", busid, devid);
4630 4631
            break;
        case VIR_DOMAIN_DISK_BUS_SCSI:
4632
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
4633
                ret = virAsprintf(&devname, "scsi%d-hd%d", busid, devid);
4634
            else
4635
                ret = virAsprintf(&devname, "scsi%d-cd%d", busid, devid);
4636 4637
            break;
        case VIR_DOMAIN_DISK_BUS_FDC:
4638
            ret = virAsprintf(&devname, "floppy%d", devid);
4639 4640
            break;
        case VIR_DOMAIN_DISK_BUS_VIRTIO:
4641
            ret = virAsprintf(&devname, "virtio%d", devid);
4642 4643
            break;
        default:
4644
            qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
4645 4646 4647 4648 4649 4650
                             _("Unsupported disk name mapping for bus '%s'"),
                             virDomainDiskBusTypeToString(disk->bus));
            return NULL;
    }

    if (ret == -1) {
4651
        virReportOOMError(conn);
4652 4653 4654 4655 4656 4657
        return NULL;
    }

    return devname;
}

4658
static int qemudDomainChangeEjectableMedia(virConnectPtr conn,
4659
                                           struct qemud_driver *driver,
4660
                                           virDomainObjPtr vm,
4661 4662
                                           virDomainDeviceDefPtr dev,
                                           unsigned int qemuCmdFlags)
4663
{
4664
    virDomainDiskDefPtr origdisk = NULL, newdisk;
4665
    char *devname = NULL;
4666
    int i;
4667
    int ret;
4668

4669
    origdisk = NULL;
4670
    newdisk = dev->data.disk;
4671 4672 4673 4674
    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];
4675
            break;
4676
        }
4677 4678 4679
    }

    if (!origdisk) {
4680
        qemudReportError(conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
4681 4682 4683 4684 4685 4686 4687
                         _("No device with bus '%s' and target '%s'"),
                         virDomainDiskBusTypeToString(newdisk->bus),
                         newdisk->dst);
        return -1;
    }

    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
4688
        if (!(devname = qemudDiskDeviceName(conn, newdisk)))
4689 4690 4691 4692 4693 4694 4695 4696 4697
            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 {
4698
            qemudReportError(conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
4699 4700 4701 4702 4703 4704 4705 4706
                             _("Emulator version does not support removable "
                               "media for device '%s' and target '%s'"),
                               virDomainDiskDeviceTypeToString(newdisk->device),
                               newdisk->dst);
            return -1;
        }

        if (!devname) {
4707
            virReportOOMError(conn);
4708 4709 4710
            return -1;
        }
    }
4711

4712
    qemuDomainObjPrivatePtr priv = vm->privateData;
4713
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
4714
    if (newdisk->src) {
4715
        ret = qemuMonitorChangeMedia(priv->mon, devname, newdisk->src);
4716
    } else {
4717
        ret = qemuMonitorEjectMedia(priv->mon, devname);
4718
    }
4719
    qemuDomainObjExitMonitorWithDriver(driver, vm);
4720

4721 4722 4723 4724 4725
    if (ret == 0) {
        VIR_FREE(origdisk->src);
        origdisk->src = newdisk->src;
        newdisk->src = NULL;
        origdisk->type = newdisk->type;
4726
    }
4727
    VIR_FREE(devname);
4728

4729
    return ret;
4730 4731
}

4732

4733
static int qemudDomainAttachPciDiskDevice(virConnectPtr conn,
4734
                                          struct qemud_driver *driver,
4735 4736
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
4737
{
4738
    int i, ret;
4739
    const char* type = virDomainDiskBusTypeToString(dev->data.disk->bus);
4740
    qemuDomainObjPrivatePtr priv = vm->privateData;
4741 4742 4743

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
4744
            qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
4745 4746 4747 4748 4749 4750
                           _("target %s already exists"), dev->data.disk->dst);
            return -1;
        }
    }

    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
4751
        virReportOOMError(conn);
4752 4753 4754
        return -1;
    }

4755
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
4756 4757 4758 4759 4760 4761
    ret = qemuMonitorAddPCIDisk(priv->mon,
                                dev->data.disk->src,
                                type,
                                &dev->data.disk->pci_addr.domain,
                                &dev->data.disk->pci_addr.bus,
                                &dev->data.disk->pci_addr.slot);
4762
    qemuDomainObjExitMonitorWithDriver(driver, vm);
4763

4764 4765
    if (ret == 0)
        virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
4766

4767
    return ret;
4768
}
4769

4770
static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn,
4771
                                                 struct qemud_driver *driver,
4772 4773
                                                 virDomainObjPtr vm,
                                                 virDomainDeviceDefPtr dev)
4774
{
4775
    qemuDomainObjPrivatePtr priv = vm->privateData;
4776
    int i, ret;
4777

4778 4779
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
4780
            qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
4781 4782 4783 4784 4785
                           _("target %s already exists"), dev->data.disk->dst);
            return -1;
        }
    }

4786 4787 4788
    if (!dev->data.disk->src) {
        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("disk source path is missing"));
4789 4790 4791
        return -1;
    }

4792
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
4793
        virReportOOMError(conn);
4794 4795 4796
        return -1;
    }

4797
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
4798
    ret = qemuMonitorAddUSBDisk(priv->mon, dev->data.disk->src);
4799
    qemuDomainObjExitMonitorWithDriver(driver, vm);
4800

4801 4802
    if (ret == 0)
        virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
4803

4804
    return ret;
4805 4806
}

M
Mark McLoughlin 已提交
4807
static int qemudDomainAttachNetDevice(virConnectPtr conn,
4808
                                      struct qemud_driver *driver,
M
Mark McLoughlin 已提交
4809 4810 4811 4812 4813
                                      virDomainObjPtr vm,
                                      virDomainDeviceDefPtr dev,
                                      unsigned int qemuCmdFlags)
{
    virDomainNetDefPtr net = dev->data.net;
4814
    qemuDomainObjPrivatePtr priv = vm->privateData;
4815
    char *tapfd_name = NULL;
4816
    int i, tapfd = -1;
4817
    char *nicstr = NULL;
4818
    char *netstr = NULL;
4819
    int ret = -1;
M
Mark McLoughlin 已提交
4820 4821 4822 4823 4824 4825 4826 4827 4828

    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) {
4829 4830 4831 4832 4833 4834 4835 4836 4837 4838
        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 已提交
4839 4840
    }

4841 4842
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
        goto no_memory;
M
Mark McLoughlin 已提交
4843 4844

    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) &&
4845 4846
        qemuAssignNetNames(vm->def, net) < 0)
        goto no_memory;
M
Mark McLoughlin 已提交
4847 4848 4849 4850 4851 4852 4853 4854 4855

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

4856 4857 4858 4859
    if (tapfd != -1) {
        if (virAsprintf(&tapfd_name, "fd-%s", net->hostnet_name) < 0)
            goto no_memory;

4860
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4861
        if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0) {
4862
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4863
            goto cleanup;
4864
        }
4865
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4866 4867
    }

4868 4869
    if (qemuBuildHostNetStr(conn, net, ' ',
                            net->vlan, tapfd_name, &netstr) < 0)
4870
        goto try_tapfd_close;
M
Mark McLoughlin 已提交
4871

4872
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
4873
    if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
4874
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4875
        goto try_tapfd_close;
4876
    }
4877
    qemuDomainObjExitMonitorWithDriver(driver, vm);
M
Mark McLoughlin 已提交
4878

4879 4880 4881
    if (tapfd != -1)
        close(tapfd);
    tapfd = -1;
M
Mark McLoughlin 已提交
4882

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

4886
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
4887
    if (qemuMonitorAddPCINetwork(priv->mon, nicstr,
4888 4889
                                 &net->pci_addr.domain,
                                 &net->pci_addr.bus,
4890
                                 &net->pci_addr.slot) < 0) {
4891
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4892
        goto try_remove;
4893
    }
4894
    qemuDomainObjExitMonitorWithDriver(driver, vm);
4895

4896
    ret = 0;
M
Mark McLoughlin 已提交
4897 4898 4899

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

4900 4901 4902 4903 4904 4905
cleanup:
    VIR_FREE(nicstr);
    VIR_FREE(netstr);
    VIR_FREE(tapfd_name);
    if (tapfd != -1)
        close(tapfd);
4906

4907
    return ret;
4908

4909 4910
try_remove:
    if (!net->hostnet_name || net->vlan == 0)
4911
        VIR_WARN0(_("Unable to remove network backend\n"));
4912
    else {
4913
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4914 4915 4916
        if (qemuMonitorRemoveHostNetwork(priv->mon, net->vlan, net->hostnet_name) < 0)
            VIR_WARN(_("Failed to remove network backend for vlan %d, net %s"),
                     net->vlan, net->hostnet_name);
4917
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4918
    }
4919
    goto cleanup;
4920

4921
try_tapfd_close:
4922
    if (tapfd_name) {
4923
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4924 4925
        if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
            VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_name);
4926
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4927
    }
4928

4929 4930
    goto cleanup;

4931 4932
no_memory:
    virReportOOMError(conn);
4933
    goto cleanup;
M
Mark McLoughlin 已提交
4934 4935
}

4936
static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
4937
                                          struct qemud_driver *driver,
4938 4939 4940
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
{
4941
    qemuDomainObjPrivatePtr priv = vm->privateData;
4942
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
4943
    pciDevice *pci;
4944
    int ret;
4945 4946 4947 4948 4949 4950

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

4951 4952 4953 4954 4955 4956 4957
    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;
4958

4959
    if ((hostdev->managed && pciDettachDevice(conn, pci) < 0) ||
4960 4961 4962 4963 4964 4965
        pciResetDevice(conn, pci, driver->activePciHostdevs) < 0) {
        pciFreeDevice(conn, pci);
        return -1;
    }

    if (pciDeviceListAdd(conn, driver->activePciHostdevs, pci) < 0) {
4966
        pciFreeDevice(conn, pci);
4967
        return -1;
4968 4969
    }

4970
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
4971 4972 4973 4974 4975 4976 4977 4978
    ret = qemuMonitorAddPCIHostDevice(priv->mon,
                                      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);
4979
    qemuDomainObjExitMonitorWithDriver(driver, vm);
4980
    if (ret < 0)
4981
        goto error;
4982 4983 4984 4985

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

    return 0;
4986 4987 4988 4989 4990

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

    return -1;
4991 4992
}

M
Mark McLoughlin 已提交
4993
static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
4994
                                          struct qemud_driver *driver,
M
Mark McLoughlin 已提交
4995 4996
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
4997 4998
{
    int ret;
4999
    qemuDomainObjPrivatePtr priv = vm->privateData;
5000

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

5006
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
5007
    if (dev->data.hostdev->source.subsys.u.usb.vendor) {
5008
        ret = qemuMonitorAddUSBDeviceMatch(priv->mon,
5009 5010
                                           dev->data.hostdev->source.subsys.u.usb.vendor,
                                           dev->data.hostdev->source.subsys.u.usb.product);
5011
    } else {
5012
        ret = qemuMonitorAddUSBDeviceExact(priv->mon,
5013 5014
                                           dev->data.hostdev->source.subsys.u.usb.bus,
                                           dev->data.hostdev->source.subsys.u.usb.device);
5015
    }
5016
    qemuDomainObjExitMonitorWithDriver(driver, vm);
5017

5018 5019
    if (ret != -1)
        vm->def->hostdevs[vm->def->nhostdevs++] = dev->data.hostdev;
5020

5021
    return ret;
5022 5023
}

M
Mark McLoughlin 已提交
5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039
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;
5040 5041 5042
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
        return -1;
M
Mark McLoughlin 已提交
5043 5044

    switch (hostdev->source.subsys.type) {
5045
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
5046
        return qemudDomainAttachHostPciDevice(conn, driver, vm, dev);
M
Mark McLoughlin 已提交
5047
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
5048
        return qemudDomainAttachHostUsbDevice(conn, driver, vm, dev);
M
Mark McLoughlin 已提交
5049 5050 5051 5052 5053 5054 5055 5056
    default:
        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         _("hostdev subsys type '%s' not supported"),
                         virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
        return -1;
    }
}

5057 5058
static int qemudDomainAttachDevice(virDomainPtr dom,
                                   const char *xml) {
5059 5060 5061
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
5062
    unsigned int qemuCmdFlags;
5063
    virCgroupPtr cgroup = NULL;
5064
    int ret = -1;
5065

5066
    qemuDriverLock(driver);
5067
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5068
    if (!vm) {
5069 5070 5071 5072
        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);
5073
        goto cleanup;
5074 5075
    }

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

D
Daniel P. Berrange 已提交
5079
    if (!virDomainObjIsActive(vm)) {
5080
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
5081
                         "%s", _("cannot attach device on inactive domain"));
5082
        goto endjob;
5083 5084
    }

5085 5086
    dev = virDomainDeviceDefParse(dom->conn, driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
5087
    if (dev == NULL)
5088
        goto endjob;
5089

5090 5091 5092
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
5093
        goto endjob;
5094

5095
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5096
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
5097 5098 5099 5100
            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);
5101
                goto endjob;
5102 5103 5104 5105 5106 5107 5108 5109
            }
            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);
5110
                goto endjob;
5111 5112 5113
            }
        }

5114
        switch (dev->data.disk->device) {
5115 5116
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5117 5118
            if (driver->securityDriver)
                driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
5119 5120

            if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
5121
                goto endjob;
5122

5123
            ret = qemudDomainChangeEjectableMedia(dom->conn, driver, vm, dev, qemuCmdFlags);
5124
            break;
5125

5126
        case VIR_DOMAIN_DISK_DEVICE_DISK:
5127 5128
            if (driver->securityDriver)
                driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
5129 5130

            if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
5131
                goto endjob;
5132

5133
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
5134
                ret = qemudDomainAttachUsbMassstorageDevice(dom->conn, driver, vm, dev);
5135 5136
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                       dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
5137
                ret = qemudDomainAttachPciDiskDevice(dom->conn, driver, vm, dev);
5138 5139 5140 5141
            } else {
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                                 _("disk bus '%s' cannot be hotplugged."),
                                 virDomainDiskBusTypeToString(dev->data.disk->bus));
5142
                /* fallthrough */
5143 5144
            }
            break;
5145

5146 5147
        default:
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
5148 5149
                             _("disk device type '%s' cannot be hotplugged"),
                             virDomainDiskDeviceTypeToString(dev->data.disk->device));
5150 5151 5152 5153 5154
            /* Fallthrough */
        }
        if (ret != 0) {
            virCgroupDenyDevicePath(cgroup,
                                    dev->data.disk->src);
5155
        }
M
Mark McLoughlin 已提交
5156
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
5157
        ret = qemudDomainAttachNetDevice(dom->conn, driver, vm, dev, qemuCmdFlags);
M
Mark McLoughlin 已提交
5158 5159
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        ret = qemudDomainAttachHostDevice(dom->conn, driver, vm, dev);
5160
    } else {
5161
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
5162 5163
                         _("device type '%s' cannot be attached"),
                         virDomainDeviceTypeToString(dev->type));
5164
        goto endjob;
5165 5166
    }

5167
    if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
5168 5169
        ret = -1;

5170 5171 5172
endjob:
    qemuDomainObjEndJob(vm);

5173
cleanup:
5174 5175 5176
    if (cgroup)
        virCgroupFree(&cgroup);

5177
    if (ret < 0 && dev != NULL) {
5178 5179
        if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
            VIR_WARN0("Fail to restore disk device ownership");
G
Guido Günther 已提交
5180
        virDomainDeviceDefFree(dev);
5181
    }
5182 5183
    if (vm)
        virDomainObjUnlock(vm);
5184
    qemuDriverUnlock(driver);
5185 5186 5187
    return ret;
}

5188
static int qemudDomainDetachPciDiskDevice(virConnectPtr conn,
5189 5190 5191
                                          struct qemud_driver *driver,
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
5192 5193 5194
{
    int i, ret = -1;
    virDomainDiskDefPtr detach = NULL;
5195
    qemuDomainObjPrivatePtr priv = vm->privateData;
5196 5197 5198 5199 5200 5201 5202 5203 5204

    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) {
5205
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
5206
                         _("disk %s not found"), dev->data.disk->dst);
5207
        goto cleanup;
5208 5209
    }

5210
    if (!virDiskHasValidPciAddr(detach)) {
5211
        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
5212 5213
                         _("disk %s cannot be detached - no PCI address for device"),
                           detach->dst);
5214
        goto cleanup;
5215 5216
    }

5217
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
5218
    if (qemuMonitorRemovePCIDevice(priv->mon,
5219 5220
                                   detach->pci_addr.domain,
                                   detach->pci_addr.bus,
5221 5222
                                   detach->pci_addr.slot) < 0) {
        qemuDomainObjExitMonitor(vm);
5223
        goto cleanup;
5224
    }
5225
    qemuDomainObjExitMonitorWithDriver(driver, vm);
5226

5227 5228 5229 5230 5231 5232 5233 5234 5235 5236
    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 {
5237
        VIR_FREE(vm->def->disks);
5238
        vm->def->ndisks = 0;
5239
    }
5240
    virDomainDiskDefFree(detach);
5241

5242
    ret = 0;
5243 5244

cleanup:
5245 5246 5247
    return ret;
}

5248 5249
static int
qemudDomainDetachNetDevice(virConnectPtr conn,
5250
                           struct qemud_driver *driver,
5251 5252 5253 5254 5255
                           virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev)
{
    int i, ret = -1;
    virDomainNetDefPtr detach = NULL;
5256
    qemuDomainObjPrivatePtr priv = vm->privateData;
5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281

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

5282
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
5283
    if (qemuMonitorRemovePCIDevice(priv->mon,
5284 5285
                                   detach->pci_addr.domain,
                                   detach->pci_addr.bus,
5286
                                   detach->pci_addr.slot) < 0) {
5287
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5288
        goto cleanup;
5289
    }
5290

5291
    if (qemuMonitorRemoveHostNetwork(priv->mon, detach->vlan, detach->hostnet_name) < 0) {
5292
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5293
        goto cleanup;
5294
    }
5295
    qemuDomainObjExitMonitorWithDriver(driver, vm);
5296

5297 5298 5299 5300 5301 5302 5303 5304 5305 5306
    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 {
5307
        VIR_FREE(vm->def->nets);
5308
        vm->def->nnets = 0;
5309
    }
5310
    virDomainNetDefFree(detach);
5311

5312 5313 5314 5315 5316 5317
    ret = 0;

cleanup:
    return ret;
}

5318
static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
5319
                                          struct qemud_driver *driver,
5320 5321 5322
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev)
{
5323
    virDomainHostdevDefPtr detach = NULL;
5324
    qemuDomainObjPrivatePtr priv = vm->privateData;
5325
    int i, ret;
5326
    pciDevice *pci;
5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358

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

5359
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
5360
    if (qemuMonitorRemovePCIDevice(priv->mon,
5361 5362
                                   detach->source.subsys.u.pci.guest_addr.domain,
                                   detach->source.subsys.u.pci.guest_addr.bus,
5363
                                   detach->source.subsys.u.pci.guest_addr.slot) < 0) {
5364
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5365
        return -1;
5366
    }
5367
    qemuDomainObjExitMonitorWithDriver(driver, vm);
5368 5369 5370

    ret = 0;

5371 5372 5373 5374 5375 5376 5377 5378
    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 {
5379 5380
        pciDeviceListDel(conn, driver->activePciHostdevs, pci);
        if (pciResetDevice(conn, pci, driver->activePciHostdevs) < 0)
5381 5382
            ret = -1;
        if (detach->managed && pciReAttachDevice(conn, pci) < 0)
5383
            ret = -1;
5384
        pciFreeDevice(conn, pci);
5385 5386
    }

5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398
    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;
5399
    }
5400
    virDomainHostdevDefFree(detach);
5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421

    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:
5422
        ret = qemudDomainDetachHostPciDevice(conn, driver, vm, dev);
5423
        break;
5424 5425 5426 5427 5428 5429 5430
    default:
        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         _("hostdev subsys type '%s' not supported"),
                         virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
        return -1;
    }

5431 5432 5433 5434
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
        VIR_WARN0("Failed to restore device labelling");

5435
    if (qemuDomainSetDeviceOwnership(conn, driver, dev, 1) < 0)
5436
        VIR_WARN0("Failed to restore device ownership");
5437 5438 5439 5440

    return ret;
}

5441 5442
static int qemudDomainDetachDevice(virDomainPtr dom,
                                   const char *xml) {
5443 5444 5445 5446
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;
5447

5448
    qemuDriverLock(driver);
5449
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5450
    if (!vm) {
5451 5452 5453 5454
        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);
5455
        goto cleanup;
5456 5457
    }

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

D
Daniel P. Berrange 已提交
5461
    if (!virDomainObjIsActive(vm)) {
5462
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
G
Guido Günther 已提交
5463
                         "%s", _("cannot detach device on inactive domain"));
5464
        goto endjob;
5465 5466
    }

5467 5468
    dev = virDomainDeviceDefParse(dom->conn, driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
5469
    if (dev == NULL)
5470
        goto endjob;
5471

5472 5473 5474 5475

    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 ||
5476
         dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)) {
5477
        ret = qemudDomainDetachPciDiskDevice(dom->conn, driver, vm, dev);
5478
        if (driver->securityDriver)
5479
            driver->securityDriver->domainRestoreSecurityImageLabel(dom->conn, vm, dev->data.disk);
5480 5481
        if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
            VIR_WARN0("Fail to restore disk device ownership");
5482
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
5483
        ret = qemudDomainDetachNetDevice(dom->conn, driver, vm, dev);
5484 5485
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        ret = qemudDomainDetachHostDevice(dom->conn, driver, vm, dev);
5486
    } else
5487 5488 5489
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         "%s", _("only SCSI or virtio disk device can be detached dynamically"));

5490
    if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
5491 5492
        ret = -1;

5493 5494 5495
endjob:
    qemuDomainObjEndJob(vm);

5496 5497
cleanup:
    virDomainDeviceDefFree(dev);
5498 5499
    if (vm)
        virDomainObjUnlock(vm);
5500
    qemuDriverUnlock(driver);
5501 5502 5503
    return ret;
}

5504
static int qemudDomainGetAutostart(virDomainPtr dom,
5505
                                   int *autostart) {
5506 5507 5508
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5509

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

5514
    if (!vm) {
5515 5516 5517 5518
        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);
5519
        goto cleanup;
5520 5521 5522
    }

    *autostart = vm->autostart;
5523
    ret = 0;
5524

5525
cleanup:
5526 5527
    if (vm)
        virDomainObjUnlock(vm);
5528
    return ret;
5529 5530
}

5531
static int qemudDomainSetAutostart(virDomainPtr dom,
5532
                                   int autostart) {
5533 5534
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5535 5536
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
5537

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

5541
    if (!vm) {
5542 5543 5544 5545
        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);
5546
        goto cleanup;
5547 5548
    }

5549 5550 5551
    if (!vm->persistent) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot set autostart for transient domain"));
5552
        goto cleanup;
5553 5554
    }

5555 5556
    autostart = (autostart != 0);

5557 5558 5559 5560 5561
    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;
5562

5563 5564
        if (autostart) {
            int err;
5565

5566
            if ((err = virFileMakePath(driver->autostartDir))) {
5567 5568 5569
                virReportSystemError(dom->conn, err,
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
5570 5571
                goto cleanup;
            }
5572

5573
            if (symlink(configFile, autostartLink) < 0) {
5574 5575 5576
                virReportSystemError(dom->conn, errno,
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
5577 5578 5579 5580
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
5581 5582 5583
                virReportSystemError(dom->conn, errno,
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
5584 5585
                goto cleanup;
            }
5586 5587
        }

5588
        vm->autostart = autostart;
5589
    }
5590
    ret = 0;
5591

5592 5593 5594
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
5595 5596
    if (vm)
        virDomainObjUnlock(vm);
5597
    qemuDriverUnlock(driver);
5598
    return ret;
5599 5600
}

5601 5602 5603 5604 5605

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

5608
    qemuDriverLock(driver);
5609
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5610 5611
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
5612
        goto cleanup;
5613 5614 5615 5616 5617 5618 5619 5620
    }

    if (nparams)
        *nparams = 1;

    ret = strdup("posix");
    if (!ret)
        virReportOOMError(dom->conn);
5621 5622 5623

cleanup:
    qemuDriverUnlock(driver);
5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636
    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;

5637
    qemuDriverLock(driver);
5638
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5639 5640
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
5641
        goto cleanup;
5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663
    }

    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 已提交
5664
                qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, "%s",
5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686
                                 _("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);
5687
    qemuDriverUnlock(driver);
5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701
    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;

5702
    qemuDriverLock(driver);
5703
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
5704 5705
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                         __FUNCTION__);
5706
        goto cleanup;
5707 5708 5709 5710 5711
    }

    if ((*nparams) != 1) {
        qemudReportError(dom->conn, domain, NULL, VIR_ERR_INVALID_ARG,
                         "%s", _("Invalid parameter count"));
5712
        goto cleanup;
5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736
    }

    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 已提交
5737 5738 5739 5740 5741
    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;
    }
5742 5743 5744 5745 5746 5747 5748

    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
5749
    qemuDriverUnlock(driver);
5750 5751 5752 5753
    return ret;
}


5754 5755 5756 5757 5758 5759 5760 5761 5762
/* 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)
{
5763
    struct qemud_driver *driver = dom->conn->privateData;
5764 5765
    const char *qemu_dev_name = NULL;
    int i, ret = -1;
5766
    virDomainObjPtr vm;
5767
    virDomainDiskDefPtr disk = NULL;
5768

5769
    qemuDriverLock(driver);
5770
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5771
    qemuDriverUnlock(driver);
5772
    if (!vm) {
5773 5774 5775 5776
        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);
5777
        goto cleanup;
5778
    }
5779 5780 5781 5782

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

D
Daniel P. Berrange 已提交
5783
    if (!virDomainObjIsActive (vm)) {
5784
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
5785
                          "%s", _("domain is not running"));
5786
        goto endjob;
5787 5788
    }

5789 5790 5791 5792 5793 5794 5795 5796
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
5797 5798
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
                          _("invalid path: %s"), path);
5799
        goto endjob;
5800 5801
    }

5802
    qemu_dev_name = qemudDiskDeviceName(dom->conn, disk);
5803
    if (!qemu_dev_name)
5804
        goto endjob;
5805

5806
    qemuDomainObjPrivatePtr priv = vm->privateData;
5807 5808 5809 5810 5811 5812 5813 5814 5815
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       qemu_dev_name,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
                                       &stats->wr_req,
                                       &stats->wr_bytes,
                                       &stats->errs);
    qemuDomainObjExitMonitor(vm);
5816

5817 5818 5819
endjob:
    qemuDomainObjEndJob(vm);

5820
cleanup:
5821
    VIR_FREE(qemu_dev_name);
5822 5823
    if (vm)
        virDomainObjUnlock(vm);
5824
    return ret;
5825 5826
}

5827
#ifdef __linux__
5828 5829 5830 5831 5832
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
5833 5834
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5835
    int i;
5836
    int ret = -1;
5837

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

5842
    if (!vm) {
5843 5844 5845 5846
        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);
5847
        goto cleanup;
5848 5849
    }

D
Daniel P. Berrange 已提交
5850
    if (!virDomainObjIsActive(vm)) {
5851
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
5852
                         "%s", _("domain is not running"));
5853
        goto cleanup;
5854 5855 5856
    }

    /* Check the path is one of the domain's network interfaces. */
5857 5858
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
5859 5860 5861 5862
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
5863 5864
    }

5865 5866 5867 5868 5869
    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);
5870

5871
cleanup:
5872 5873
    if (vm)
        virDomainObjUnlock(vm);
5874 5875
    return ret;
}
5876
#else
5877 5878 5879 5880
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
5881 5882 5883 5884
    qemudReportError (dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                      "%s", __FUNCTION__);
    return -1;
}
5885
#endif
5886

5887 5888 5889 5890 5891 5892 5893
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
5894 5895 5896
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
5897

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

5902
    if (!vm) {
5903 5904 5905 5906
        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);
5907
        goto cleanup;
5908 5909 5910 5911
    }

    if (!path || path[0] == '\0') {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
5912
                         "%s", _("NULL or empty path"));
5913
        goto cleanup;
5914 5915 5916
    }

    /* Check the path belongs to this domain. */
5917 5918
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
5919 5920 5921 5922
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
5923 5924
    }

5925 5926 5927 5928 5929
    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) {
5930 5931
            virReportSystemError (dom->conn, errno,
                                  _("%s: failed to open"), path);
5932 5933
            goto cleanup;
        }
5934

5935 5936 5937 5938 5939 5940
        /* 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) {
5941 5942
            virReportSystemError (dom->conn, errno,
                                  _("%s: failed to seek or read"), path);
5943 5944 5945 5946 5947 5948 5949
            goto cleanup;
        }

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

5952 5953 5954
cleanup:
    if (fd >= 0)
        close (fd);
5955 5956
    if (vm)
        virDomainObjUnlock(vm);
5957 5958 5959
    return ret;
}

R
Richard W.M. Jones 已提交
5960 5961 5962 5963 5964 5965
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
5966 5967
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5968
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
5969 5970
    int fd = -1, ret = -1;

5971
    qemuDriverLock(driver);
5972
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5973
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
5974 5975

    if (!vm) {
5976 5977 5978 5979
        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);
5980 5981 5982
        goto cleanup;
    }

5983
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
5984
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
5985
                     "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
5986
        goto cleanup;
R
Richard W.M. Jones 已提交
5987 5988
    }

5989 5990 5991
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
5992
    if (!virDomainObjIsActive(vm)) {
5993
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
R
Richard W.M. Jones 已提交
5994
                         "%s", _("domain is not running"));
5995
        goto endjob;
R
Richard W.M. Jones 已提交
5996 5997
    }

5998 5999
    if (virAsprintf(&tmp, driver->cacheDir,  "/qemu.mem.XXXXXX") < 0) {
        virReportOOMError(dom->conn);
6000
        goto endjob;
6001 6002
    }

R
Richard W.M. Jones 已提交
6003 6004
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
6005 6006
        virReportSystemError (dom->conn, errno,
                              _("mkstemp(\"%s\") failed"), tmp);
6007
        goto endjob;
R
Richard W.M. Jones 已提交
6008 6009
    }

6010
    qemuDomainObjPrivatePtr priv = vm->privateData;
6011
    qemuDomainObjEnterMonitor(vm);
6012
    if (flags == VIR_MEMORY_VIRTUAL) {
6013 6014
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
6015
            goto endjob;
6016
        }
6017
    } else {
6018 6019
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
6020
            goto endjob;
6021
        }
R
Richard W.M. Jones 已提交
6022
    }
6023
    qemuDomainObjExitMonitor(vm);
R
Richard W.M. Jones 已提交
6024 6025 6026

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
6027 6028 6029
        virReportSystemError (dom->conn, errno,
                              _("failed to read temporary file "
                                "created with template %s"), tmp);
6030
        goto endjob;
R
Richard W.M. Jones 已提交
6031 6032 6033
    }

    ret = 0;
6034

6035 6036 6037
endjob:
    qemuDomainObjEndJob(vm);

6038
cleanup:
6039
    VIR_FREE(tmp);
R
Richard W.M. Jones 已提交
6040 6041
    if (fd >= 0) close (fd);
    unlink (tmp);
6042 6043
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
6044 6045 6046
    return ret;
}

6047

6048 6049
static int
qemudDomainEventRegister (virConnectPtr conn,
6050
                          virConnectDomainEventCallback callback,
6051 6052
                          void *opaque,
                          virFreeCallback freecb)
6053
{
6054 6055 6056
    struct qemud_driver *driver = conn->privateData;
    int ret;

6057
    qemuDriverLock(driver);
6058 6059
    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
                                        callback, opaque, freecb);
6060
    qemuDriverUnlock(driver);
6061

6062
    return ret;
6063 6064 6065 6066
}

static int
qemudDomainEventDeregister (virConnectPtr conn,
6067
                            virConnectDomainEventCallback callback)
6068
{
6069 6070 6071
    struct qemud_driver *driver = conn->privateData;
    int ret;

6072
    qemuDriverLock(driver);
6073 6074 6075 6076 6077 6078
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
                                               callback);
6079
    qemuDriverUnlock(driver);
6080

6081
    return ret;
6082 6083
}

6084 6085 6086 6087 6088
static void qemuDomainEventDispatchFunc(virConnectPtr conn,
                                        virDomainEventPtr event,
                                        virConnectDomainEventCallback cb,
                                        void *cbopaque,
                                        void *opaque)
6089
{
6090
    struct qemud_driver *driver = opaque;
6091

6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135
    /* 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);
6136 6137
}

D
Daniel Veillard 已提交
6138 6139
/* Migration support. */

C
Chris Lalancette 已提交
6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312
/* 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;

6313 6314
    if (VIR_ALLOC(qemust) < 0) {
        virReportOOMError(st->conn);
C
Chris Lalancette 已提交
6315
        return NULL;
6316
    }
C
Chris Lalancette 已提交
6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463

    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;

6464 6465
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
C
Chris Lalancette 已提交
6466 6467

    if (!(vm = virDomainAssignDef(dconn,
6468
                                  driver->caps,
C
Chris Lalancette 已提交
6469 6470 6471 6472 6473 6474 6475 6476
                                  &driver->domains,
                                  def))) {
        qemudReportError(dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("failed to assign new VM"));
        goto cleanup;
    }
    def = NULL;

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

C
Chris Lalancette 已提交
6480 6481 6482 6483 6484 6485
    /* 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);
6486
        goto endjob;
C
Chris Lalancette 已提交
6487 6488 6489 6490 6491 6492 6493 6494
    }
    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);
6495
        goto endjob;
C
Chris Lalancette 已提交
6496 6497 6498 6499 6500 6501 6502 6503
    }
    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"));
6504
        goto endjob;
C
Chris Lalancette 已提交
6505 6506 6507
    }
    if (internalret < 0) {
        virReportOOMError(dconn);
6508
        goto endjob;
C
Chris Lalancette 已提交
6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522
    }
    /* 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;
        }
6523
        goto endjob;
C
Chris Lalancette 已提交
6524 6525 6526 6527 6528
    }

    qemust = qemuStreamMigOpen(st, unixfile);
    if (qemust == NULL) {
        qemudShutdownVMDaemon(NULL, driver, vm);
6529
        if (!vm->persistent) {
6530
            qemuDomainObjEndJob(vm);
6531 6532 6533
            virDomainRemoveInactive(&driver->domains, vm);
            vm = NULL;
        }
C
Chris Lalancette 已提交
6534 6535 6536
        virReportSystemError(dconn, errno,
                             _("cannot open unix socket '%s' for tunnelled migration"),
                             unixfile);
6537
        goto endjob;
C
Chris Lalancette 已提交
6538 6539 6540 6541 6542 6543 6544 6545 6546 6547
    }

    st->driver = &qemuStreamMigDrv;
    st->privateData = qemust;

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_MIGRATED);
    ret = 0;

6548 6549 6550 6551
endjob:
    if (vm)
        qemuDomainObjEndJob(vm);

C
Chris Lalancette 已提交
6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563
cleanup:
    virDomainDefFree(def);
    unlink(unixfile);
    VIR_FREE(unixfile);
    if (vm)
        virDomainObjUnlock(vm);
    if (event)
        qemuDomainEventQueue(driver, event);
    qemuDriverUnlock(driver);
    return ret;
}

D
Daniel Veillard 已提交
6564 6565 6566 6567 6568 6569 6570 6571 6572 6573
/* 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 已提交
6574
                            unsigned long flags,
D
Daniel Veillard 已提交
6575 6576 6577 6578 6579
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
    static int port = 0;
6580 6581
    struct qemud_driver *driver = dconn->privateData;
    virDomainDefPtr def = NULL;
D
Daniel Veillard 已提交
6582 6583
    virDomainObjPtr vm = NULL;
    int this_port;
6584
    char *hostname;
D
Daniel Veillard 已提交
6585 6586
    char migrateFrom [64];
    const char *p;
6587
    virDomainEventPtr event = NULL;
6588
    int ret = -1;
6589
    int internalret;
6590 6591

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

6593
    qemuDriverLock(driver);
C
Chris Lalancette 已提交
6594 6595 6596 6597 6598 6599 6600 6601 6602
    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 已提交
6603 6604 6605
    if (!dom_xml) {
        qemudReportError (dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                          "%s", _("no domain XML passed"));
6606
        goto cleanup;
D
Daniel Veillard 已提交
6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623
    }

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

6627 6628 6629 6630 6631
        /* 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 已提交
6632
        /* Caller frees */
6633 6634 6635
        internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
        VIR_FREE(hostname);
        if (internalret < 0) {
6636
            virReportOOMError (dconn);
6637
            goto cleanup;
D
Daniel Veillard 已提交
6638 6639 6640 6641 6642 6643
        }
    } 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.
         */
6644
        if (!STRPREFIX (uri_in, "tcp:")) {
D
Daniel Veillard 已提交
6645
            qemudReportError (dconn, NULL, NULL, VIR_ERR_INVALID_ARG,
6646
                  "%s", _("only tcp URIs are supported for KVM/QEMU migrations"));
6647
            goto cleanup;
D
Daniel Veillard 已提交
6648 6649 6650 6651
        }

        /* Get the port number. */
        p = strrchr (uri_in, ':');
6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671
        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 已提交
6672 6673 6674
        }
    }

6675 6676 6677
    if (uri_out && *uri_out)
        VIR_DEBUG("Generated uri_out=%s", *uri_out);

D
Daniel Veillard 已提交
6678
    /* Parse the domain XML. */
6679 6680
    if (!(def = virDomainDefParseString(dconn, driver->caps, dom_xml,
                                        VIR_DOMAIN_XML_INACTIVE))) {
D
Daniel Veillard 已提交
6681 6682
        qemudReportError (dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                          "%s", _("failed to parse XML"));
6683
        goto cleanup;
D
Daniel Veillard 已提交
6684 6685 6686 6687 6688
    }

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

6689 6690
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
6691 6692

    if (!(vm = virDomainAssignDef(dconn,
6693
                                  driver->caps,
D
Daniel Veillard 已提交
6694 6695 6696 6697
                                  &driver->domains,
                                  def))) {
        qemudReportError (dconn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                          "%s", _("failed to assign new VM"));
6698
        goto cleanup;
D
Daniel Veillard 已提交
6699
    }
6700
    def = NULL;
D
Daniel Veillard 已提交
6701

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

D
Daniel Veillard 已提交
6705 6706 6707 6708 6709 6710 6711
    /* 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);
6712
    if (qemudStartVMDaemon (dconn, driver, vm, migrateFrom, -1) < 0) {
6713 6714 6715
        /* Note that we don't set an error here because qemudStartVMDaemon
         * should have already done that.
         */
6716
        if (!vm->persistent) {
6717
            qemuDomainObjEndJob(vm);
D
Daniel Veillard 已提交
6718
            virDomainRemoveInactive(&driver->domains, vm);
6719 6720
            vm = NULL;
        }
6721
        goto endjob;
D
Daniel Veillard 已提交
6722
    }
6723 6724 6725 6726

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

6729 6730 6731 6732
endjob:
    if (vm)
        qemuDomainObjEndJob(vm);

6733 6734 6735 6736 6737
cleanup:
    virDomainDefFree(def);
    if (ret != 0) {
        VIR_FREE(*uri_out);
    }
6738 6739
    if (vm)
        virDomainObjUnlock(vm);
6740 6741
    if (event)
        qemuDomainEventQueue(driver, event);
6742
    qemuDriverUnlock(driver);
6743
    return ret;
C
Chris Lalancette 已提交
6744 6745 6746

}

6747 6748 6749 6750 6751

/* Perform migration using QEMU's native TCP migrate support,
 * not encrypted obviously
 */
static int doNativeMigrate(virDomainPtr dom,
6752
                           struct qemud_driver *driver,
6753 6754 6755 6756 6757 6758 6759
                           virDomainObjPtr vm,
                           const char *uri,
                           unsigned long flags ATTRIBUTE_UNUSED,
                           const char *dname ATTRIBUTE_UNUSED,
                           unsigned long resource)
{
    int ret = -1;
6760
    xmlURIPtr uribits = NULL;
6761 6762
    int status;
    unsigned long long transferred, remaining, total;
6763
    qemuDomainObjPrivatePtr priv = vm->privateData;
6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783

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

6784
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6785
    if (resource > 0 &&
6786
        qemuMonitorSetMigrationSpeed(priv->mon, resource) < 0) {
6787
        qemuDomainObjExitMonitorWithDriver(driver, vm);
6788
        goto cleanup;
6789
    }
6790

6791
    if (qemuMonitorMigrateToHost(priv->mon, 0, uribits->server, uribits->port) < 0) {
6792
        qemuDomainObjExitMonitorWithDriver(driver, vm);
6793
        goto cleanup;
6794
    }
6795 6796 6797 6798

    /* it is also possible that the migrate didn't fail initially, but
     * rather failed later on.  Check the output of "info migrate"
     */
6799 6800
    if (qemuMonitorGetMigrationStatus(priv->mon,
                                      &status,
6801 6802 6803
                                      &transferred,
                                      &remaining,
                                      &total) < 0) {
6804
        qemuDomainObjExitMonitorWithDriver(driver, vm);
6805 6806
        goto cleanup;
    }
6807
    qemuDomainObjExitMonitorWithDriver(driver, vm);
6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822

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


6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843
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 已提交
6844
            qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s",
6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856
                             _("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 已提交
6857
static int doTunnelMigrate(virDomainPtr dom,
6858
                           struct qemud_driver *driver,
6859
                           virConnectPtr dconn,
C
Chris Lalancette 已提交
6860
                           virDomainObjPtr vm,
6861
                           const char *dom_xml,
C
Chris Lalancette 已提交
6862 6863 6864 6865 6866
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
6867
    qemuDomainObjPrivatePtr priv = vm->privateData;
6868 6869
    int client_sock = -1;
    int qemu_sock = -1;
C
Chris Lalancette 已提交
6870 6871
    struct sockaddr_un sa_qemu, sa_client;
    socklen_t addrlen;
6872
    virDomainPtr ddomain = NULL;
C
Chris Lalancette 已提交
6873
    int retval = -1;
6874
    virStreamPtr st = NULL;
C
Chris Lalancette 已提交
6875 6876 6877 6878 6879 6880
    char *unixfile = NULL;
    int internalret;
    unsigned int qemuCmdFlags;
    int status;
    unsigned long long transferred, remaining, total;

6881 6882 6883 6884 6885 6886 6887 6888
    /*
     * 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 已提交
6889 6890
     */

6891

6892
    /* Stage 1. setup local support infrastructure */
C
Chris Lalancette 已提交
6893 6894 6895 6896

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
                    driver->stateDir, vm->def->name) < 0) {
        virReportOOMError(dom->conn);
6897
        goto cleanup;
C
Chris Lalancette 已提交
6898 6899 6900 6901 6902 6903
    }

    qemu_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (qemu_sock < 0) {
        virReportSystemError(dom->conn, errno, "%s",
                             _("cannot open tunnelled migration socket"));
6904
        goto cleanup;
C
Chris Lalancette 已提交
6905 6906 6907 6908 6909 6910 6911 6912
    }
    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);
6913
        goto cleanup;
C
Chris Lalancette 已提交
6914 6915 6916 6917 6918 6919
    }
    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);
6920
        goto cleanup;
C
Chris Lalancette 已提交
6921 6922 6923 6924 6925
    }
    if (listen(qemu_sock, 1) < 0) {
        virReportSystemError(dom->conn, errno,
                             _("Cannot listen on unix socket '%s' for tunnelled migration"),
                             unixfile);
6926
        goto cleanup;
C
Chris Lalancette 已提交
6927 6928 6929 6930 6931 6932 6933
    }

    /* 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);
6934 6935 6936 6937 6938 6939 6940 6941
        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 已提交
6942
    }
6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963


    /* 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 */
6964
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
6965
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX)
6966
        internalret = qemuMonitorMigrateToUnix(priv->mon, 1, unixfile);
C
Chris Lalancette 已提交
6967 6968
    else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
        const char *args[] = { "nc", "-U", unixfile, NULL };
6969
        internalret = qemuMonitorMigrateToCommand(priv->mon, 1, args, "/dev/null");
6970 6971
    } else {
        internalret = -1;
C
Chris Lalancette 已提交
6972
    }
6973
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
6974 6975 6976
    if (internalret < 0) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s", _("tunnelled migration monitor command failed"));
6977
        goto finish;
C
Chris Lalancette 已提交
6978 6979
    }

6980 6981 6982
    /* From this point onwards we *must* call cancel to abort the
     * migration on source if anything goes wrong */

C
Chris Lalancette 已提交
6983 6984 6985
    /* it is also possible that the migrate didn't fail initially, but
     * rather failed later on.  Check the output of "info migrate"
     */
6986
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6987 6988
    if (qemuMonitorGetMigrationStatus(priv->mon,
                                      &status,
C
Chris Lalancette 已提交
6989 6990 6991
                                      &transferred,
                                      &remaining,
                                      &total) < 0) {
6992
        qemuDomainObjExitMonitorWithDriver(driver, vm);
6993
        goto cancel;
C
Chris Lalancette 已提交
6994
    }
6995
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
6996 6997 6998 6999

    if (status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                         "%s",_("migrate failed"));
7000
        goto cancel;
C
Chris Lalancette 已提交
7001 7002 7003 7004 7005 7006 7007 7008
    }

    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"));
7009
        goto cancel;
C
Chris Lalancette 已提交
7010 7011
    }

7012
    retval = doTunnelSendAll(dom, st, client_sock);
7013

7014
cancel:
7015
    if (retval != 0) {
7016
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7017
        qemuMonitorMigrateCancel(priv->mon);
7018
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7019
    }
C
Chris Lalancette 已提交
7020

7021
finish:
C
Chris Lalancette 已提交
7022 7023 7024
    dname = dname ? dname : dom->name;
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri, flags, retval);
7025 7026 7027 7028 7029 7030 7031

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

C
Chris Lalancette 已提交
7032 7033 7034
    if (ddomain)
        virUnrefDomain(ddomain);

7035 7036 7037 7038
    if (unixfile) {
        unlink(unixfile);
        VIR_FREE(unixfile);
    }
C
Chris Lalancette 已提交
7039

7040 7041 7042
    if (st)
        /* don't call virStreamFree(), because that resets any pending errors */
        virUnrefStream(st);
7043 7044 7045 7046
    return retval;
}


7047 7048 7049 7050
/* 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,
7051
                              struct qemud_driver *driver,
7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076
                              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 已提交
7077
        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
7078 7079 7080
                         _("domainMigratePrepare2 did not set uri"));
    }

7081
    if (doNativeMigrate(dom, driver, vm, uri_out, flags, dname, resource) < 0)
7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098
        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;
}


7099
static int doPeer2PeerMigrate(virDomainPtr dom,
7100
                              struct qemud_driver *driver,
7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121
                              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,
7122
                                  VIR_DRV_FEATURE_MIGRATION_P2P)) {
7123
        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED, "%s",
7124
                         _("Destination libvirt does not support peer-to-peer migration protocol"));
7125 7126 7127 7128 7129 7130 7131 7132 7133 7134
        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;
    }

7135
    if (flags & VIR_MIGRATE_TUNNELLED)
7136
        ret = doTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
7137
    else
7138
        ret = doNonTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
7139 7140 7141

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

7145
    return ret;
D
Daniel Veillard 已提交
7146 7147
}

7148

D
Daniel Veillard 已提交
7149 7150 7151 7152 7153 7154
/* 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,
7155
                           unsigned long flags,
7156
                           const char *dname,
D
Daniel Veillard 已提交
7157 7158
                           unsigned long resource)
{
7159 7160
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
7161
    virDomainEventPtr event = NULL;
7162
    int ret = -1;
7163
    int paused = 0;
D
Daniel Veillard 已提交
7164

7165
    qemuDriverLock(driver);
7166
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
7167
    if (!vm) {
7168 7169 7170 7171
        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);
7172
        goto cleanup;
D
Daniel Veillard 已提交
7173 7174
    }

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

D
Daniel P. Berrange 已提交
7178
    if (!virDomainObjIsActive(vm)) {
7179
        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
D
Daniel Veillard 已提交
7180
                          "%s", _("domain is not running"));
7181
        goto endjob;
D
Daniel Veillard 已提交
7182 7183
    }

7184
    if (!(flags & VIR_MIGRATE_LIVE)) {
7185
        qemuDomainObjPrivatePtr priv = vm->privateData;
7186
        /* Pause domain for non-live migration */
7187
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7188
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
7189 7190
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto endjob;
7191
        }
7192
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7193
        paused = 1;
7194

7195 7196 7197 7198 7199 7200
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
        if (event)
            qemuDomainEventQueue(driver, event);
        event = NULL;
7201 7202
    }

7203
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
7204
        if (doPeer2PeerMigrate(dom, driver, vm, uri, flags, dname, resource) < 0)
7205
            /* doPeer2PeerMigrate already set the error, so just get out */
7206
            goto endjob;
7207
    } else {
7208 7209
        if (doNativeMigrate(dom, driver, vm, uri, flags, dname, resource) < 0)
            goto endjob;
7210 7211
    }

D
Daniel Veillard 已提交
7212 7213
    /* Clean up the source domain. */
    qemudShutdownVMDaemon (dom->conn, driver, vm);
7214
    paused = 0;
7215 7216 7217 7218

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
C
Chris Lalancette 已提交
7219 7220
    if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
        virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm);
7221
        qemuDomainObjEndJob(vm);
D
Daniel Veillard 已提交
7222
        virDomainRemoveInactive(&driver->domains, vm);
7223 7224
        vm = NULL;
    }
7225
    ret = 0;
D
Daniel Veillard 已提交
7226

7227
endjob:
7228
    if (paused) {
7229
        qemuDomainObjPrivatePtr priv = vm->privateData;
7230
        /* we got here through some sort of failure; start the domain again */
7231
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7232
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
7233 7234 7235 7236
            /* 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
             */
7237 7238
            VIR_ERROR(_("Failed to resume guest %s after failure\n"),
                      vm->def->name);
7239
        }
7240
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7241 7242 7243 7244 7245

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }
7246 7247
    if (vm)
        qemuDomainObjEndJob(vm);
7248

7249
cleanup:
7250 7251
    if (vm)
        virDomainObjUnlock(vm);
7252 7253
    if (event)
        qemuDomainEventQueue(driver, event);
7254
    qemuDriverUnlock(driver);
7255
    return ret;
D
Daniel Veillard 已提交
7256 7257 7258 7259 7260 7261 7262 7263 7264
}

/* 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 已提交
7265
                           unsigned long flags,
D
Daniel Veillard 已提交
7266 7267
                           int retcode)
{
7268 7269 7270
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
7271
    virDomainEventPtr event = NULL;
C
Chris Lalancette 已提交
7272
    int newVM = 1;
D
Daniel Veillard 已提交
7273

7274
    qemuDriverLock(driver);
7275
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
7276
    if (!vm) {
7277 7278
        qemudReportError (dconn, NULL, NULL, VIR_ERR_NO_DOMAIN,
                          _("no domain with matching name '%s'"), dname);
7279
        goto cleanup;
D
Daniel Veillard 已提交
7280 7281
    }

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

D
Daniel Veillard 已提交
7285 7286 7287 7288
    /* 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 已提交
7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304
        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;
7305
                goto endjob;
C
Chris Lalancette 已提交
7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316
            }

            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_DEFINED,
                                             newVM ?
                                             VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                             VIR_DOMAIN_EVENT_DEFINED_UPDATED);
            if (event)
                qemuDomainEventQueue(driver, event);

        }
7317
        qemuDomainObjPrivatePtr priv = vm->privateData;
D
Daniel Veillard 已提交
7318
        dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
7319 7320 7321 7322 7323

        /* 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
         */
7324
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7325
        if (qemuMonitorStartCPUs(priv->mon, dconn) < 0) {
7326 7327 7328
            if (virGetLastError() == NULL)
                qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                 "%s", _("resume operation failed"));
7329 7330
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto endjob;
7331
        }
7332
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7333

D
Daniel Veillard 已提交
7334
        vm->state = VIR_DOMAIN_RUNNING;
7335 7336 7337
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
D
Daniel Veillard 已提交
7338
        virDomainSaveStatus(dconn, driver->stateDir, vm);
D
Daniel Veillard 已提交
7339 7340
    } else {
        qemudShutdownVMDaemon (dconn, driver, vm);
7341 7342 7343
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
7344
        if (!vm->persistent) {
7345
            qemuDomainObjEndJob(vm);
D
Daniel Veillard 已提交
7346
            virDomainRemoveInactive(&driver->domains, vm);
7347 7348
            vm = NULL;
        }
D
Daniel Veillard 已提交
7349
    }
7350

7351 7352 7353 7354
endjob:
    if (vm)
        qemuDomainObjEndJob(vm);

7355
cleanup:
7356 7357
    if (vm)
        virDomainObjUnlock(vm);
7358 7359
    if (event)
        qemuDomainEventQueue(driver, event);
7360
    qemuDriverUnlock(driver);
7361
    return dom;
D
Daniel Veillard 已提交
7362 7363
}

7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379
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;

7380
    def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458
    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)
{
7459
    struct qemud_driver *driver = dev->conn->privateData;
7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470
    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;

7471 7472 7473
    qemuDriverLock(driver);

    if (pciResetDevice(dev->conn, pci, driver->activePciHostdevs) < 0)
7474 7475 7476 7477
        goto out;

    ret = 0;
out:
7478
    qemuDriverUnlock(driver);
7479 7480 7481 7482
    pciFreeDevice(dev->conn, pci);
    return ret;
}

7483 7484 7485 7486 7487
static virDriver qemuDriver = {
    VIR_DRV_QEMU,
    "QEMU",
    qemudOpen, /* open */
    qemudClose, /* close */
D
Daniel Veillard 已提交
7488
    qemudSupportsFeature, /* supports_feature */
7489 7490
    qemudGetType, /* type */
    qemudGetVersion, /* version */
7491
    NULL, /* libvirtVersion (impl. in libvirt.c) */
7492
    virGetHostname, /* getHostname */
7493
    qemudGetMaxVCPUs, /* getMaxVcpus */
7494
    nodeGetInfo, /* nodeGetInfo */
7495 7496 7497
    qemudGetCapabilities, /* getCapabilities */
    qemudListDomains, /* listDomains */
    qemudNumDomains, /* numOfDomains */
7498
    qemudDomainCreate, /* domainCreateXML */
7499 7500 7501 7502 7503
    qemudDomainLookupByID, /* domainLookupByID */
    qemudDomainLookupByUUID, /* domainLookupByUUID */
    qemudDomainLookupByName, /* domainLookupByName */
    qemudDomainSuspend, /* domainSuspend */
    qemudDomainResume, /* domainResume */
7504
    qemudDomainShutdown, /* domainShutdown */
7505 7506 7507
    NULL, /* domainReboot */
    qemudDomainDestroy, /* domainDestroy */
    qemudDomainGetOSType, /* domainGetOSType */
7508 7509 7510
    qemudDomainGetMaxMemory, /* domainGetMaxMemory */
    qemudDomainSetMaxMemory, /* domainSetMaxMemory */
    qemudDomainSetMemory, /* domainSetMemory */
7511 7512 7513
    qemudDomainGetInfo, /* domainGetInfo */
    qemudDomainSave, /* domainSave */
    qemudDomainRestore, /* domainRestore */
P
Paolo Bonzini 已提交
7514
    qemudDomainCoreDump, /* domainCoreDump */
7515
    qemudDomainSetVcpus, /* domainSetVcpus */
7516 7517 7518 7519
#if HAVE_SCHED_GETAFFINITY
    qemudDomainPinVcpu, /* domainPinVcpu */
    qemudDomainGetVcpus, /* domainGetVcpus */
#else
7520 7521
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
7522
#endif
7523
    qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
7524 7525
    qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
    qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
7526
    qemudDomainDumpXML, /* domainDumpXML */
7527
    qemuDomainXMLFromNative, /* domainXmlFromNative */
7528
    qemuDomainXMLToNative, /* domainXMLToNative */
7529 7530
    qemudListDefinedDomains, /* listDefinedDomains */
    qemudNumDefinedDomains, /* numOfDefinedDomains */
7531 7532 7533
    qemudDomainStart, /* domainCreate */
    qemudDomainDefine, /* domainDefineXML */
    qemudDomainUndefine, /* domainUndefine */
7534
    qemudDomainAttachDevice, /* domainAttachDevice */
7535
    qemudDomainDetachDevice, /* domainDetachDevice */
7536 7537
    qemudDomainGetAutostart, /* domainGetAutostart */
    qemudDomainSetAutostart, /* domainSetAutostart */
7538 7539 7540
    qemuGetSchedulerType, /* domainGetSchedulerType */
    qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
    qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
7541 7542
    NULL, /* domainMigratePrepare (v1) */
    qemudDomainMigratePerform, /* domainMigratePerform */
7543
    NULL, /* domainMigrateFinish */
7544
    qemudDomainBlockStats, /* domainBlockStats */
7545
    qemudDomainInterfaceStats, /* domainInterfaceStats */
7546
    qemudDomainBlockPeek, /* domainBlockPeek */
R
Richard W.M. Jones 已提交
7547
    qemudDomainMemoryPeek, /* domainMemoryPeek */
7548 7549
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
7550 7551
    qemudDomainEventRegister, /* domainEventRegister */
    qemudDomainEventDeregister, /* domainEventDeregister */
D
Daniel Veillard 已提交
7552 7553
    qemudDomainMigratePrepare2, /* domainMigratePrepare2 */
    qemudDomainMigrateFinish2, /* domainMigrateFinish2 */
7554 7555 7556
    qemudNodeDeviceDettach, /* nodeDeviceDettach */
    qemudNodeDeviceReAttach, /* nodeDeviceReAttach */
    qemudNodeDeviceReset, /* nodeDeviceReset */
C
Chris Lalancette 已提交
7557
    qemudDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
7558 7559 7560 7561
    qemuIsEncrypted,
    qemuIsSecure,
    qemuDomainIsActive,
    qemuDomainIsPersistent,
7562 7563 7564
};


7565
static virStateDriver qemuStateDriver = {
7566
    .name = "QEMU",
7567 7568 7569 7570
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
7571
};
7572

7573
int qemuRegister(void) {
7574 7575 7576 7577
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
    return 0;
}