qemu_driver.c 344.9 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, 2010 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
#ifdef __linux__
51 52 53 54
# include <sys/vfs.h>
# ifndef NFS_SUPER_MAGIC
#  define NFS_SUPER_MAGIC 0x6969
# endif /* NFS_SUPER_MAGIC */
55
#endif /* __linux__ */
56

57
#include "virterror_internal.h"
58
#include "logging.h"
59
#include "datatypes.h"
60 61
#include "qemu_driver.h"
#include "qemu_conf.h"
62
#include "qemu_monitor.h"
63
#include "qemu_monitor_text.h"
64
#include "qemu_bridge_filter.h"
J
Jim Meyering 已提交
65
#include "c-ctype.h"
66
#include "event.h"
67
#include "buf.h"
68
#include "util.h"
69
#include "nodeinfo.h"
70
#include "stats_linux.h"
71
#include "capabilities.h"
72
#include "memory.h"
73
#include "uuid.h"
74
#include "domain_conf.h"
75 76
#include "node_device_conf.h"
#include "pci.h"
77
#include "hostusb.h"
78
#include "processinfo.h"
79 80
#include "qemu_security_stacked.h"
#include "qemu_security_dac.h"
81
#include "cgroup.h"
C
Chris Lalancette 已提交
82
#include "libvirt_internal.h"
83
#include "xml.h"
84
#include "cpu/cpu.h"
85
#include "macvtap.h"
S
Stefan Berger 已提交
86
#include "nwfilter/nwfilter_gentech_driver.h"
87
#include "hooks.h"
88

89

90 91
#define VIR_FROM_THIS VIR_FROM_QEMU

92 93 94 95 96 97 98 99 100 101 102 103
/* Only 1 job is allowed at any time
 * A job includes *all* monitor commands, even those just querying
 * information, not merely actions */
enum qemuDomainJob {
    QEMU_JOB_NONE = 0,  /* Always set to 0 for easy if (jobActive) conditions */
    QEMU_JOB_UNSPECIFIED,
    QEMU_JOB_MIGRATION,
};

enum qemuDomainJobSignals {
    QEMU_JOB_SIGNAL_CANCEL  = 1 << 0, /* Request job cancellation */
    QEMU_JOB_SIGNAL_SUSPEND = 1 << 1, /* Request VM suspend to finish live migration offline */
104 105 106 107 108
    QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME = 1 << 2, /* Request migration downtime change */
};

struct qemuDomainJobSignalsData {
    unsigned long long migrateDowntime; /* Data for QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME */
109 110
};

111 112 113
typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate;
typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr;
struct _qemuDomainObjPrivate {
114
    virCond jobCond; /* Use in conjunction with main virDomainObjPtr lock */
115 116
    enum qemuDomainJob jobActive;   /* Currently running job */
    unsigned int jobSignals;        /* Signals for running job */
117
    struct qemuDomainJobSignalsData jobSignalsData; /* Signal specific data */
118 119
    virDomainJobInfo jobInfo;
    unsigned long long jobStart;
120

121
    qemuMonitorPtr mon;
122
    virDomainChrDefPtr monConfig;
D
Daniel P. Berrange 已提交
123
    int monJSON;
124 125 126

    int nvcpupids;
    int *vcpupids;
127 128

    qemuDomainPCIAddressSetPtr pciaddrs;
129
    int persistentAddrs;
130 131
};

132 133
static int qemudShutdown(void);

134 135
static void qemuDriverLock(struct qemud_driver *driver)
{
136
    virMutexLock(&driver->lock);
137 138 139
}
static void qemuDriverUnlock(struct qemud_driver *driver)
{
140
    virMutexUnlock(&driver->lock);
141 142
}

143 144 145
static void qemuDomainEventFlush(int timer, void *opaque);
static void qemuDomainEventQueue(struct qemud_driver *driver,
                                 virDomainEventPtr event);
146

147 148
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
149
                              virDomainObjPtr vm,
150 151
                              const char *migrateFrom,
                              int stdin_fd);
152

153
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
154
                                  virDomainObjPtr vm);
155

156
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
157

158
static int qemuDetectVcpuPIDs(struct qemud_driver *driver,
159
                              virDomainObjPtr vm);
160

161 162 163
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                                       virDomainDefPtr def);

J
Jim Meyering 已提交
164
static struct qemud_driver *qemu_driver = NULL;
165

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

static void *qemuDomainObjPrivateAlloc(void)
{
    qemuDomainObjPrivatePtr priv;

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

    return priv;
}

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

181
    qemuDomainPCIAddressSetFree(priv->pciaddrs);
182 183 184
    virDomainChrDefFree(priv->monConfig);
    VIR_FREE(priv->vcpupids);

185 186 187 188 189 190 191 192 193
    /* 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);
}


194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
static int qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void *data)
{
    qemuDomainObjPrivatePtr priv = data;
    const char *monitorpath;

    /* priv->monitor_chr is set only for qemu */
    if (priv->monConfig) {
        switch (priv->monConfig->type) {
        case VIR_DOMAIN_CHR_TYPE_UNIX:
            monitorpath = priv->monConfig->data.nix.path;
            break;
        default:
        case VIR_DOMAIN_CHR_TYPE_PTY:
            monitorpath = priv->monConfig->data.file.path;
            break;
        }

        virBufferEscapeString(buf, "  <monitor path='%s'", monitorpath);
D
Daniel P. Berrange 已提交
212 213
        if (priv->monJSON)
            virBufferAddLit(buf, " json='1'");
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
        virBufferVSprintf(buf, " type='%s'/>\n",
                          virDomainChrTypeToString(priv->monConfig->type));
    }


    if (priv->nvcpupids) {
        int i;
        virBufferAddLit(buf, "  <vcpus>\n");
        for (i = 0 ; i < priv->nvcpupids ; i++) {
            virBufferVSprintf(buf, "    <vcpu pid='%d'/>\n", priv->vcpupids[i]);
        }
        virBufferAddLit(buf, "  </vcpus>\n");
    }

    return 0;
}

static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data)
{
    qemuDomainObjPrivatePtr priv = data;
    char *monitorpath;
    char *tmp;
    int n, i;
    xmlNodePtr *nodes = NULL;

    if (VIR_ALLOC(priv->monConfig) < 0) {
240
        virReportOOMError();
241 242 243
        goto error;
    }

244
    if (!(priv->monConfig->info.alias = strdup("monitor"))) {
245
        virReportOOMError();
246 247 248
        goto error;
    }

249
    if (!(monitorpath =
250
          virXPathString("string(./monitor[1]/@path)", ctxt))) {
251 252
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no monitor path"));
253 254 255
        goto error;
    }

256
    tmp = virXPathString("string(./monitor[1]/@type)", ctxt);
257 258 259 260 261 262
    if (tmp)
        priv->monConfig->type = virDomainChrTypeFromString(tmp);
    else
        priv->monConfig->type = VIR_DOMAIN_CHR_TYPE_PTY;
    VIR_FREE(tmp);

263
    if (virXPathBoolean("count(./monitor[@json = '1']) > 0", ctxt)) {
D
Daniel P. Berrange 已提交
264
        priv->monJSON = 1;
265 266 267
    } else {
        priv->monJSON = 0;
    }
D
Daniel P. Berrange 已提交
268

269 270 271 272 273 274 275 276 277
    switch (priv->monConfig->type) {
    case VIR_DOMAIN_CHR_TYPE_PTY:
        priv->monConfig->data.file.path = monitorpath;
        break;
    case VIR_DOMAIN_CHR_TYPE_UNIX:
        priv->monConfig->data.nix.path = monitorpath;
        break;
    default:
        VIR_FREE(monitorpath);
278 279 280
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unsupported monitor type '%s'"),
                        virDomainChrTypeToString(priv->monConfig->type));
281 282 283
        goto error;
    }

284
    n = virXPathNodeSet("./vcpus/vcpu", ctxt, &nodes);
285 286 287 288 289
    if (n < 0)
        goto error;
    if (n) {
        priv->nvcpupids = n;
        if (VIR_REALLOC_N(priv->vcpupids, priv->nvcpupids) < 0) {
290
            virReportOOMError();
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
            goto error;
        }

        for (i = 0 ; i < n ; i++) {
            char *pidstr = virXMLPropString(nodes[i], "pid");
            if (!pidstr)
                goto error;

            if (virStrToLong_i(pidstr, NULL, 10, &(priv->vcpupids[i])) < 0) {
                VIR_FREE(pidstr);
                goto error;
            }
            VIR_FREE(pidstr);
        }
        VIR_FREE(nodes);
    }

    return 0;

error:
311 312
    virDomainChrDefFree(priv->monConfig);
    priv->monConfig = NULL;
313 314 315 316 317 318
    VIR_FREE(nodes);
    return -1;
}



319 320 321 322 323 324 325 326 327
/*
 * 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
 */
328 329 330 331

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

332 333 334 335
static int qemuDomainObjBeginJob(virDomainObjPtr obj) ATTRIBUTE_RETURN_CHECK;
static int qemuDomainObjBeginJob(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;
336 337 338 339
    struct timeval now;
    unsigned long long then;

    if (gettimeofday(&now, NULL) < 0) {
340
        virReportSystemError(errno, "%s",
341 342 343 344 345
                             _("cannot get time of day"));
        return -1;
    }
    then = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    then += QEMU_JOB_WAIT_TIME;
346 347 348 349

    virDomainObjRef(obj);

    while (priv->jobActive) {
350
        if (virCondWaitUntil(&priv->jobCond, &obj->lock, then) < 0) {
351
            virDomainObjUnref(obj);
352
            if (errno == ETIMEDOUT)
353 354
                qemuReportError(VIR_ERR_OPERATION_TIMEOUT,
                                "%s", _("cannot acquire state change lock"));
355
            else
356
                virReportSystemError(errno,
357
                                     "%s", _("cannot acquire job mutex"));
358 359 360
            return -1;
        }
    }
361 362
    priv->jobActive = QEMU_JOB_UNSPECIFIED;
    priv->jobSignals = 0;
363
    memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData));
364 365
    priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381

    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;
382 383 384 385
    struct timeval now;
    unsigned long long then;

    if (gettimeofday(&now, NULL) < 0) {
386
        virReportSystemError(errno, "%s",
387 388 389 390 391
                             _("cannot get time of day"));
        return -1;
    }
    then = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    then += QEMU_JOB_WAIT_TIME;
392 393 394 395 396

    virDomainObjRef(obj);
    qemuDriverUnlock(driver);

    while (priv->jobActive) {
397
        if (virCondWaitUntil(&priv->jobCond, &obj->lock, then) < 0) {
398
            virDomainObjUnref(obj);
399
            if (errno == ETIMEDOUT)
400 401
                qemuReportError(VIR_ERR_OPERATION_TIMEOUT,
                                "%s", _("cannot acquire state change lock"));
402
            else
403
                virReportSystemError(errno,
404
                                     "%s", _("cannot acquire job mutex"));
M
Matthias Bolte 已提交
405
            qemuDriverLock(driver);
406 407 408
            return -1;
        }
    }
409 410
    priv->jobActive = QEMU_JOB_UNSPECIFIED;
    priv->jobSignals = 0;
411
    memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData));
412 413
    priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
414 415 416 417 418 419 420 421 422 423 424 425 426

    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
427 428 429
 *
 * Returns remaining refcount on 'obj', maybe 0 to indicated it
 * was deleted
430
 */
431
static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj)
432 433 434
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

435 436
    priv->jobActive = QEMU_JOB_NONE;
    priv->jobSignals = 0;
437
    memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData));
438 439
    priv->jobStart = 0;
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
440 441
    virCondSignal(&priv->jobCond);

442
    return virDomainObjUnref(obj);
443 444 445 446 447 448 449 450 451 452 453
}


/*
 * 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
 */
454 455 456 457 458
static void qemuDomainObjEnterMonitor(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    qemuMonitorLock(priv->mon);
459
    qemuMonitorRef(priv->mon);
460
    virDomainObjUnlock(obj);
461 462 463
}


464 465 466 467
/* obj must NOT be locked before calling, qemud_driver must be unlocked
 *
 * Should be paired with an earlier  qemuDomainObjEnterMonitor() call
 */
468 469 470
static void qemuDomainObjExitMonitor(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;
471 472 473 474 475 476
    int refs;

    refs = qemuMonitorUnref(priv->mon);

    if (refs > 0)
        qemuMonitorUnlock(priv->mon);
477

478
    virDomainObjLock(obj);
479 480 481 482 483

    if (refs == 0) {
        virDomainObjUnref(obj);
        priv->mon = NULL;
    }
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
}


/*
 * 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);
500
    qemuMonitorRef(priv->mon);
501 502 503 504 505 506 507 508 509 510 511 512 513
    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;
514 515 516 517 518 519
    int refs;

    refs = qemuMonitorUnref(priv->mon);

    if (refs > 0)
        qemuMonitorUnlock(priv->mon);
520 521 522

    qemuDriverLock(driver);
    virDomainObjLock(obj);
523 524 525 526 527

    if (refs == 0) {
        virDomainObjUnref(obj);
        priv->mon = NULL;
    }
528 529 530
}


531 532 533 534 535 536 537 538 539
static int qemuCgroupControllerActive(struct qemud_driver *driver,
                                      int controller)
{
    if (driver->cgroup == NULL)
        return 0;
    if (driver->cgroupControllers & (1 << controller))
        return 1;
    return 0;
}
540

541
static int
542
qemudLogFD(struct qemud_driver *driver, const char* name)
543 544 545
{
    char logfile[PATH_MAX];
    mode_t logmode;
G
Guido Günther 已提交
546
    int ret, fd = -1;
547

548 549
    if ((ret = snprintf(logfile, sizeof(logfile), "%s/%s.log",
                        driver->logDir, name))
G
Guido Günther 已提交
550
        < 0 || ret >= sizeof(logfile)) {
551
        virReportOOMError();
552 553 554 555
        return -1;
    }

    logmode = O_CREAT | O_WRONLY;
556 557
    /* Only logrotate files in /var/log, so only append if running privileged */
    if (driver->privileged)
558
        logmode |= O_APPEND;
559 560 561
    else
        logmode |= O_TRUNC;

562
    if ((fd = open(logfile, logmode, S_IRUSR | S_IWUSR)) < 0) {
563
        virReportSystemError(errno,
564 565
                             _("failed to create logfile %s"),
                             logfile);
566 567
        return -1;
    }
568
    if (virSetCloseExec(fd) < 0) {
569
        virReportSystemError(errno, "%s",
570
                             _("Unable to set VM logfile close-on-exec flag"));
571 572 573 574 575 576 577
        close(fd);
        return -1;
    }
    return fd;
}


578
static int
579
qemudLogReadFD(const char* logDir, const char* name, off_t pos)
580 581 582 583 584 585 586
{
    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)) {
587 588 589
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("failed to build logfile name %s/%s.log"),
                        logDir, name);
590 591 592 593 594
        return -1;
    }


    if ((fd = open(logfile, logmode)) < 0) {
595
        virReportSystemError(errno,
596 597
                             _("failed to create logfile %s"),
                             logfile);
598 599
        return -1;
    }
600
    if (virSetCloseExec(fd) < 0) {
601
        virReportSystemError(errno, "%s",
602
                             _("Unable to set VM logfile close-on-exec flag"));
603 604 605
        close(fd);
        return -1;
    }
606
    if (pos < 0 || lseek(fd, pos, SEEK_SET) < 0) {
607
      virReportSystemError(pos < 0 ? 0 : errno,
608 609
                             _("Unable to seek to %lld in %s"),
                             (long long) pos, logfile);
610 611 612 613 614 615
        close(fd);
    }
    return fd;
}


616 617 618 619 620 621 622 623 624 625 626 627
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 已提交
628
        !virDomainObjIsActive(vm)) {
629 630 631 632 633 634
        int ret;

        virResetLastError();
        ret = qemudStartVMDaemon(data->conn, data->driver, vm, NULL, -1);
        if (ret < 0) {
            virErrorPtr err = virGetLastError();
635
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
636 637 638 639 640 641 642 643 644 645 646 647 648 649
                      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);
}

650 651
static void
qemudAutostartConfigs(struct qemud_driver *driver) {
652 653 654 655 656
    /* 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
     */
657 658 659
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
660
    /* Ignoring NULL conn which is mostly harmless here */
661
    struct qemuAutostartData data = { driver, conn };
662

663
    qemuDriverLock(driver);
664
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
665
    qemuDriverUnlock(driver);
666

667 668
    if (conn)
        virConnectClose(conn);
669 670
}

671 672 673 674 675 676 677 678 679

/**
 * qemudRemoveDomainStatus
 *
 * remove all state files of a domain from statedir
 *
 * Returns 0 on success
 */
static int
680
qemudRemoveDomainStatus(struct qemud_driver *driver,
681 682
                        virDomainObjPtr vm)
{
683
    char ebuf[1024];
684 685 686
    char *file = NULL;

    if (virAsprintf(&file, "%s/%s.xml", driver->stateDir, vm->def->name) < 0) {
687
        virReportOOMError();
D
Daniel Veillard 已提交
688
        return(-1);
689 690
    }

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

696 697 698
    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)));
699

D
Daniel Veillard 已提交
700

701
    return 0;
702 703
}

704 705 706 707 708 709 710 711 712 713 714 715 716 717

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

718
    VIR_DEBUG("Received EOF on %p '%s'", vm, vm->def->name);
719 720 721 722 723 724 725 726
    virDomainObjLock(vm);

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

727
    qemudShutdownVMDaemon(driver, vm);
728 729 730 731 732 733 734 735 736 737 738 739 740
    if (!vm->persistent)
        virDomainRemoveInactive(&driver->domains, vm);
    else
        virDomainObjUnlock(vm);

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


741 742 743
static virDomainDiskDefPtr
findDomainDiskByPath(virDomainObjPtr vm,
                     const char *path)
744 745 746 747 748 749 750
{
    int i;

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

        disk = vm->def->disks[i];
751 752
        if (disk->src != NULL && STREQ(disk->src, path))
            return disk;
753
    }
754 755 756 757

    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                    _("no disk found with path %s"),
                    path);
758 759 760
    return NULL;
}

761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
static virDomainDiskDefPtr
findDomainDiskByAlias(virDomainObjPtr vm,
                      const char *alias)
{
    int i;

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

        disk = vm->def->disks[i];
        if (disk->info.alias != NULL && STREQ(disk->info.alias, alias))
            return disk;
    }

    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                    _("no disk found with alias %s"),
                    alias);
    return NULL;
}

781
static int
782 783 784 785
getVolumeQcowPassphrase(virConnectPtr conn,
                        virDomainDiskDefPtr disk,
                        char **secretRet,
                        size_t *secretLen)
786 787 788 789 790
{
    virSecretPtr secret;
    char *passphrase;
    unsigned char *data;
    size_t size;
791
    int ret = -1;
792
    virStorageEncryptionPtr enc;
793

794 795 796 797 798 799 800
    if (!disk->encryption) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("disk %s does not have any encryption information"),
                        disk->src);
        return -1;
    }
    enc = disk->encryption;
801 802

    if (!conn) {
803 804
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cannot find secrets without a connection"));
805
        goto cleanup;
806 807 808 809 810
    }

    if (conn->secretDriver == NULL ||
        conn->secretDriver->lookupByUUID == NULL ||
        conn->secretDriver->getValue == NULL) {
811 812
        qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                        _("secret storage not supported"));
813
        goto cleanup;
814 815 816 817 818 819
    }

    if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW ||
        enc->nsecrets != 1 ||
        enc->secrets[0]->type !=
        VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) {
820
        qemuReportError(VIR_ERR_INVALID_DOMAIN,
821
                        _("invalid <encryption> for volume %s"), disk->src);
822
        goto cleanup;
823 824 825 826 827
    }

    secret = conn->secretDriver->lookupByUUID(conn,
                                              enc->secrets[0]->uuid);
    if (secret == NULL)
828
        goto cleanup;
829 830 831 832
    data = conn->secretDriver->getValue(secret, &size,
                                        VIR_SECRET_GET_VALUE_INTERNAL_CALL);
    virUnrefSecret(secret);
    if (data == NULL)
833
        goto cleanup;
834 835 836 837

    if (memchr(data, '\0', size) != NULL) {
        memset(data, 0, size);
        VIR_FREE(data);
838 839
        qemuReportError(VIR_ERR_INVALID_SECRET,
                        _("format='qcow' passphrase for %s must not contain a "
840
                          "'\\0'"), disk->src);
841
        goto cleanup;
842 843 844 845 846
    }

    if (VIR_ALLOC_N(passphrase, size + 1) < 0) {
        memset(data, 0, size);
        VIR_FREE(data);
847
        virReportOOMError();
848
        goto cleanup;
849 850 851 852 853 854 855 856 857 858
    }
    memcpy(passphrase, data, size);
    passphrase[size] = '\0';

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

    *secretRet = passphrase;
    *secretLen = size;

859 860 861
    ret = 0;

cleanup:
862 863
    return ret;
}
864

865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
static int
findVolumeQcowPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                         virConnectPtr conn,
                         virDomainObjPtr vm,
                         const char *path,
                         char **secretRet,
                         size_t *secretLen)
{
    virDomainDiskDefPtr disk;
    int ret = -1;

    virDomainObjLock(vm);
    disk = findDomainDiskByPath(vm, path);

    if (!disk)
        goto cleanup;

    ret = getVolumeQcowPassphrase(conn, disk, secretRet, secretLen);

cleanup:
    virDomainObjUnlock(vm);
886
    return ret;
887 888
}

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910

static int
qemuHandleDomainReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                      virDomainObjPtr vm)
{
    struct qemud_driver *driver = qemu_driver;
    virDomainEventPtr event;

    virDomainObjLock(vm);
    event = virDomainEventRebootNewFromObj(vm);
    virDomainObjUnlock(vm);

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

    return 0;
}


911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
static int
qemuHandleDomainStop(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                     virDomainObjPtr vm)
{
    struct qemud_driver *driver = qemu_driver;
    virDomainEventPtr event = NULL;

    virDomainObjLock(vm);
    if (vm->state == VIR_DOMAIN_RUNNING) {
        VIR_DEBUG("Transitioned guest %s to paused state due to unknown event", vm->def->name);

        vm->state = VIR_DOMAIN_PAUSED;
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);

        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
    }
    virDomainObjUnlock(vm);

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

    return 0;
}


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
static int
qemuHandleDomainRTCChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                          virDomainObjPtr vm,
                          long long offset)
{
    struct qemud_driver *driver = qemu_driver;
    virDomainEventPtr event;

    virDomainObjLock(vm);
    event = virDomainEventRTCChangeNewFromObj(vm, offset);

    if (vm->def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_VARIABLE)
        vm->def->clock.data.adjustment = offset;

    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        VIR_WARN0("unable to save domain status with RTC change");

    virDomainObjUnlock(vm);

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

    return 0;
}


972 973 974 975 976 977
static int
qemuHandleDomainWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                         virDomainObjPtr vm,
                         int action)
{
    struct qemud_driver *driver = qemu_driver;
978 979
    virDomainEventPtr watchdogEvent = NULL;
    virDomainEventPtr lifecycleEvent = NULL;
980 981

    virDomainObjLock(vm);
982 983 984 985 986 987 988 989 990 991 992 993 994 995
    watchdogEvent = virDomainEventWatchdogNewFromObj(vm, action);

    if (action == VIR_DOMAIN_EVENT_WATCHDOG_PAUSE &&
        vm->state == VIR_DOMAIN_RUNNING) {
        VIR_DEBUG("Transitioned guest %s to paused state due to watchdog", vm->def->name);

        vm->state = VIR_DOMAIN_PAUSED;
        lifecycleEvent = virDomainEventNewFromObj(vm,
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG);

        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
    }
996 997
    virDomainObjUnlock(vm);

998
    if (watchdogEvent || lifecycleEvent) {
999
        qemuDriverLock(driver);
1000 1001 1002 1003
        if (watchdogEvent)
            qemuDomainEventQueue(driver, watchdogEvent);
        if (lifecycleEvent)
            qemuDomainEventQueue(driver, lifecycleEvent);
1004 1005 1006 1007 1008 1009 1010
        qemuDriverUnlock(driver);
    }

    return 0;
}


1011 1012 1013 1014 1015 1016 1017
static int
qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                        virDomainObjPtr vm,
                        const char *diskAlias,
                        int action)
{
    struct qemud_driver *driver = qemu_driver;
1018 1019
    virDomainEventPtr ioErrorEvent = NULL;
    virDomainEventPtr lifecycleEvent = NULL;
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
    const char *srcPath;
    const char *devAlias;
    virDomainDiskDefPtr disk;

    virDomainObjLock(vm);
    disk = findDomainDiskByAlias(vm, diskAlias);

    if (disk) {
        srcPath = disk->src;
        devAlias = disk->info.alias;
    } else {
        srcPath = "";
        devAlias = "";
    }

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
    ioErrorEvent = virDomainEventIOErrorNewFromObj(vm, srcPath, devAlias, action);

    if (action == VIR_DOMAIN_EVENT_IO_ERROR_PAUSE &&
        vm->state == VIR_DOMAIN_RUNNING) {
        VIR_DEBUG("Transitioned guest %s to paused state due to IO error", vm->def->name);

        vm->state = VIR_DOMAIN_PAUSED;
        lifecycleEvent = virDomainEventNewFromObj(vm,
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  VIR_DOMAIN_EVENT_SUSPENDED_IOERROR);

        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
    }
1049 1050
    virDomainObjUnlock(vm);

1051
    if (ioErrorEvent || lifecycleEvent) {
1052
        qemuDriverLock(driver);
1053 1054 1055 1056
        if (ioErrorEvent)
            qemuDomainEventQueue(driver, ioErrorEvent);
        if (lifecycleEvent)
            qemuDomainEventQueue(driver, lifecycleEvent);
1057 1058 1059 1060 1061 1062 1063
        qemuDriverUnlock(driver);
    }

    return 0;
}


1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
static int
qemuHandleDomainGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                         virDomainObjPtr vm,
                         int phase,
                         int localFamily,
                         const char *localNode,
                         const char *localService,
                         int remoteFamily,
                         const char *remoteNode,
                         const char *remoteService,
                         const char *authScheme,
                         const char *x509dname,
                         const char *saslUsername)
{
    struct qemud_driver *driver = qemu_driver;
    virDomainEventPtr event;
    virDomainEventGraphicsAddressPtr localAddr = NULL;
    virDomainEventGraphicsAddressPtr remoteAddr = NULL;
    virDomainEventGraphicsSubjectPtr subject = NULL;
    int i;

    virDomainObjLock(vm);

    if (VIR_ALLOC(localAddr) < 0)
        goto no_memory;
    localAddr->family = localFamily;
    if (!(localAddr->service = strdup(localService)) ||
        !(localAddr->node = strdup(localNode)))
        goto no_memory;

    if (VIR_ALLOC(remoteAddr) < 0)
        goto no_memory;
    remoteAddr->family = remoteFamily;
    if (!(remoteAddr->service = strdup(remoteService)) ||
        !(remoteAddr->node = strdup(remoteNode)))
        goto no_memory;

    if (VIR_ALLOC(subject) < 0)
        goto no_memory;
    if (x509dname) {
        if (VIR_REALLOC_N(subject->identities, subject->nidentity+1) < 0)
            goto no_memory;
        if (!(subject->identities[subject->nidentity].type = strdup("x509dname")) ||
            !(subject->identities[subject->nidentity].name = strdup(x509dname)))
            goto no_memory;
        subject->nidentity++;
    }
    if (saslUsername) {
        if (VIR_REALLOC_N(subject->identities, subject->nidentity+1) < 0)
            goto no_memory;
        if (!(subject->identities[subject->nidentity].type = strdup("saslUsername")) ||
            !(subject->identities[subject->nidentity].name = strdup(saslUsername)))
            goto no_memory;
        subject->nidentity++;
    }

    event = virDomainEventGraphicsNewFromObj(vm, phase, localAddr, remoteAddr, authScheme, subject);
    virDomainObjUnlock(vm);

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

    return 0;

no_memory:
    virReportOOMError();
    if (localAddr) {
        VIR_FREE(localAddr->service);
        VIR_FREE(localAddr->node);
        VIR_FREE(localAddr);
    }
    if (remoteAddr) {
        VIR_FREE(remoteAddr->service);
        VIR_FREE(remoteAddr->node);
        VIR_FREE(remoteAddr);
    }
    if (subject) {
        for (i = 0 ; i < subject->nidentity ; i++) {
            VIR_FREE(subject->identities[i].type);
            VIR_FREE(subject->identities[i].name);
        }
        VIR_FREE(subject->identities);
        VIR_FREE(subject);
    }

    return -1;
}


1156 1157 1158
static qemuMonitorCallbacks monitorCallbacks = {
    .eofNotify = qemuHandleMonitorEOF,
    .diskSecretLookup = findVolumeQcowPassphrase,
1159
    .domainStop = qemuHandleDomainStop,
1160
    .domainReset = qemuHandleDomainReset,
1161
    .domainRTCChange = qemuHandleDomainRTCChange,
1162
    .domainWatchdog = qemuHandleDomainWatchdog,
1163
    .domainIOError = qemuHandleDomainIOError,
1164
    .domainGraphics = qemuHandleDomainGraphics,
1165 1166
};

1167
static int
1168
qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
1169
{
1170
    qemuDomainObjPrivatePtr priv = vm->privateData;
1171
    int ret;
1172

1173 1174 1175 1176
    /* Hold an extra reference because we can't allow 'vm' to be
     * deleted while the monitor is active */
    virDomainObjRef(vm);

1177 1178
    if ((priv->mon = qemuMonitorOpen(vm,
                                     priv->monConfig,
D
Daniel P. Berrange 已提交
1179
                                     priv->monJSON,
1180
                                     &monitorCallbacks)) == NULL) {
1181
        VIR_ERROR(_("Failed to connect monitor for %s"), vm->def->name);
1182
        return -1;
1183
    }
1184

1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorSetCapabilities(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (ret < 0) {
        qemuMonitorClose(priv->mon);
        priv->mon = NULL;
    }

    return ret;
1195
}
1196 1197 1198 1199

/*
 * Open an existing VM's monitor, re-detect VCPU threads
 * and re-reserve the security labels in use
1200
 */
1201 1202
static void
qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
1203
{
1204 1205
    virDomainObjPtr obj = payload;
    struct qemud_driver *driver = opaque;
1206
    qemuDomainObjPrivatePtr priv;
1207
    unsigned long long qemuCmdFlags;
1208 1209

    virDomainObjLock(obj);
1210

1211 1212
    VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name);

1213 1214
    priv = obj->privateData;

1215
    /* XXX check PID liveliness & EXE path */
1216
    if (qemuConnectMonitor(driver, obj) < 0)
1217
        goto error;
1218

1219 1220 1221 1222
    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
        goto error;
    }

1223 1224 1225 1226 1227 1228 1229 1230 1231
    /* XXX we should be persisting the original flags in the XML
     * not re-detecting them, since the binary may have changed
     * since launch time */
    if (qemudExtractVersionInfo(obj->def->emulator,
                                NULL,
                                &qemuCmdFlags) >= 0 &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
        priv->persistentAddrs = 1;

1232 1233 1234
    if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(obj->def)))
        goto error;

1235
    if (driver->securityDriver &&
1236
        driver->securityDriver->domainReserveSecurityLabel &&
1237
        driver->securityDriver->domainReserveSecurityLabel(obj) < 0)
1238
        goto error;
1239

1240 1241
    if (obj->def->id >= driver->nextvmid)
        driver->nextvmid = obj->def->id + 1;
1242

1243 1244
    virDomainObjUnlock(obj);
    return;
1245

1246
error:
1247 1248 1249
    /* 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 */
1250
    qemudShutdownVMDaemon(driver, obj);
1251 1252 1253 1254
    if (!obj->persistent)
        virDomainRemoveInactive(&driver->domains, obj);
    else
        virDomainObjUnlock(obj);
1255
}
1256

1257
/**
1258
 * qemudReconnectDomains
1259 1260 1261 1262 1263 1264 1265
 *
 * Try to re-open the resources for live VMs that we care
 * about.
 */
static void
qemuReconnectDomains(struct qemud_driver *driver)
{
1266
    virHashForEach(driver->domains.objs, qemuReconnectDomain, driver);
1267 1268
}

1269

1270 1271 1272 1273 1274 1275
static int
qemudSecurityInit(struct qemud_driver *qemud_drv)
{
    int ret;
    virSecurityDriverPtr security_drv;

1276 1277 1278
    qemuSecurityStackedSetDriver(qemud_drv);
    qemuSecurityDACSetDriver(qemud_drv);

1279 1280 1281 1282 1283 1284
    ret = virSecurityDriverStartup(&security_drv,
                                   qemud_drv->securityDriverName);
    if (ret == -1) {
        VIR_ERROR0(_("Failed to start security driver"));
        return -1;
    }
1285 1286 1287

    /* No primary security driver wanted to be enabled: just setup
     * the DAC driver on its own */
1288
    if (ret == -2) {
1289
        qemud_drv->securityDriver = &qemuDACSecurityDriver;
1290
        VIR_INFO0(_("No security driver available"));
1291 1292 1293 1294 1295
    } else {
        qemud_drv->securityPrimaryDriver = security_drv;
        qemud_drv->securitySecondaryDriver = &qemuDACSecurityDriver;
        qemud_drv->securityDriver = &qemuStackedSecurityDriver;
        VIR_INFO("Initialized security driver %s", security_drv->name);
1296 1297
    }

1298
    return 0;
1299
}
1300 1301


1302 1303
static virCapsPtr
qemuCreateCapabilities(virCapsPtr oldcaps,
1304
                       struct qemud_driver *driver)
1305 1306 1307 1308 1309
{
    virCapsPtr caps;

    /* Basic host arch / guest machine capabilities */
    if (!(caps = qemudCapsInit(oldcaps))) {
1310
        virReportOOMError();
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321
        return NULL;
    }

    /* Domain XML parser hooks */
    caps->privateDataAllocFunc = qemuDomainObjPrivateAlloc;
    caps->privateDataFreeFunc = qemuDomainObjPrivateFree;
    caps->privateDataXMLFormat = qemuDomainObjPrivateXMLFormat;
    caps->privateDataXMLParse = qemuDomainObjPrivateXMLParse;


    /* Security driver data */
1322
    if (driver->securityPrimaryDriver) {
1323 1324
        const char *doi, *model;

1325 1326
        doi = virSecurityDriverGetDOI(driver->securityPrimaryDriver);
        model = virSecurityDriverGetModel(driver->securityPrimaryDriver);
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339

        if (!(caps->host.secModel.model = strdup(model)))
            goto no_memory;
        if (!(caps->host.secModel.doi = strdup(doi)))
            goto no_memory;

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

    return caps;

no_memory:
1340
    virReportOOMError();
1341 1342 1343
    virCapabilitiesFree(caps);
    return NULL;
}
1344

C
Chris Lalancette 已提交
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
static void qemuDomainSnapshotLoad(void *payload,
                                   const char *name ATTRIBUTE_UNUSED,
                                   void *data)
{
    virDomainObjPtr vm = (virDomainObjPtr)payload;
    char *baseDir = (char *)data;
    char *snapDir = NULL;
    DIR *dir = NULL;
    struct dirent *entry;
    char *xmlStr;
    int ret;
    char *fullpath;
    virDomainSnapshotDefPtr def = NULL;
    char ebuf[1024];

    virDomainObjLock(vm);
    if (virAsprintf(&snapDir, "%s/%s", baseDir, vm->def->name) < 0) {
        VIR_ERROR("Failed to allocate memory for snapshot directory for domain %s",
                   vm->def->name);
        goto cleanup;
    }

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

    if (!(dir = opendir(snapDir))) {
        if (errno != ENOENT)
            VIR_ERROR("Failed to open snapshot directory %s for domain %s: %s",
                      snapDir, vm->def->name,
                      virStrerror(errno, ebuf, sizeof(ebuf)));
        goto cleanup;
    }

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

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

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

        ret = virFileReadAll(fullpath, 1024*1024*1, &xmlStr);
        VIR_FREE(fullpath);
        if (ret < 0) {
            /* Nothing we can do here, skip this one */
            VIR_ERROR("Failed to read snapshot file %s: %s", fullpath,
                      virStrerror(errno, ebuf, sizeof(ebuf)));
            continue;
        }

        def = virDomainSnapshotDefParseString(xmlStr, 0);
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
            VIR_ERROR("Failed to parse snapshot XML from file '%s'", fullpath);
            VIR_FREE(xmlStr);
            continue;
        }

1408
        virDomainSnapshotAssignDef(&vm->snapshots, def);
C
Chris Lalancette 已提交
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430

        VIR_FREE(xmlStr);
    }

    /* FIXME: qemu keeps internal track of snapshots.  We can get access
     * to this info via the "info snapshots" monitor command for running
     * domains, or via "qemu-img snapshot -l" for shutoff domains.  It would
     * be nice to update our internal state based on that, but there is a
     * a problem.  qemu doesn't track all of the same metadata that we do.
     * In particular we wouldn't be able to fill in the <parent>, which is
     * pretty important in our metadata.
     */

    virResetLastError();

cleanup:
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
    virDomainObjUnlock(vm);
}

1431 1432 1433 1434 1435 1436
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
1437
qemudStartup(int privileged) {
1438
    char *base = NULL;
D
Daniel P. Berrange 已提交
1439
    char driverConf[PATH_MAX];
1440
    int rc;
1441

1442
    if (VIR_ALLOC(qemu_driver) < 0)
1443 1444
        return -1;

1445
    if (virMutexInit(&qemu_driver->lock) < 0) {
1446
        VIR_ERROR("%s", _("cannot initialize mutex"));
1447 1448 1449
        VIR_FREE(qemu_driver);
        return -1;
    }
1450
    qemuDriverLock(qemu_driver);
1451
    qemu_driver->privileged = privileged;
1452

1453 1454 1455
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;

1456 1457 1458
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;

1459
    /* Init callback list */
1460
    if (VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
1461
        goto out_of_memory;
1462 1463 1464 1465 1466 1467
    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
        goto out_of_memory;

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

1469
    if (privileged) {
1470 1471
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1)
1472
            goto out_of_memory;
1473

D
Daniel P. Berrange 已提交
1474
        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
1475
            goto out_of_memory;
1476 1477

        if (virAsprintf(&qemu_driver->stateDir,
1478
                      "%s/run/libvirt/qemu", LOCAL_STATE_DIR) == -1)
1479
            goto out_of_memory;
1480 1481 1482 1483 1484 1485 1486 1487

        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;
1488 1489 1490
        if (virAsprintf(&qemu_driver->saveDir,
                      "%s/lib/libvirt/qemu/save/", LOCAL_STATE_DIR) == -1)
            goto out_of_memory;
C
Chris Lalancette 已提交
1491 1492 1493
        if (virAsprintf(&qemu_driver->snapshotDir,
                        "%s/lib/libvirt/qemu/snapshot", LOCAL_STATE_DIR) == -1)
            goto out_of_memory;
1494
    } else {
1495
        uid_t uid = geteuid();
1496
        char *userdir = virGetUserDirectory(uid);
1497
        if (!userdir)
1498
            goto error;
1499

1500
        if (virAsprintf(&qemu_driver->logDir,
1501 1502
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
1503
            goto out_of_memory;
1504
        }
1505

1506 1507
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
1508
            goto out_of_memory;
1509 1510
        }
        VIR_FREE(userdir);
1511 1512 1513

        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
            goto out_of_memory;
1514 1515 1516 1517
        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;
1518 1519
        if (virAsprintf(&qemu_driver->saveDir, "%s/qemu/save", base) == -1)
            goto out_of_memory;
C
Chris Lalancette 已提交
1520 1521
        if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
            goto out_of_memory;
1522 1523
    }

L
Laine Stump 已提交
1524
    if (virFileMakePath(qemu_driver->stateDir) != 0) {
1525
        char ebuf[1024];
1526
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
1527
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
1528
        goto error;
1529
    }
L
Laine Stump 已提交
1530
    if (virFileMakePath(qemu_driver->libDir) != 0) {
1531
        char ebuf[1024];
1532
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
1533 1534 1535
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
L
Laine Stump 已提交
1536
    if (virFileMakePath(qemu_driver->cacheDir) != 0) {
1537
        char ebuf[1024];
1538
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
1539 1540 1541
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
1542 1543 1544 1545 1546 1547
    if (virFileMakePath(qemu_driver->saveDir) != 0) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
                  qemu_driver->saveDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
C
Chris Lalancette 已提交
1548 1549 1550 1551 1552 1553
    if (virFileMakePath(qemu_driver->snapshotDir) != 0) {
        char ebuf[1024];
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
                  qemu_driver->snapshotDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
1554 1555 1556 1557

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

1562
    if (virAsprintf(&qemu_driver->configDir, "%s/qemu", base) == -1)
1563 1564
        goto out_of_memory;

1565
    if (virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1)
1566 1567
        goto out_of_memory;

1568
    VIR_FREE(base);
1569

1570 1571 1572 1573 1574 1575 1576
    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)));
    }

1577 1578 1579 1580
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
        goto error;
    }

1581 1582
    if (qemudSecurityInit(qemu_driver) < 0)
        goto error;
D
Daniel P. Berrange 已提交
1583

1584
    if ((qemu_driver->caps = qemuCreateCapabilities(NULL,
1585
                                                    qemu_driver)) == NULL)
1586
        goto error;
1587

1588
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
1589 1590
        goto error;

1591 1592
    if (privileged) {
        if (chown(qemu_driver->libDir, qemu_driver->user, qemu_driver->group) < 0) {
1593
            virReportSystemError(errno,
1594 1595 1596 1597 1598
                                 _("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) {
1599
            virReportSystemError(errno,
1600 1601 1602 1603
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
1604 1605 1606 1607 1608 1609
        if (chown(qemu_driver->saveDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->saveDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
C
Chris Lalancette 已提交
1610 1611 1612 1613 1614 1615
        if (chown(qemu_driver->snapshotDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->snapshotDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
1616 1617
    }

1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
    /* 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) {
1632
            virReportSystemError(rc,
1633 1634 1635 1636 1637 1638
                                 _("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) {
1639
            virReportSystemError(errno,
1640 1641 1642 1643 1644 1645 1646 1647 1648
                                 _("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;
    }

1649
    /* Get all the running persistent or transient configs first */
1650
    if (virDomainLoadAllConfigs(qemu_driver->caps,
1651 1652 1653 1654 1655 1656 1657 1658 1659
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
                                1, NULL, NULL) < 0)
        goto error;

    qemuReconnectDomains(qemu_driver);

    /* Then inactive persistent configs */
1660
    if (virDomainLoadAllConfigs(qemu_driver->caps,
1661 1662
                                &qemu_driver->domains,
                                qemu_driver->configDir,
1663
                                qemu_driver->autostartDir,
1664
                                0, NULL, NULL) < 0)
1665
        goto error;
C
Chris Lalancette 已提交
1666 1667 1668 1669 1670


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

1671 1672
    qemuDriverUnlock(qemu_driver);

1673 1674
    qemudAutostartConfigs(qemu_driver);

1675

1676 1677
    return 0;

1678
out_of_memory:
1679
    virReportOOMError();
1680 1681 1682
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
1683
    VIR_FREE(base);
1684
    qemudShutdown();
1685 1686 1687
    return -1;
}

1688 1689 1690 1691
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;

1692 1693 1694 1695 1696 1697 1698 1699
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }
1700 1701
}

1702 1703 1704 1705 1706 1707 1708 1709
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
1710 1711 1712
    if (!qemu_driver)
        return 0;

1713
    qemuDriverLock(qemu_driver);
1714
    virDomainLoadAllConfigs(qemu_driver->caps,
1715 1716
                            &qemu_driver->domains,
                            qemu_driver->configDir,
1717
                            qemu_driver->autostartDir,
1718
                            0, qemudNotifyLoadDomain, qemu_driver);
1719
    qemuDriverUnlock(qemu_driver);
1720

1721
    qemudAutostartConfigs(qemu_driver);
1722 1723

    return 0;
1724 1725
}

1726 1727 1728 1729 1730 1731 1732 1733 1734 1735
/**
 * 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) {
1736
    int active = 0;
1737

1738 1739 1740
    if (!qemu_driver)
        return 0;

1741
    /* XXX having to iterate here is not great because it requires many locks */
1742
    qemuDriverLock(qemu_driver);
1743
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
1744 1745
    qemuDriverUnlock(qemu_driver);
    return active;
1746 1747
}

1748 1749 1750 1751 1752 1753 1754
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
1755
    int i;
1756

1757
    if (!qemu_driver)
1758
        return -1;
1759

1760
    qemuDriverLock(qemu_driver);
1761
    pciDeviceListFree(qemu_driver->activePciHostdevs);
1762 1763
    virCapabilitiesFree(qemu_driver->caps);

1764
    virDomainObjListDeinit(&qemu_driver->domains);
1765

1766
    VIR_FREE(qemu_driver->securityDriverName);
1767
    VIR_FREE(qemu_driver->logDir);
1768 1769
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
1770
    VIR_FREE(qemu_driver->stateDir);
1771 1772
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
1773
    VIR_FREE(qemu_driver->saveDir);
C
Chris Lalancette 已提交
1774
    VIR_FREE(qemu_driver->snapshotDir);
1775
    VIR_FREE(qemu_driver->vncTLSx509certdir);
J
Jim Meyering 已提交
1776
    VIR_FREE(qemu_driver->vncListen);
1777
    VIR_FREE(qemu_driver->vncPassword);
1778
    VIR_FREE(qemu_driver->vncSASLdir);
1779
    VIR_FREE(qemu_driver->saveImageFormat);
1780 1781
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
D
Daniel P. Berrange 已提交
1782

1783 1784 1785 1786 1787 1788
    if (qemu_driver->cgroupDeviceACL) {
        for (i = 0 ; qemu_driver->cgroupDeviceACL[i] != NULL ; i++)
            VIR_FREE(qemu_driver->cgroupDeviceACL[i]);
        VIR_FREE(qemu_driver->cgroupDeviceACL);
    }

1789 1790
    /* Free domain callback list */
    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
1791 1792 1793 1794
    virDomainEventQueueFree(qemu_driver->domainEventQueue);

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

1796 1797 1798
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);

1799 1800
    virCgroupFree(&qemu_driver->cgroup);

1801
    qemuDriverUnlock(qemu_driver);
1802
    virMutexDestroy(&qemu_driver->lock);
1803
    VIR_FREE(qemu_driver);
1804 1805

    return 0;
1806 1807
}

1808
typedef int qemuLogHandleOutput(virDomainObjPtr vm,
1809 1810
                                const char *output,
                                int fd);
1811 1812 1813 1814 1815

/*
 * Returns -1 for error, 0 on success
 */
static int
1816
qemudReadLogOutput(virDomainObjPtr vm,
1817 1818
                   int fd,
                   char *buf,
G
Guido Günther 已提交
1819
                   size_t buflen,
1820
                   qemuLogHandleOutput func,
1821 1822 1823
                   const char *what,
                   int timeout)
{
1824
    int retries = (timeout*10);
1825
    int got = 0;
1826 1827 1828
    buf[0] = '\0';

    while (retries) {
1829
        ssize_t func_ret, ret;
1830
        int isdead = 0;
G
Guido Günther 已提交
1831

1832
        func_ret = func(vm, buf, fd);
1833

1834 1835
        if (kill(vm->pid, 0) == -1 && errno == ESRCH)
            isdead = 1;
1836

1837 1838
        /* Any failures should be detected before we read the log, so we
         * always have something useful to report on failure. */
1839 1840
        ret = saferead(fd, buf+got, buflen-got-1);
        if (ret < 0) {
1841
            virReportSystemError(errno,
1842 1843 1844 1845 1846
                                 _("Failure while reading %s log output"),
                                 what);
            return -1;
        }

1847 1848 1849
        got += ret;
        buf[got] = '\0';
        if (got == buflen-1) {
1850
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
1851 1852
                            _("Out of space while reading %s log output: %s"),
                            what, buf);
1853 1854 1855 1856
            return -1;
        }

        if (isdead) {
1857
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
1858 1859
                            _("Process exited while reading %s log output: %s"),
                            what, buf);
1860 1861 1862
            return -1;
        }

1863 1864
        if (func_ret <= 0)
            return func_ret;
1865 1866 1867 1868

        usleep(100*1000);
        retries--;
    }
1869

1870
    qemuReportError(VIR_ERR_INTERNAL_ERROR,
1871 1872
                    _("Timed out while reading %s log output: %s"),
                    what, buf);
1873 1874 1875
    return -1;
}

1876

1877 1878 1879 1880 1881 1882 1883 1884
/*
 * 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
 */
1885
static int
1886
qemudExtractTTYPath(const char *haystack,
1887 1888
                    size_t *offset,
                    char **path)
1889
{
1890
    static const char needle[] = "char device redirected to";
1891
    char *tmp, *dev;
1892

1893
    VIR_FREE(*path);
1894
    /* First look for our magic string */
1895 1896 1897 1898 1899
    if (!(tmp = strstr(haystack + *offset, needle))) {
        return 1;
    }
    tmp += sizeof(needle);
    dev = tmp;
1900

1901 1902 1903 1904 1905
    /*
     * And look for first whitespace character and nul terminate
     * to mark end of the pty path
     */
    while (*tmp) {
1906
        if (c_isspace(*tmp)) {
1907 1908
            *path = strndup(dev, tmp-dev);
            if (*path == NULL) {
1909
                virReportOOMError();
1910 1911
                return -1;
            }
1912

1913
            /* ... now further update offset till we get EOL */
1914
            *offset = tmp - haystack;
1915 1916
            return 0;
        }
1917
        tmp++;
1918 1919 1920 1921 1922
    }

    /*
     * We found a path, but didn't find any whitespace,
     * so it must be still incomplete - we should at
1923 1924
     * least see a \n - indicate that we want to carry
     * on trying again
1925
     */
1926
    return 1;
1927 1928
}

1929
static int
1930
qemudFindCharDevicePTYsMonitor(virDomainObjPtr vm,
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945
                               virHashTablePtr paths)
{
    int i;

#define LOOKUP_PTYS(array, arraylen, idprefix)                            \
    for (i = 0 ; i < (arraylen) ; i++) {                                  \
        virDomainChrDefPtr chr = (array)[i];                              \
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {                       \
            char id[16];                                                  \
                                                                          \
            if (snprintf(id, sizeof(id), idprefix "%i", i) >= sizeof(id)) \
                return -1;                                                \
                                                                          \
            const char *path = (const char *) virHashLookup(paths, id);   \
            if (path == NULL) {                                           \
1946 1947 1948
                if (chr->data.file.path == NULL) {                        \
                    /* neither the log output nor 'info chardev' had a */ \
                    /* pty path for this chardev, report an error */      \
1949 1950 1951
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,               \
                                    _("no assigned pty for device %s"), id); \
                    return -1;                                            \
1952 1953 1954 1955 1956
                } else {                                                  \
                    /* 'info chardev' had no pty path for this chardev, */\
                    /* but the log output had, so we're fine */           \
                    continue;                                             \
                }                                                         \
1957 1958
            }                                                             \
                                                                          \
1959
            VIR_FREE(chr->data.file.path);                                \
1960
            chr->data.file.path = strdup(path);                           \
1961 1962
                                                                          \
            if (chr->data.file.path == NULL) {                            \
1963
                virReportOOMError();                                      \
1964 1965
                return -1;                                                \
            }                                                             \
1966 1967 1968 1969 1970 1971
        }                                                                 \
    }

    LOOKUP_PTYS(vm->def->serials,   vm->def->nserials,   "serial");
    LOOKUP_PTYS(vm->def->parallels, vm->def->nparallels, "parallel");
    LOOKUP_PTYS(vm->def->channels,  vm->def->nchannels,  "channel");
1972
#undef LOOKUP_PTYS
1973 1974 1975 1976

    return 0;
}

1977
static int
1978
qemudFindCharDevicePTYs(virDomainObjPtr vm,
1979 1980
                        const char *output,
                        int fd ATTRIBUTE_UNUSED)
1981
{
1982
    size_t offset = 0;
1983
    int ret, i;
1984 1985

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

1989
    /* first comes the serial devices */
1990 1991
    for (i = 0 ; i < vm->def->nserials ; i++) {
        virDomainChrDefPtr chr = vm->def->serials[i];
1992
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
1993
            if ((ret = qemudExtractTTYPath(output, &offset,
1994
                                           &chr->data.file.path)) != 0)
1995
                return ret;
1996 1997 1998
        }
    }

1999
    /* then the parallel devices */
2000 2001
    for (i = 0 ; i < vm->def->nparallels ; i++) {
        virDomainChrDefPtr chr = vm->def->parallels[i];
2002
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
2003
            if ((ret = qemudExtractTTYPath(output, &offset,
2004
                                           &chr->data.file.path)) != 0)
2005
                return ret;
2006 2007 2008
        }
    }

2009 2010 2011 2012
    /* then the channel devices */
    for (i = 0 ; i < vm->def->nchannels ; i++) {
        virDomainChrDefPtr chr = vm->def->channels[i];
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
2013
            if ((ret = qemudExtractTTYPath(output, &offset,
2014 2015 2016 2017 2018
                                           &chr->data.file.path)) != 0)
                return ret;
        }
    }

2019
    return 0;
2020 2021
}

2022 2023 2024 2025 2026
static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED)
{
    VIR_FREE(payload);
}

2027
static int
2028
qemudWaitForMonitor(struct qemud_driver* driver,
2029
                    virDomainObjPtr vm, off_t pos)
2030
{
2031
    char buf[4096]; /* Plenty of space to get startup greeting */
2032
    int logfd;
2033
    int ret = -1;
2034

2035
    if ((logfd = qemudLogReadFD(driver->logDir, vm->def->name, pos))
2036
        < 0)
2037
        return -1;
2038

2039
    ret = qemudReadLogOutput(vm, logfd, buf, sizeof(buf),
2040
                             qemudFindCharDevicePTYs,
2041
                             "console", 30);
2042
    if (close(logfd) < 0) {
2043
        char ebuf[4096];
2044
        VIR_WARN(_("Unable to close logfile: %s"),
2045 2046
                 virStrerror(errno, ebuf, sizeof ebuf));
    }
2047

2048
    if (ret < 0)
2049
        return -1;
2050

2051
    VIR_DEBUG("Connect monitor to %p '%s'", vm, vm->def->name);
2052
    if (qemuConnectMonitor(driver, vm) < 0)
2053 2054
        return -1;

2055 2056 2057 2058 2059 2060
    /* Try to get the pty path mappings again via the monitor. This is much more
     * reliable if it's available.
     * Note that the monitor itself can be on a pty, so we still need to try the
     * log output method. */
    virHashTablePtr paths = virHashCreate(0);
    if (paths == NULL) {
2061
        virReportOOMError();
2062 2063 2064
        goto cleanup;
    }

2065
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2066 2067
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ret = qemuMonitorGetPtyPaths(priv->mon, paths);
2068
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2069 2070 2071

    VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret);
    if (ret == 0) {
2072
        ret = qemudFindCharDevicePTYsMonitor(vm, paths);
2073 2074 2075 2076 2077 2078 2079 2080
    }

cleanup:
    if (paths) {
        virHashFree(paths, qemudFreePtyPath);
    }

    return ret;
2081 2082
}

2083
static int
2084
qemuDetectVcpuPIDs(struct qemud_driver *driver,
2085 2086 2087
                   virDomainObjPtr vm) {
    pid_t *cpupids = NULL;
    int ncpupids;
2088
    qemuDomainObjPrivatePtr priv = vm->privateData;
2089

2090
    if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
2091 2092
        priv->nvcpupids = 1;
        if (VIR_ALLOC_N(priv->vcpupids, priv->nvcpupids) < 0) {
2093
            virReportOOMError();
2094 2095
            return -1;
        }
2096
        priv->vcpupids[0] = vm->pid;
2097 2098 2099
        return 0;
    }

2100
    /* What follows is now all KVM specific */
2101

2102
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2103
    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) < 0) {
2104
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2105
        return -1;
2106
    }
2107
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2108

2109 2110 2111
    /* Treat failure to get VCPU<->PID mapping as non-fatal */
    if (ncpupids == 0)
        return 0;
2112

2113
    if (ncpupids != vm->def->vcpus) {
2114 2115 2116
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"),
                        ncpupids, (int)vm->def->vcpus);
2117 2118 2119
        VIR_FREE(cpupids);
        return -1;
    }
2120

2121 2122
    priv->nvcpupids = ncpupids;
    priv->vcpupids = cpupids;
2123 2124 2125
    return 0;
}

2126 2127 2128
/*
 * To be run between fork/exec of QEMU only
 */
2129
static int
2130 2131
qemudInitCpuAffinity(virDomainObjPtr vm)
{
2132
    int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN;
2133
    virNodeInfo nodeinfo;
2134 2135
    unsigned char *cpumap;
    int cpumaplen;
2136 2137

    DEBUG0("Setting CPU affinity");
2138

2139
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
2140 2141 2142 2143
        return -1;

    /* setaffinity fails if you set bits for CPUs which
     * aren't present, so we have to limit ourselves */
2144 2145 2146
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
2147

2148 2149
    cpumaplen = VIR_CPU_MAPLEN(maxcpu);
    if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) {
2150
        virReportOOMError();
2151 2152 2153
        return -1;
    }

D
Daniel P. Berrange 已提交
2154
    if (vm->def->cpumask) {
2155 2156 2157
        /* XXX why don't we keep 'cpumask' in the libvirt cpumap
         * format to start with ?!?! */
        for (i = 0 ; i < maxcpu && i < vm->def->cpumasklen ; i++)
D
Daniel P. Berrange 已提交
2158
            if (vm->def->cpumask[i])
2159
                VIR_USE_CPU(cpumap, i);
D
Daniel P. Berrange 已提交
2160
    } else {
2161 2162 2163 2164
        /* You may think this is redundant, but we can't assume libvirtd
         * itself is running on all pCPUs, so we need to explicitly set
         * the spawned QEMU instance to all pCPUs if no map is given in
         * its config file */
D
Daniel P. Berrange 已提交
2165
        for (i = 0 ; i < maxcpu ; i++)
2166
            VIR_USE_CPU(cpumap, i);
D
Daniel P. Berrange 已提交
2167
    }
2168

2169 2170 2171 2172 2173 2174 2175 2176
    /* We are pressuming we are running between fork/exec of QEMU
     * so use '0' to indicate our own process ID. No threads are
     * running at this point
     */
    if (virProcessInfoSetAffinity(0, /* Self */
                                  cpumap, cpumaplen, maxcpu) < 0) {
        VIR_FREE(cpumap);
        return -1;
2177
    }
2178
    VIR_FREE(cpumap);
2179 2180 2181 2182 2183

    return 0;
}


2184
static int
2185 2186 2187 2188
qemuInitPasswords(virConnectPtr conn,
                  struct qemud_driver *driver,
                  virDomainObjPtr vm,
                  unsigned long long qemuCmdFlags) {
2189
    int ret = 0;
2190
    qemuDomainObjPrivatePtr priv = vm->privateData;
2191

2192 2193 2194
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) {
2195

2196
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
2197
        ret = qemuMonitorSetVNCPassword(priv->mon,
2198 2199 2200
                                        vm->def->graphics[0]->data.vnc.passwd ?
                                        vm->def->graphics[0]->data.vnc.passwd :
                                        driver->vncPassword);
2201
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2202 2203
    }

2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226
    if (ret < 0)
        goto cleanup;

    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        int i;

        for (i = 0 ; i < vm->def->ndisks ; i++) {
            char *secret;
            size_t secretLen;

            if (!vm->def->disks[i]->encryption ||
                !vm->def->disks[i]->src)
                continue;

            if (getVolumeQcowPassphrase(conn,
                                        vm->def->disks[i],
                                        &secret, &secretLen) < 0)
                goto cleanup;

            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            ret = qemuMonitorSetDrivePassphrase(priv->mon,
                                                vm->def->disks[i]->info.alias,
                                                secret);
2227
            VIR_FREE(secret);
2228 2229 2230 2231 2232 2233 2234
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (ret < 0)
                goto cleanup;
        }
    }

cleanup:
2235
    return ret;
2236 2237 2238
}


2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467
#define QEMU_PCI_VENDOR_INTEL     0x8086
#define QEMU_PCI_VENDOR_LSI_LOGIC 0x1000
#define QEMU_PCI_VENDOR_REDHAT    0x1af4
#define QEMU_PCI_VENDOR_CIRRUS    0x1013
#define QEMU_PCI_VENDOR_REALTEK   0x10ec
#define QEMU_PCI_VENDOR_AMD       0x1022
#define QEMU_PCI_VENDOR_ENSONIQ   0x1274
#define QEMU_PCI_VENDOR_VMWARE    0x15ad
#define QEMU_PCI_VENDOR_QEMU      0x1234

#define QEMU_PCI_PRODUCT_DISK_VIRTIO 0x1001

#define QEMU_PCI_PRODUCT_NIC_NE2K     0x8029
#define QEMU_PCI_PRODUCT_NIC_PCNET    0x2000
#define QEMU_PCI_PRODUCT_NIC_RTL8139  0x8139
#define QEMU_PCI_PRODUCT_NIC_E1000    0x100E
#define QEMU_PCI_PRODUCT_NIC_VIRTIO   0x1000

#define QEMU_PCI_PRODUCT_VGA_CIRRUS 0x00b8
#define QEMU_PCI_PRODUCT_VGA_VMWARE 0x0405
#define QEMU_PCI_PRODUCT_VGA_STDVGA 0x1111

#define QEMU_PCI_PRODUCT_AUDIO_AC97    0x2415
#define QEMU_PCI_PRODUCT_AUDIO_ES1370  0x5000

#define QEMU_PCI_PRODUCT_CONTROLLER_PIIX 0x7010
#define QEMU_PCI_PRODUCT_CONTROLLER_LSI  0x0012

#define QEMU_PCI_PRODUCT_WATCHDOG_I63000ESB 0x25ab

static int
qemuAssignNextPCIAddress(virDomainDeviceInfo *info,
                         int vendor,
                         int product,
                         qemuMonitorPCIAddress *addrs,
                         int naddrs)
{
    int found = 0;
    int i;

    VIR_DEBUG("Look for %x:%x out of %d", vendor, product, naddrs);

    for (i = 0 ; (i < naddrs) && !found; i++) {
        VIR_DEBUG("Maybe %x:%x", addrs[i].vendor, addrs[i].product);
        if (addrs[i].vendor == vendor &&
            addrs[i].product == product) {
            VIR_DEBUG("Match %d", i);
            found = 1;
            break;
        }
    }
    if (!found) {
        return -1;
    }

    /* Blank it out so this device isn't matched again */
    addrs[i].vendor = 0;
    addrs[i].product = 0;

    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
        info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;

    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
        info->addr.pci.domain = addrs[i].addr.domain;
        info->addr.pci.bus = addrs[i].addr.bus;
        info->addr.pci.slot = addrs[i].addr.slot;
        info->addr.pci.function = addrs[i].addr.function;
    }

    return 0;
}

static int
qemuGetPCIDiskVendorProduct(virDomainDiskDefPtr def,
                            unsigned *vendor,
                            unsigned *product)
{
    switch (def->bus) {
    case VIR_DOMAIN_DISK_BUS_VIRTIO:
        *vendor = QEMU_PCI_VENDOR_REDHAT;
        *product = QEMU_PCI_PRODUCT_DISK_VIRTIO;
        break;

    default:
        return -1;
    }

    return 0;
}

static int
qemuGetPCINetVendorProduct(virDomainNetDefPtr def,
                            unsigned *vendor,
                            unsigned *product)
{
    if (!def->model)
        return -1;

    if (STREQ(def->model, "ne2k_pci")) {
        *vendor = QEMU_PCI_VENDOR_REALTEK;
        *product = QEMU_PCI_PRODUCT_NIC_NE2K;
    } else if (STREQ(def->model, "pcnet")) {
        *vendor = QEMU_PCI_VENDOR_AMD;
        *product = QEMU_PCI_PRODUCT_NIC_PCNET;
    } else if (STREQ(def->model, "rtl8139")) {
        *vendor = QEMU_PCI_VENDOR_REALTEK;
        *product = QEMU_PCI_PRODUCT_NIC_RTL8139;
    } else if (STREQ(def->model, "e1000")) {
        *vendor = QEMU_PCI_VENDOR_INTEL;
        *product = QEMU_PCI_PRODUCT_NIC_E1000;
    } else if (STREQ(def->model, "virtio")) {
        *vendor = QEMU_PCI_VENDOR_REDHAT;
        *product = QEMU_PCI_PRODUCT_NIC_VIRTIO;
    } else {
        VIR_INFO("Unexpected NIC model %s, cannot get PCI address",
                 def->model);
        return -1;
    }
    return 0;
}

static int
qemuGetPCIControllerVendorProduct(virDomainControllerDefPtr def,
                                  unsigned *vendor,
                                  unsigned *product)
{
    switch (def->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
        *vendor = QEMU_PCI_VENDOR_LSI_LOGIC;
        *product = QEMU_PCI_PRODUCT_CONTROLLER_LSI;
        break;

    case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
        /* XXX we could put in the ISA bridge address, but
           that's not technically the FDC's address */
        return -1;

    case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
        *vendor = QEMU_PCI_VENDOR_INTEL;
        *product = QEMU_PCI_PRODUCT_CONTROLLER_PIIX;
        break;

    default:
        VIR_INFO("Unexpected controller type %s, cannot get PCI address",
                 virDomainControllerTypeToString(def->type));
        return -1;
    }

    return 0;
}

static int
qemuGetPCIVideoVendorProduct(virDomainVideoDefPtr def,
                             unsigned *vendor,
                             unsigned *product)
{
    switch (def->type) {
    case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
        *vendor = QEMU_PCI_VENDOR_CIRRUS;
        *product = QEMU_PCI_PRODUCT_VGA_CIRRUS;
        break;

    case VIR_DOMAIN_VIDEO_TYPE_VGA:
        *vendor = QEMU_PCI_VENDOR_QEMU;
        *product = QEMU_PCI_PRODUCT_VGA_STDVGA;
        break;

    case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
        *vendor = QEMU_PCI_VENDOR_VMWARE;
        *product = QEMU_PCI_PRODUCT_VGA_VMWARE;
        break;

    default:
        return -1;
    }
    return 0;
}

static int
qemuGetPCISoundVendorProduct(virDomainSoundDefPtr def,
                             unsigned *vendor,
                             unsigned *product)
{
    switch (def->model) {
    case VIR_DOMAIN_SOUND_MODEL_ES1370:
        *vendor = QEMU_PCI_VENDOR_ENSONIQ;
        *product = QEMU_PCI_PRODUCT_AUDIO_ES1370;
        break;

    case VIR_DOMAIN_SOUND_MODEL_AC97:
        *vendor = QEMU_PCI_VENDOR_INTEL;
        *product = QEMU_PCI_PRODUCT_AUDIO_AC97;
        break;

    default:
        return -1;
    }

    return 0;
}

static int
qemuGetPCIWatchdogVendorProduct(virDomainWatchdogDefPtr def,
                                unsigned *vendor,
                                unsigned *product)
{
    switch (def->model) {
    case VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB:
        *vendor = QEMU_PCI_VENDOR_INTEL;
        *product = QEMU_PCI_PRODUCT_WATCHDOG_I63000ESB;
        break;

    default:
        return -1;
    }

    return 0;
}


/*
 * This entire method assumes that PCI devices in 'info pci'
 * match ordering of devices specified on the command line
 * wrt to devices of matching vendor+product
 *
 * XXXX this might not be a valid assumption if we assign
 * some static addrs on CLI. Have to check that...
 */
static int
2468
qemuDetectPCIAddresses(virDomainObjPtr vm,
2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485
                       qemuMonitorPCIAddress *addrs,
                       int naddrs)
{
    unsigned int vendor = 0, product = 0;
    int i;

    /* XXX should all these vendor/product IDs be kept in the
     * actual device data structure instead ?
     */

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (qemuGetPCIDiskVendorProduct(vm->def->disks[i], &vendor, &product) < 0)
            continue;

        if (qemuAssignNextPCIAddress(&(vm->def->disks[i]->info),
                                     vendor, product,
                                     addrs, naddrs) < 0) {
2486 2487 2488
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for VirtIO disk %s"),
                            vm->def->disks[i]->dst);
2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499
            return -1;
        }
    }

    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (qemuGetPCINetVendorProduct(vm->def->nets[i], &vendor, &product) < 0)
            continue;

        if (qemuAssignNextPCIAddress(&(vm->def->nets[i]->info),
                                     vendor, product,
                                     addrs,  naddrs) < 0) {
2500 2501 2502
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for %s NIC"),
                            vm->def->nets[i]->model);
2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513
            return -1;
        }
    }

    for (i = 0 ; i < vm->def->ncontrollers ; i++) {
        if (qemuGetPCIControllerVendorProduct(vm->def->controllers[i], &vendor, &product) < 0)
            continue;

        if (qemuAssignNextPCIAddress(&(vm->def->controllers[i]->info),
                                     vendor, product,
                                     addrs,  naddrs) < 0) {
2514 2515 2516
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for controller %s"),
                            virDomainControllerTypeToString(vm->def->controllers[i]->type));
2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527
            return -1;
        }
    }

    for (i = 0 ; i < vm->def->nvideos ; i++) {
        if (qemuGetPCIVideoVendorProduct(vm->def->videos[i], &vendor, &product) < 0)
            continue;

        if (qemuAssignNextPCIAddress(&(vm->def->videos[i]->info),
                                     vendor, product,
                                     addrs,  naddrs) < 0) {
2528 2529 2530
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for video adapter %s"),
                            virDomainVideoTypeToString(vm->def->videos[i]->type));
2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541
            return -1;
        }
    }

    for (i = 0 ; i < vm->def->nsounds ; i++) {
        if (qemuGetPCISoundVendorProduct(vm->def->sounds[i], &vendor, &product) < 0)
            continue;

        if (qemuAssignNextPCIAddress(&(vm->def->sounds[i]->info),
                                     vendor, product,
                                     addrs,  naddrs) < 0) {
2542 2543 2544
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for sound adapter %s"),
                            virDomainSoundModelTypeToString(vm->def->sounds[i]->model));
2545 2546 2547 2548 2549 2550 2551 2552 2553 2554
            return -1;
        }
    }


    if (vm->def->watchdog &&
        qemuGetPCIWatchdogVendorProduct(vm->def->watchdog, &vendor, &product) == 0) {
        if (qemuAssignNextPCIAddress(&(vm->def->watchdog->info),
                                     vendor, product,
                                     addrs,  naddrs) < 0) {
2555 2556 2557
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for watchdog %s"),
                            virDomainWatchdogModelTypeToString(vm->def->watchdog->model));
2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589
            return -1;
        }
    }

    /* XXX console (virtio) */


    /* ... and now things we don't have in our xml */

    /* XXX USB controller ? */

    /* XXXX virtio balloon ? */

    /* XXX what about other PCI devices (ie bridges) */

    return 0;
}

static int
qemuInitPCIAddresses(struct qemud_driver *driver,
                     virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int naddrs;
    int ret;
    qemuMonitorPCIAddress *addrs = NULL;

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    naddrs = qemuMonitorGetAllPCIAddresses(priv->mon,
                                           &addrs);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

2590
    ret = qemuDetectPCIAddresses(vm, addrs, naddrs);
2591 2592 2593 2594 2595 2596

    VIR_FREE(addrs);

    return ret;
}

2597
static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
2598 2599
    int i;

2600
    for (i = 5900 ; i < 65535 ; i++) {
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632
        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;
}

2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670

static int
qemuAssignPCIAddresses(virDomainDefPtr def)
{
    int ret = -1;
    unsigned long long qemuCmdFlags = 0;
    qemuDomainPCIAddressSetPtr addrs = NULL;
    struct stat sb;

    if (stat(def->emulator, &sb) < 0) {
        virReportSystemError(errno,
                             _("Cannot find QEMU binary %s"),
                             def->emulator);
        goto cleanup;
    }

    if (qemudExtractVersionInfo(def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
        goto cleanup;

    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (!(addrs = qemuDomainPCIAddressSetCreate(def)))
            goto cleanup;

        if (qemuAssignDevicePCISlots(def, addrs) < 0)
            goto cleanup;
    }

    ret = 0;

cleanup:
    qemuDomainPCIAddressSetFree(addrs);

    return ret;
}


2671
static pciDeviceList *
2672
qemuGetPciHostDeviceList(virDomainDefPtr def)
2673 2674
{
    pciDeviceList *list;
2675 2676
    int i;

2677
    if (!(list = pciDeviceListNew()))
2678
        return NULL;
2679 2680 2681 2682 2683 2684 2685 2686 2687 2688

    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;

2689
        dev = pciGetDevice(hostdev->source.subsys.u.pci.domain,
2690 2691 2692
                           hostdev->source.subsys.u.pci.bus,
                           hostdev->source.subsys.u.pci.slot,
                           hostdev->source.subsys.u.pci.function);
2693
        if (!dev) {
2694
            pciDeviceListFree(list);
2695 2696
            return NULL;
        }
2697

2698 2699 2700
        if (pciDeviceListAdd(list, dev) < 0) {
            pciFreeDevice(dev);
            pciDeviceListFree(list);
2701
            return NULL;
2702 2703
        }

2704
        pciDeviceSetManaged(dev, hostdev->managed);
2705 2706
    }

2707 2708 2709 2710
    return list;
}

static int
2711 2712 2713 2714
qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                            virDomainDefPtr def)
{
    pciDeviceList *pcidevs;
2715
    int i;
2716
    int ret = -1;
2717 2718 2719 2720

    if (!def->nhostdevs)
        return 0;

2721
    if (!(pcidevs = qemuGetPciHostDeviceList(def)))
2722 2723
        return -1;

2724 2725
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2726 2727 2728
        pciDeviceListSteal(pcidevs, dev);
        if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            pciFreeDevice(dev);
2729
            goto cleanup;
2730 2731 2732
        }
    }

2733 2734 2735
    ret = 0;

cleanup:
2736
    pciDeviceListFree(pcidevs);
2737 2738 2739
    return ret;
}

2740

2741
static int
2742 2743
qemuPrepareHostPCIDevices(struct qemud_driver *driver,
                          virDomainDefPtr def)
2744 2745 2746
{
    pciDeviceList *pcidevs;
    int i;
2747
    int ret = -1;
2748

2749
    if (!(pcidevs = qemuGetPciHostDeviceList(def)))
2750 2751
        return -1;

2752
    /* We have to use 3 loops here. *All* devices must
2753 2754
     * be detached before we reset any of them, because
     * in some cases you have to reset the whole PCI,
2755 2756
     * which impacts all devices on it. Also, all devices
     * must be reset before being marked as active.
2757 2758 2759 2760 2761 2762 2763
     */

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

2764 2765
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2766
        if (!pciDeviceIsAssignable(dev, !driver->relaxedACS))
2767 2768
            goto cleanup;

2769
        if (pciDeviceGetManaged(dev) &&
2770
            pciDettachDevice(dev) < 0)
2771 2772
            goto cleanup;
    }
2773 2774 2775

    /* Now that all the PCI hostdevs have be dettached, we can safely
     * reset them */
2776 2777
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2778
        if (pciResetDevice(dev, driver->activePciHostdevs) < 0)
2779 2780
            goto cleanup;
    }
2781

2782
    /* Now mark all the devices as active */
2783 2784
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2785 2786 2787
        pciDeviceListSteal(pcidevs, dev);
        if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            pciFreeDevice(dev);
2788 2789
            goto cleanup;
        }
2790 2791
    }

2792
    ret = 0;
2793

2794
cleanup:
2795
    pciDeviceListFree(pcidevs);
2796
    return ret;
2797 2798
}

2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809

static int
qemuPrepareHostUSBDevices(struct qemud_driver *driver ATTRIBUTE_UNUSED,
                          virDomainDefPtr def)
{
    int i;
    for (i = 0 ; i < def->nhostdevs ; i++) {
        virDomainHostdevDefPtr hostdev = def->hostdevs[i];

        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;
2810
        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848
            continue;

        /* Resolve a vendor/product to bus/device */
        if (hostdev->source.subsys.u.usb.vendor) {
            usbDevice *usb
                = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
                                hostdev->source.subsys.u.usb.product);

            if (!usb)
                return -1;

            hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
            hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);

            usbFreeDevice(usb);
        }
    }

    return 0;
}

static int
qemuPrepareHostDevices(struct qemud_driver *driver,
                       virDomainDefPtr def)
{
    if (!def->nhostdevs)
        return 0;

    if (qemuPrepareHostPCIDevices(driver, def) < 0)
        return -1;

    if (qemuPrepareHostUSBDevices(driver, def) < 0)
        return -1;

    return 0;
}


2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859
static void
qemudReattachManagedDevice(pciDevice *dev)
{
    int retries = 100;

    if (pciDeviceGetManaged(dev)) {
        while (pciWaitForDeviceCleanup(dev, "kvm_assigned_device")
               && retries) {
            usleep(100*1000);
            retries--;
        }
2860
        if (pciReAttachDevice(dev) < 0) {
2861 2862 2863 2864 2865 2866 2867 2868
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to re-attach PCI device: %s"),
                      err ? err->message : "");
            virResetError(err);
        }
    }
}

2869
static void
2870
qemuDomainReAttachHostDevices(struct qemud_driver *driver,
2871
                              virDomainDefPtr def)
2872
{
2873
    pciDeviceList *pcidevs;
2874 2875
    int i;

2876 2877
    if (!def->nhostdevs)
        return;
2878

2879
    if (!(pcidevs = qemuGetPciHostDeviceList(def))) {
2880
        virErrorPtr err = virGetLastError();
2881
        VIR_ERROR(_("Failed to allocate pciDeviceList: %s"),
2882 2883 2884
                  err ? err->message : "");
        virResetError(err);
        return;
2885 2886
    }

2887 2888
    /* Again 3 loops; mark all devices as inactive before reset
     * them and reset all the devices before re-attach */
2889

2890 2891
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2892
        pciDeviceListDel(driver->activePciHostdevs, dev);
2893
    }
2894

2895 2896
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2897
        if (pciResetDevice(dev, driver->activePciHostdevs) < 0) {
2898
            virErrorPtr err = virGetLastError();
2899
            VIR_ERROR(_("Failed to reset PCI device: %s"),
2900 2901 2902
                      err ? err->message : "");
            virResetError(err);
        }
2903
    }
2904

2905 2906
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2907
        qemudReattachManagedDevice(dev);
2908
    }
2909

2910
    pciDeviceListFree(pcidevs);
2911 2912
}

2913 2914 2915 2916 2917 2918 2919 2920 2921 2922
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

2923
static int qemuSetupCgroup(struct qemud_driver *driver,
2924 2925 2926 2927
                           virDomainObjPtr vm)
{
    virCgroupPtr cgroup = NULL;
    int rc;
2928
    unsigned int i;
2929 2930 2931 2932
    const char *const *deviceACL =
        driver->cgroupDeviceACL ?
        (const char *const *)driver->cgroupDeviceACL :
        defaultDeviceACL;
2933 2934 2935 2936 2937 2938

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

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

2945 2946
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        rc = virCgroupDenyAllDevices(cgroup);
2947
        if (rc != 0) {
2948 2949 2950 2951 2952
            if (rc == -EPERM) {
                VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
                goto done;
            }

2953
            virReportSystemError(-rc,
2954
                                 _("Unable to deny all devices for %s"), vm->def->name);
2955 2956 2957
            goto cleanup;
        }

2958 2959 2960 2961 2962 2963 2964 2965
        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) {
2966
                virReportSystemError(-rc,
2967 2968 2969 2970 2971
                                     _("Unable to allow device %s for %s"),
                                     vm->def->disks[i]->src, vm->def->name);
                goto cleanup;
            }
        }
2972

2973
        rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
2974
        if (rc != 0) {
2975
            virReportSystemError(-rc, "%s",
2976
                                 _("unable to allow /dev/pts/ devices"));
2977 2978 2979
            goto cleanup;
        }

2980 2981 2982
        if (vm->def->nsounds) {
            rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR);
            if (rc != 0) {
2983
                virReportSystemError(-rc, "%s",
2984 2985 2986 2987 2988 2989 2990 2991 2992 2993
                                     _("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) {
2994
                virReportSystemError(-rc,
2995 2996 2997 2998
                                     _("unable to allow device %s"),
                                     deviceACL[i]);
                goto cleanup;
            }
2999 3000 3001 3002
        }
    }

done:
3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014
    virCgroupFree(&cgroup);
    return 0;

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


3015
static int qemuRemoveCgroup(struct qemud_driver *driver,
3016 3017
                            virDomainObjPtr vm,
                            int quiet)
3018 3019 3020 3021 3022 3023 3024 3025 3026
{
    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) {
3027
        if (!quiet)
3028 3029 3030
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Unable to find cgroup for %s\n"),
                            vm->def->name);
3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050
        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) {
3051
        virReportSystemError(-rc,
3052 3053 3054 3055 3056 3057 3058
                             _("unable to find cgroup for domain %s"),
                             def->name);
        goto cleanup;
    }

    rc = virCgroupAddTask(cgroup, getpid());
    if (rc != 0) {
3059
        virReportSystemError(-rc,
3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072
                             _("unable to add domain %s task %d to cgroup"),
                             def->name, getpid());
        goto cleanup;
    }

    ret = 0;

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


S
Stefan Berger 已提交
3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087
static void
qemuTearNWFilter(virDomainNetDefPtr net) {
    if ((net->filter) && (net->ifname))
        virNWFilterTeardownFilter(net);
}


static void
qemuTearVMNWFilters(virDomainObjPtr vm) {
    int i;
    for (i = 0; i < vm->def->nnets; i++)
        qemuTearNWFilter(vm->def->nets[i]);
}


3088 3089 3090 3091
struct qemudHookData {
    virConnectPtr conn;
    virDomainObjPtr vm;
    struct qemud_driver *driver;
3092 3093 3094
};

static int qemudSecurityHook(void *data) {
3095 3096
    struct qemudHookData *h = data;

3097 3098 3099 3100 3101 3102
    /* This must take place before exec(), so that all QEMU
     * memory allocation is on the correct NUMA node
     */
    if (qemudInitCpuAffinity(h->vm) < 0)
        return -1;

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

3106 3107
    if (h->driver->securityDriver &&
        h->driver->securityDriver->domainSetSecurityProcessLabel &&
3108
        h->driver->securityDriver->domainSetSecurityProcessLabel(h->driver->securityDriver, h->vm) < 0)
3109 3110 3111
        return -1;

    return 0;
3112 3113
}

3114
static int
3115
qemuPrepareMonitorChr(struct qemud_driver *driver,
3116
                      virDomainChrDefPtr monConfig,
3117 3118
                      const char *vm)
{
3119
    monConfig->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_MONITOR;
3120

3121 3122
    monConfig->type = VIR_DOMAIN_CHR_TYPE_UNIX;
    monConfig->data.nix.listen = 1;
3123

D
Daniel P. Berrange 已提交
3124
    if (!(monConfig->info.alias = strdup("monitor"))) {
3125
        virReportOOMError();
D
Daniel P. Berrange 已提交
3126 3127 3128
        return -1;
    }

3129
    if (virAsprintf(&monConfig->data.nix.path, "%s/%s.monitor",
3130
                    driver->libDir, vm) < 0) {
3131
        virReportOOMError();
3132 3133 3134 3135 3136 3137
        return -1;
    }

    return 0;
}

C
Chris Lalancette 已提交
3138 3139 3140 3141 3142
static int qemuDomainSnapshotSetActive(virDomainObjPtr vm,
                                       char *snapshotDir);
static int qemuDomainSnapshotSetInactive(virDomainObjPtr vm,
                                         char *snapshotDir);

3143 3144
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
3145
                              virDomainObjPtr vm,
3146 3147
                              const char *migrateFrom,
                              int stdin_fd) {
3148
    const char **argv = NULL, **tmp;
3149
    const char **progenv = NULL;
3150
    int i, ret;
3151
    struct stat sb;
3152 3153
    int *tapfds = NULL;
    int ntapfds = 0;
3154
    unsigned long long qemuCmdFlags;
3155
    fd_set keepfd;
3156
    const char *emulator;
G
Guido Günther 已提交
3157
    pid_t child;
3158
    int pos = -1;
3159
    char ebuf[1024];
3160
    char *pidfile = NULL;
3161
    int logfile = -1;
3162
    qemuDomainObjPrivatePtr priv = vm->privateData;
3163

3164
    struct qemudHookData hookData;
3165 3166 3167 3168
    hookData.conn = conn;
    hookData.vm = vm;
    hookData.driver = driver;

3169
    FD_ZERO(&keepfd);
3170

3171 3172
    DEBUG0("Beginning VM startup process");

D
Daniel P. Berrange 已提交
3173
    if (virDomainObjIsActive(vm)) {
3174 3175
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("VM is already active"));
3176 3177 3178
        return -1;
    }

3179 3180 3181 3182 3183
    /* Must be run before security labelling */
    DEBUG0("Preparing host devices");
    if (qemuPrepareHostDevices(driver, vm->def) < 0)
        goto cleanup;

3184 3185
    /* If you are using a SecurityDriver with dynamic labelling,
       then generate a security label for isolation */
3186
    DEBUG0("Generating domain security label (if required)");
3187
    if (driver->securityDriver &&
3188
        driver->securityDriver->domainGenSecurityLabel &&
3189
        driver->securityDriver->domainGenSecurityLabel(vm) < 0)
3190 3191
        return -1;

3192
    DEBUG0("Generating setting domain security labels (if required)");
3193 3194
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityAllLabel &&
3195
        driver->securityDriver->domainSetSecurityAllLabel(vm) < 0)
3196 3197
        goto cleanup;

3198 3199 3200
    /* Ensure no historical cgroup for this VM is lying around bogus
     * settings */
    DEBUG0("Ensuring no historical cgroup is lying around");
3201
    qemuRemoveCgroup(driver, vm, 1);
3202

3203 3204 3205
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        vm->def->graphics[0]->data.vnc.autoport) {
3206
        DEBUG0("Determining VNC port");
3207
        int port = qemudNextFreeVNCPort(driver);
3208
        if (port < 0) {
3209 3210
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Unable to find an unused VNC port"));
3211
            goto cleanup;
3212
        }
3213
        vm->def->graphics[0]->data.vnc.port = port;
3214
    }
3215

L
Laine Stump 已提交
3216
    if (virFileMakePath(driver->logDir) != 0) {
3217
        virReportSystemError(errno,
3218 3219
                             _("cannot create log directory %s"),
                             driver->logDir);
3220
        goto cleanup;
3221 3222
    }

3223
    DEBUG0("Creating domain log file");
3224
    if ((logfile = qemudLogFD(driver, vm->def->name)) < 0)
3225
        goto cleanup;
3226

3227 3228
    emulator = vm->def->emulator;

3229 3230 3231 3232
    /* 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
     */
3233
    if (stat(emulator, &sb) < 0) {
3234
        virReportSystemError(errno,
3235 3236
                             _("Cannot find QEMU binary %s"),
                             emulator);
3237
        goto cleanup;
3238 3239
    }

3240
    DEBUG0("Determing emulator version");
3241
    if (qemudExtractVersionInfo(emulator,
3242
                                NULL,
3243
                                &qemuCmdFlags) < 0)
3244
        goto cleanup;
3245

3246
    DEBUG0("Setting up domain cgroup (if required)");
3247
    if (qemuSetupCgroup(driver, vm) < 0)
3248 3249
        goto cleanup;

3250
    if (VIR_ALLOC(priv->monConfig) < 0) {
3251
        virReportOOMError();
3252 3253 3254
        goto cleanup;
    }

3255
    DEBUG0("Preparing monitor state");
3256
    if (qemuPrepareMonitorChr(driver, priv->monConfig, vm->def->name) < 0)
3257
        goto cleanup;
3258

D
Daniel P. Berrange 已提交
3259 3260 3261
#if HAVE_YAJL
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON)
        priv->monJSON = 1;
3262
    else
D
Daniel P. Berrange 已提交
3263
#endif
3264
        priv->monJSON = 0;
D
Daniel P. Berrange 已提交
3265

D
Daniel P. Berrange 已提交
3266
    if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
3267
        virReportSystemError(ret,
D
Daniel P. Berrange 已提交
3268 3269 3270 3271 3272
                             _("Cannot remove stale PID file for %s"),
                             vm->def->name);
        goto cleanup;
    }

3273
    if (!(pidfile = virFilePid(driver->stateDir, vm->def->name))) {
3274
        virReportSystemError(errno,
3275 3276 3277
                             "%s", _("Failed to build pidfile path."));
        goto cleanup;
    }
D
Daniel P. Berrange 已提交
3278

3279
    /*
M
Matthew Booth 已提交
3280
     * Normally PCI addresses are assigned in the virDomainCreate
3281 3282 3283 3284 3285
     * or virDomainDefine methods. We might still need to assign
     * some here to cope with the question of upgrades. Regardless
     * we also need to populate the PCi address set cache for later
     * use in hotplug
     */
3286
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
3287
        DEBUG0("Assigning domain PCI addresses");
3288
        /* Populate cache with current addresses */
3289 3290 3291 3292 3293 3294 3295
        if (priv->pciaddrs) {
            qemuDomainPCIAddressSetFree(priv->pciaddrs);
            priv->pciaddrs = NULL;
        }
        if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(vm->def)))
            goto cleanup;

3296 3297

        /* Assign any remaining addresses */
3298 3299
        if (qemuAssignDevicePCISlots(vm->def, priv->pciaddrs) < 0)
            goto cleanup;
3300 3301 3302 3303

        priv->persistentAddrs = 1;
    } else {
        priv->persistentAddrs = 0;
3304 3305
    }

3306
    DEBUG0("Building emulator command line");
3307
    vm->def->id = driver->nextvmid++;
3308
    if (qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
D
Daniel P. Berrange 已提交
3309
                              priv->monJSON, qemuCmdFlags, &argv, &progenv,
C
Chris Lalancette 已提交
3310 3311 3312 3313 3314
                              &tapfds, &ntapfds, migrateFrom,
                              vm->current_snapshot) < 0)
        goto cleanup;

    if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
3315
        goto cleanup;
3316

3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332
    /* now that we know it is about to start call the hook if present */
    if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
        char *xml = virDomainDefFormat(vm->def, 0);
        int hookret;

        hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
                    VIR_HOOK_QEMU_OP_START, VIR_HOOK_SUBOP_BEGIN, NULL, xml);
        VIR_FREE(xml);

        /*
         * If the script raised an error abort the launch
         */
        if (hookret < 0)
            goto cleanup;
    }

3333 3334
    tmp = progenv;
    while (*tmp) {
3335
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
3336
            VIR_WARN(_("Unable to write envv to logfile: %s"),
3337
                     virStrerror(errno, ebuf, sizeof ebuf));
3338
        if (safewrite(logfile, " ", 1) < 0)
3339
            VIR_WARN(_("Unable to write envv to logfile: %s"),
3340
                     virStrerror(errno, ebuf, sizeof ebuf));
3341 3342
        tmp++;
    }
3343 3344
    tmp = argv;
    while (*tmp) {
3345
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
3346
            VIR_WARN(_("Unable to write argv to logfile: %s"),
3347
                     virStrerror(errno, ebuf, sizeof ebuf));
3348
        if (safewrite(logfile, " ", 1) < 0)
3349
            VIR_WARN(_("Unable to write argv to logfile: %s"),
3350
                     virStrerror(errno, ebuf, sizeof ebuf));
3351 3352
        tmp++;
    }
3353
    if (safewrite(logfile, "\n", 1) < 0)
3354
        VIR_WARN(_("Unable to write argv to logfile: %s"),
3355
                 virStrerror(errno, ebuf, sizeof ebuf));
3356

3357
    if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
3358
        VIR_WARN(_("Unable to seek to end of logfile: %s"),
3359
                 virStrerror(errno, ebuf, sizeof ebuf));
3360

3361 3362 3363
    for (i = 0 ; i < ntapfds ; i++)
        FD_SET(tapfds[i], &keepfd);

3364
    ret = virExecDaemonize(argv, progenv, &keepfd, &child,
3365
                           stdin_fd, &logfile, &logfile,
3366
                           VIR_EXEC_NONBLOCK | VIR_EXEC_CLEAR_CAPS,
3367 3368 3369
                           qemudSecurityHook, &hookData,
                           pidfile);
    VIR_FREE(pidfile);
G
Guido Günther 已提交
3370 3371 3372

    /* wait for qemu process to to show up */
    if (ret == 0) {
3373
        if (virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) {
3374 3375
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Domain %s didn't show up\n"), vm->def->name);
3376
            ret = -1;
G
Guido Günther 已提交
3377
        }
3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388
    } 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;
    }
3389 3390

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

3392
    for (i = 0 ; argv[i] ; i++)
3393 3394
        VIR_FREE(argv[i]);
    VIR_FREE(argv);
3395

3396 3397 3398 3399
    for (i = 0 ; progenv[i] ; i++)
        VIR_FREE(progenv[i]);
    VIR_FREE(progenv);

3400 3401 3402
    if (tapfds) {
        for (i = 0 ; i < ntapfds ; i++) {
            close(tapfds[i]);
3403
        }
3404
        VIR_FREE(tapfds);
3405 3406
    }

3407
    if (ret == -1) /* The VM failed to start */
3408 3409
        goto cleanup;

3410
    DEBUG0("Waiting for monitor to show up");
3411
    if (qemudWaitForMonitor(driver, vm, pos) < 0)
3412 3413
        goto abort;

3414
    DEBUG0("Detecting VCPU PIDs");
3415
    if (qemuDetectVcpuPIDs(driver, vm) < 0)
3416 3417
        goto abort;

3418
    DEBUG0("Setting any required VM passwords");
3419
    if (qemuInitPasswords(conn, driver, vm, qemuCmdFlags) < 0)
3420 3421
        goto abort;

D
Daniel P. Berrange 已提交
3422 3423 3424
    /* If we have -device, then addresses are assigned explicitly.
     * If not, then we have to detect dynamic ones here */
    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
3425
        DEBUG0("Determining domain device PCI addresses");
D
Daniel P. Berrange 已提交
3426 3427 3428
        if (qemuInitPCIAddresses(driver, vm) < 0)
            goto abort;
    }
3429

3430
    DEBUG0("Setting initial memory amount");
3431
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
3432
    if (qemuMonitorSetBalloon(priv->mon, vm->def->memory) < 0) {
3433
        qemuDomainObjExitMonitorWithDriver(driver, vm);
3434
        goto abort;
3435
    }
3436 3437

    if (migrateFrom == NULL) {
3438
        DEBUG0("Starting domain CPUs");
3439 3440 3441
        /* Allow the CPUS to start executing */
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
            if (virGetLastError() == NULL)
3442 3443
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("resume operation failed"));
3444 3445 3446 3447
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto abort;
        }
    }
3448
    qemuDomainObjExitMonitorWithDriver(driver, vm);
3449

3450

3451
    DEBUG0("Writing domain status to disk");
3452
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
3453
        goto abort;
3454

3455 3456 3457
    if (logfile != -1)
        close(logfile);

3458
    return 0;
3459 3460

cleanup:
3461 3462 3463
    /* 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 */
S
Stefan Berger 已提交
3464 3465
    qemuTearVMNWFilters(vm);

3466
    qemuDomainReAttachHostDevices(driver, vm->def);
3467

3468 3469
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityAllLabel)
3470
        driver->securityDriver->domainRestoreSecurityAllLabel(vm);
3471 3472
    if (driver->securityDriver &&
        driver->securityDriver->domainReleaseSecurityLabel)
3473
        driver->securityDriver->domainReleaseSecurityLabel(vm);
3474
    qemuRemoveCgroup(driver, vm, 1);
3475 3476 3477 3478
    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;
3479 3480
    if (logfile != -1)
        close(logfile);
3481 3482
    vm->def->id = -1;
    return -1;
3483 3484 3485 3486

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

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

    return -1;
3493 3494 3495
}


3496
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
3497
                                  virDomainObjPtr vm) {
D
Daniel P. Berrange 已提交
3498
    int ret;
3499
    int retries = 0;
3500
    qemuDomainObjPrivatePtr priv = vm->privateData;
3501
    virErrorPtr orig_err;
3502 3503
    virDomainDefPtr def;
    int i;
D
Daniel P. Berrange 已提交
3504

D
Daniel P. Berrange 已提交
3505
    if (!virDomainObjIsActive(vm))
3506
        return;
3507

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

3510 3511 3512 3513
    /* This method is routinely used in clean up paths. Disable error
     * reporting so we don't squash a legit error. */
    orig_err = virSaveLastError();

S
Stefan Berger 已提交
3514 3515
    qemuTearVMNWFilters(vm);

3516
    if (driver->macFilter) {
3517
        def = vm->def;
3518 3519 3520 3521
        for (i = 0 ; i < def->nnets ; i++) {
            virDomainNetDefPtr net = def->nets[i];
            if (net->ifname == NULL)
                continue;
3522
            if ((errno = networkDisallowMacOnPort(driver, net->ifname,
3523
                                                  net->mac))) {
3524
                virReportSystemError(errno,
3525 3526 3527 3528 3529 3530
             _("failed to remove ebtables rule to allow MAC address on  '%s'"),
                                     net->ifname);
            }
        }
    }

G
Guido Günther 已提交
3531 3532
    if (virKillProcess(vm->pid, 0) == 0 &&
        virKillProcess(vm->pid, SIGTERM) < 0)
3533
        virReportSystemError(errno,
3534 3535
                             _("Failed to send SIGTERM to %s (%d)"),
                             vm->def->name, vm->pid);
3536

3537 3538 3539
    if (priv->mon &&
        qemuMonitorClose(priv->mon) == 0) {
        virDomainObjUnref(vm);
3540
        priv->mon = NULL;
3541
    }
3542

3543 3544 3545 3546 3547
    if (priv->monConfig) {
        if (priv->monConfig->type == VIR_DOMAIN_CHR_TYPE_UNIX)
            unlink(priv->monConfig->data.nix.path);
        virDomainChrDefFree(priv->monConfig);
        priv->monConfig = NULL;
3548 3549
    }

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

3553 3554 3555 3556 3557 3558 3559 3560 3561 3562
    /* now that we know it's stopped call the hook if present */
    if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
        char *xml = virDomainDefFormat(vm->def, 0);

        /* we can't stop the operation even if the script raised an error */
        virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name,
                    VIR_HOOK_QEMU_OP_STOPPED, VIR_HOOK_SUBOP_END, NULL, xml);
        VIR_FREE(xml);
    }

3563
    /* Reset Security Labels */
3564
    if (driver->securityDriver &&
3565
        driver->securityDriver->domainRestoreSecurityAllLabel)
3566
        driver->securityDriver->domainRestoreSecurityAllLabel(vm);
3567 3568
    if (driver->securityDriver &&
        driver->securityDriver->domainReleaseSecurityLabel)
3569
        driver->securityDriver->domainReleaseSecurityLabel(vm);
3570

3571 3572 3573 3574 3575 3576 3577
    /* 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);
    }

D
Daniel P. Berrange 已提交
3578
    virDomainDefClearDeviceAliases(vm->def);
3579 3580 3581 3582 3583
    if (!priv->persistentAddrs) {
        virDomainDefClearPCIAddresses(vm->def);
        qemuDomainPCIAddressSetFree(priv->pciaddrs);
        priv->pciaddrs = NULL;
    }
3584

3585
    qemuDomainReAttachHostDevices(driver, vm->def);
3586

S
Stefan Berger 已提交
3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597
#if WITH_MACVTAP
    def = vm->def;
    for (i = 0; i < def->nnets; i++) {
        virDomainNetDefPtr net = def->nets[i];
        if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
            if (net->ifname)
                delMacvtap(net->ifname);
        }
    }
#endif

3598
retry:
3599
    if ((ret = qemuRemoveCgroup(driver, vm, 0)) < 0) {
3600 3601 3602 3603 3604 3605 3606 3607
        if (ret == -EBUSY && (retries++ < 5)) {
            usleep(200*1000);
            goto retry;
        }
        VIR_WARN("Failed to remove cgroup for %s",
                 vm->def->name);
    }

3608
    qemudRemoveDomainStatus(driver, vm);
D
Daniel P. Berrange 已提交
3609

3610
    vm->pid = -1;
3611
    vm->def->id = -1;
3612
    vm->state = VIR_DOMAIN_SHUTOFF;
3613 3614
    VIR_FREE(priv->vcpupids);
    priv->nvcpupids = 0;
3615 3616

    if (vm->newDef) {
3617
        virDomainDefFree(vm->def);
3618
        vm->def = vm->newDef;
3619
        vm->def->id = -1;
3620 3621
        vm->newDef = NULL;
    }
3622 3623 3624 3625 3626

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
3627 3628 3629
}


3630
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
3631
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
3632
                                  int flags ATTRIBUTE_UNUSED) {
3633
    if (conn->uri == NULL) {
3634 3635 3636
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

3637
        conn->uri = xmlParseURI(qemu_driver->privileged ?
3638 3639
                                "qemu:///system" :
                                "qemu:///session");
3640
        if (!conn->uri) {
3641
            virReportOOMError();
3642 3643
            return VIR_DRV_OPEN_ERROR;
        }
3644 3645 3646 3647 3648 3649 3650 3651 3652 3653
    } 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;

3654
        if (qemu_driver == NULL) {
3655 3656
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("qemu state driver is not active"));
3657 3658 3659
            return VIR_DRV_OPEN_ERROR;
        }

3660
        if (conn->uri->path == NULL) {
3661 3662 3663 3664 3665
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no QEMU URI path given, try %s"),
                            qemu_driver->privileged
                            ? "qemu:///system"
                            : "qemu:///session");
3666 3667 3668
                return VIR_DRV_OPEN_ERROR;
        }

3669
        if (qemu_driver->privileged) {
3670 3671
            if (STRNEQ (conn->uri->path, "/system") &&
                STRNEQ (conn->uri->path, "/session")) {
3672 3673 3674
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///system"),
                                conn->uri->path);
3675 3676 3677 3678
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
3679 3680 3681
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///session"),
                                conn->uri->path);
3682 3683 3684
                return VIR_DRV_OPEN_ERROR;
            }
        }
3685 3686 3687 3688 3689 3690 3691
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
3692
    struct qemud_driver *driver = conn->privateData;
3693 3694

    /* Get rid of callbacks registered for this conn */
3695
    qemuDriverLock(driver);
3696
    virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
3697
    qemuDriverUnlock(driver);
3698 3699 3700 3701 3702 3703

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
3704 3705 3706 3707 3708
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
3709 3710 3711 3712 3713
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
3714 3715 3716
    }
}

3717
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
3718
    return "QEMU";
3719 3720
}

3721

3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734
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;
}


3735 3736 3737 3738
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
3739

3740 3741
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
3742
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
3743
        return -1;
3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754
    }

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

    close(fd);
    return maxvcpus;
}


3755
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
3756 3757 3758
    if (!type)
        return 16;

3759
    if (STRCASEEQ(type, "qemu"))
3760 3761
        return 16;

3762
    if (STRCASEEQ(type, "kvm"))
3763
        return kvmGetMaxVCPUs();
3764

3765
    if (STRCASEEQ(type, "kqemu"))
3766
        return 1;
3767

3768 3769
    qemuReportError(VIR_ERR_INVALID_ARG,
                    _("unknown type '%s'"), type);
3770 3771 3772
    return -1;
}

3773

3774
static char *qemudGetCapabilities(virConnectPtr conn) {
3775
    struct qemud_driver *driver = conn->privateData;
3776
    virCapsPtr caps = NULL;
3777
    char *xml = NULL;
3778

3779
    qemuDriverLock(driver);
3780

3781
    if ((caps = qemuCreateCapabilities(qemu_driver->caps,
3782
                                       qemu_driver)) == NULL) {
3783 3784 3785
        virCapabilitiesFree(caps);
        goto cleanup;
    }
3786

3787
    virCapabilitiesFree(qemu_driver->caps);
3788 3789 3790
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
3791
        virReportOOMError();
3792 3793

cleanup:
3794
    qemuDriverUnlock(driver);
3795

3796
    return xml;
3797 3798 3799
}


3800
static int qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid, int tid) {
D
Daniel P. Berrange 已提交
3801 3802
    char proc[PATH_MAX];
    FILE *pidinfo;
3803
    unsigned long long usertime, systime;
3804 3805
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
3806

3807 3808 3809 3810 3811 3812
    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 已提交
3813 3814 3815 3816
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
3817
        /*printf("cannot read pid info");*/
D
Daniel P. Berrange 已提交
3818
        /* VM probably shut down, so fake 0 */
3819 3820 3821 3822
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
D
Daniel P. Berrange 已提交
3823 3824 3825
        return 0;
    }

3826 3827 3828 3829 3830 3831 3832 3833 3834 3835
    /* 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) {
3836
        fclose(pidinfo);
3837 3838
        VIR_WARN0("cannot parse process status data");
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
3839 3840 3841 3842 3843 3844 3845 3846
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
3847 3848 3849 3850 3851
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

D
Daniel P. Berrange 已提交
3852

3853 3854
    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
              pid, tid, usertime, systime, cpu);
D
Daniel P. Berrange 已提交
3855 3856 3857 3858 3859 3860 3861

    fclose(pidinfo);

    return 0;
}


3862
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
3863
                                          int id) {
3864 3865 3866 3867
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

3868
    qemuDriverLock(driver);
3869
    vm  = virDomainFindByID(&driver->domains, id);
3870
    qemuDriverUnlock(driver);
3871 3872

    if (!vm) {
3873 3874
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching id %d"), id);
3875
        goto cleanup;
3876 3877
    }

3878
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
3879
    if (dom) dom->id = vm->def->id;
3880 3881

cleanup:
3882 3883
    if (vm)
        virDomainObjUnlock(vm);
3884 3885
    return dom;
}
3886

3887
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
3888
                                            const unsigned char *uuid) {
3889 3890 3891
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
3892

3893
    qemuDriverLock(driver);
3894
    vm = virDomainFindByUUID(&driver->domains, uuid);
3895 3896
    qemuDriverUnlock(driver);

3897
    if (!vm) {
3898 3899
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
3900 3901
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
3902
        goto cleanup;
3903 3904
    }

3905
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
3906
    if (dom) dom->id = vm->def->id;
3907 3908

cleanup:
3909 3910
    if (vm)
        virDomainObjUnlock(vm);
3911 3912
    return dom;
}
3913

3914
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
3915
                                            const char *name) {
3916 3917 3918
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
3919

3920
    qemuDriverLock(driver);
3921
    vm = virDomainFindByName(&driver->domains, name);
3922 3923
    qemuDriverUnlock(driver);

3924
    if (!vm) {
3925 3926
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), name);
3927
        goto cleanup;
3928 3929
    }

3930
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
3931
    if (dom) dom->id = vm->def->id;
3932 3933

cleanup:
3934 3935
    if (vm)
        virDomainObjUnlock(vm);
3936 3937 3938
    return dom;
}

3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949

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) {
3950
        qemuReportError(VIR_ERR_NO_DOMAIN, NULL);
3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970
        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) {
3971
        qemuReportError(VIR_ERR_NO_DOMAIN, NULL);
3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982
        goto cleanup;
    }
    ret = obj->persistent;

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


3983
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
3984 3985 3986
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

3987
    qemuDriverLock(driver);
3988
    if (qemudExtractVersion(driver) < 0)
3989
        goto cleanup;
3990

3991
    *version = qemu_driver->qemuVersion;
3992 3993 3994
    ret = 0;

cleanup:
3995
    qemuDriverUnlock(driver);
3996
    return ret;
D
Daniel P. Berrange 已提交
3997 3998
}

3999
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
4000
    struct qemud_driver *driver = conn->privateData;
4001
    int n;
4002

4003
    qemuDriverLock(driver);
4004
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
4005
    qemuDriverUnlock(driver);
4006

4007
    return n;
D
Daniel P. Berrange 已提交
4008
}
4009

4010
static int qemudNumDomains(virConnectPtr conn) {
4011
    struct qemud_driver *driver = conn->privateData;
4012
    int n;
4013

4014
    qemuDriverLock(driver);
4015
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
4016
    qemuDriverUnlock(driver);
4017

4018
    return n;
D
Daniel P. Berrange 已提交
4019
}
4020

4021
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
4022
                                      unsigned int flags ATTRIBUTE_UNUSED) {
4023
    struct qemud_driver *driver = conn->privateData;
4024
    virDomainDefPtr def;
4025
    virDomainObjPtr vm = NULL;
4026
    virDomainPtr dom = NULL;
4027
    virDomainEventPtr event = NULL;
D
Daniel P. Berrange 已提交
4028

4029
    qemuDriverLock(driver);
4030
    if (!(def = virDomainDefParseString(driver->caps, xml,
4031
                                        VIR_DOMAIN_XML_INACTIVE)))
4032
        goto cleanup;
4033

4034
    if (virSecurityDriverVerify(def) < 0)
4035 4036
        goto cleanup;

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

4040 4041 4042 4043 4044 4045
    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

    if (qemuAssignPCIAddresses(def) < 0)
        goto cleanup;

4046
    if (!(vm = virDomainAssignDef(driver->caps,
4047
                                  &driver->domains,
4048
                                  def, false)))
4049 4050 4051
        goto cleanup;

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

4053 4054 4055
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup; /* XXXX free the 'vm' we created ? */

4056
    if (qemudStartVMDaemon(conn, driver, vm, NULL, -1) < 0) {
4057 4058 4059
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
4060
        vm = NULL;
4061
        goto endjob;
D
Daniel P. Berrange 已提交
4062
    }
4063 4064 4065 4066

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

4068
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4069
    if (dom) dom->id = vm->def->id;
4070

4071
endjob:
4072 4073 4074
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4075

4076 4077
cleanup:
    virDomainDefFree(def);
4078 4079
    if (vm)
        virDomainObjUnlock(vm);
4080 4081
    if (event)
        qemuDomainEventQueue(driver, event);
4082
    qemuDriverUnlock(driver);
4083
    return dom;
D
Daniel P. Berrange 已提交
4084 4085 4086
}


4087
static int qemudDomainSuspend(virDomainPtr dom) {
4088 4089 4090
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4091
    virDomainEventPtr event = NULL;
4092
    qemuDomainObjPrivatePtr priv;
4093

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

D
Daniel P. Berrange 已提交
4097
    if (!vm) {
4098 4099
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4100 4101
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4102
        goto cleanup;
D
Daniel P. Berrange 已提交
4103
    }
D
Daniel P. Berrange 已提交
4104
    if (!virDomainObjIsActive(vm)) {
4105 4106
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4107
        goto cleanup;
D
Daniel P. Berrange 已提交
4108
    }
4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126

    priv = vm->privateData;

    if (priv->jobActive == QEMU_JOB_MIGRATION) {
        if (vm->state != VIR_DOMAIN_PAUSED) {
            VIR_DEBUG("Requesting domain pause on %s",
                      vm->def->name);
            priv->jobSignals |= QEMU_JOB_SIGNAL_SUSPEND;
        }
        ret = 0;
        goto cleanup;
    } else {
        if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
            goto cleanup;

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("domain is not running"));
4127
            goto endjob;
4128
        }
4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144
        if (vm->state != VIR_DOMAIN_PAUSED) {
            int rc;

            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorStopCPUs(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (rc < 0)
                goto endjob;
            vm->state = VIR_DOMAIN_PAUSED;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
        }
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            goto endjob;
        ret = 0;
D
Daniel P. Berrange 已提交
4145
    }
4146

4147
endjob:
4148 4149
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4150

4151
cleanup:
4152 4153
    if (vm)
        virDomainObjUnlock(vm);
4154

4155
    if (event)
4156
        qemuDomainEventQueue(driver, event);
4157
    qemuDriverUnlock(driver);
4158
    return ret;
D
Daniel P. Berrange 已提交
4159 4160 4161
}


4162
static int qemudDomainResume(virDomainPtr dom) {
4163 4164 4165
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4166
    virDomainEventPtr event = NULL;
4167

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

D
Daniel P. Berrange 已提交
4171
    if (!vm) {
4172 4173
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4174 4175
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4176
        goto cleanup;
D
Daniel P. Berrange 已提交
4177
    }
4178 4179 4180 4181

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

D
Daniel P. Berrange 已提交
4182
    if (!virDomainObjIsActive(vm)) {
4183 4184
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4185
        goto endjob;
D
Daniel P. Berrange 已提交
4186
    }
4187
    if (vm->state == VIR_DOMAIN_PAUSED) {
4188
        qemuDomainObjPrivatePtr priv = vm->privateData;
4189
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4190
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
4191
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4192
            if (virGetLastError() == NULL)
4193 4194
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resume operation failed"));
4195
            goto endjob;
4196
        }
4197
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4198
        vm->state = VIR_DOMAIN_RUNNING;
4199 4200 4201
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
4202
    }
4203
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
4204
        goto endjob;
4205 4206
    ret = 0;

4207
endjob:
4208 4209
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4210

4211
cleanup:
4212 4213
    if (vm)
        virDomainObjUnlock(vm);
4214
    if (event)
4215
        qemuDomainEventQueue(driver, event);
4216
    qemuDriverUnlock(driver);
4217
    return ret;
D
Daniel P. Berrange 已提交
4218 4219 4220
}


4221
static int qemudDomainShutdown(virDomainPtr dom) {
4222 4223 4224
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4225

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

4230
    if (!vm) {
4231 4232
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4233 4234
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4235
        goto cleanup;
4236 4237
    }

4238 4239 4240
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
4241
    if (!virDomainObjIsActive(vm)) {
4242 4243
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4244
        goto endjob;
4245 4246
    }

4247
    qemuDomainObjPrivatePtr priv = vm->privateData;
4248 4249 4250
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorSystemPowerdown(priv->mon);
    qemuDomainObjExitMonitor(vm);
4251

4252
endjob:
4253 4254
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4255

4256
cleanup:
4257 4258
    if (vm)
        virDomainObjUnlock(vm);
4259
    return ret;
4260 4261 4262
}


4263
static int qemudDomainDestroy(virDomainPtr dom) {
4264 4265 4266
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4267
    virDomainEventPtr event = NULL;
4268

4269
    qemuDriverLock(driver);
4270
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
4271
    if (!vm) {
4272 4273
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4274 4275
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4276
        goto cleanup;
D
Daniel P. Berrange 已提交
4277
    }
4278 4279 4280 4281

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

D
Daniel P. Berrange 已提交
4282
    if (!virDomainObjIsActive(vm)) {
4283 4284
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4285
        goto endjob;
4286
    }
4287

4288
    qemudShutdownVMDaemon(driver, vm);
4289 4290 4291
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
4292
    if (!vm->persistent) {
4293 4294 4295
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
4296 4297
        vm = NULL;
    }
4298 4299
    ret = 0;

4300
endjob:
4301 4302 4303
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4304

4305
cleanup:
4306 4307
    if (vm)
        virDomainObjUnlock(vm);
4308 4309
    if (event)
        qemuDomainEventQueue(driver, event);
4310
    qemuDriverUnlock(driver);
4311
    return ret;
D
Daniel P. Berrange 已提交
4312 4313 4314
}


4315
static char *qemudDomainGetOSType(virDomainPtr dom) {
4316 4317 4318
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
4319

4320
    qemuDriverLock(driver);
4321
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4322
    qemuDriverUnlock(driver);
4323
    if (!vm) {
4324 4325
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4326 4327
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4328
        goto cleanup;
4329 4330
    }

4331
    if (!(type = strdup(vm->def->os.type)))
4332
        virReportOOMError();
4333 4334

cleanup:
4335 4336
    if (vm)
        virDomainObjUnlock(vm);
4337 4338 4339
    return type;
}

4340 4341
/* Returns max memory in kb, 0 if error */
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
4342 4343 4344
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
4345

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

4350
    if (!vm) {
4351 4352
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4353 4354
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4355
        goto cleanup;
4356 4357
    }

4358 4359 4360
    ret = vm->def->maxmem;

cleanup:
4361 4362
    if (vm)
        virDomainObjUnlock(vm);
4363
    return ret;
4364 4365 4366
}

static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
4367
    struct qemud_driver *driver = dom->conn->privateData;
4368
    qemuDomainObjPrivatePtr priv;
4369
    virDomainObjPtr vm;
4370
    int ret = -1, r;
4371

4372
    qemuDriverLock(driver);
4373
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4374
    qemuDriverUnlock(driver);
4375
    if (!vm) {
4376 4377
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4378 4379
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4380
        goto cleanup;
4381 4382
    }

4383 4384 4385 4386 4387 4388
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

4389
    if (newmem > vm->def->maxmem) {
4390 4391
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("cannot set memory higher than max memory"));
4392
        goto cleanup;
4393 4394
    }

4395 4396 4397
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

4398 4399 4400 4401 4402 4403
    priv = vm->privateData;
    qemuDomainObjEnterMonitor(vm);
    r = qemuMonitorSetBalloon(priv->mon, newmem);
    qemuDomainObjExitMonitor(vm);
    if (r < 0)
        goto endjob;
4404

4405 4406 4407 4408 4409
    /* Lack of balloon support is a fatal error */
    if (r == 0) {
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cannot set memory of an active domain"));
        goto endjob;
4410
    }
4411

4412
    ret = 0;
4413
endjob:
4414 4415
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4416

4417
cleanup:
4418 4419
    if (vm)
        virDomainObjUnlock(vm);
4420
    return ret;
4421 4422
}

4423
static int qemudDomainGetInfo(virDomainPtr dom,
4424
                              virDomainInfoPtr info) {
4425 4426 4427
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4428 4429
    int err;
    unsigned long balloon;
4430

4431
    qemuDriverLock(driver);
4432
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4433
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
4434
    if (!vm) {
4435 4436
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4437 4438
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4439
        goto cleanup;
D
Daniel P. Berrange 已提交
4440 4441
    }

4442
    info->state = vm->state;
D
Daniel P. Berrange 已提交
4443

D
Daniel P. Berrange 已提交
4444
    if (!virDomainObjIsActive(vm)) {
4445
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
4446
    } else {
4447
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
4448
            qemuReportError(VIR_ERR_OPERATION_FAILED, ("cannot read cputime for domain"));
4449
            goto cleanup;
D
Daniel P. Berrange 已提交
4450 4451 4452
        }
    }

4453
    info->maxMem = vm->def->maxmem;
4454

D
Daniel P. Berrange 已提交
4455
    if (virDomainObjIsActive(vm)) {
4456
        qemuDomainObjPrivatePtr priv = vm->privateData;
4457 4458 4459
        if (!priv->jobActive) {
            if (qemuDomainObjBeginJob(vm) < 0)
                goto cleanup;
4460

4461 4462 4463 4464
            qemuDomainObjEnterMonitor(vm);
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
            qemuDomainObjExitMonitor(vm);
            if (err < 0) {
4465 4466
                if (qemuDomainObjEndJob(vm) == 0)
                    vm = NULL;
4467 4468 4469 4470 4471 4472 4473 4474 4475
                goto cleanup;
            }

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

4476 4477 4478 4479
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
                goto cleanup;
            }
4480 4481 4482
        } else {
            info->memory = vm->def->memory;
        }
4483 4484 4485 4486
    } else {
        info->memory = vm->def->memory;
    }

4487
    info->nrVirtCpu = vm->def->vcpus;
4488 4489 4490
    ret = 0;

cleanup:
4491 4492
    if (vm)
        virDomainObjUnlock(vm);
4493
    return ret;
D
Daniel P. Berrange 已提交
4494 4495 4496
}


4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525
/** qemuDomainMigrateOffline:
 * Pause domain for non-live migration.
 */
static int
qemuDomainMigrateOffline(struct qemud_driver *driver,
                         virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret;

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorStopCPUs(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (ret == 0) {
        virDomainEventPtr event;

        vm->state = VIR_DOMAIN_PAUSED;
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }

    return ret;
}


4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543
static int
qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr vm)
{
    int ret = -1;
    int status;
    unsigned long long memProcessed;
    unsigned long long memRemaining;
    unsigned long long memTotal;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

    while (priv->jobInfo.type == VIR_DOMAIN_JOB_UNBOUNDED) {
        /* Poll every 50ms for progress & to allow cancellation */
        struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000ull };
        struct timeval now;
        int rc;

4544 4545
        if (priv->jobSignals & QEMU_JOB_SIGNAL_CANCEL) {
            priv->jobSignals ^= QEMU_JOB_SIGNAL_CANCEL;
4546 4547 4548 4549 4550 4551 4552
            VIR_DEBUG0("Cancelling migration at client request");
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorMigrateCancel(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (rc < 0) {
                VIR_WARN0("Unable to cancel migration");
            }
4553 4554 4555 4556 4557
        } else if (priv->jobSignals & QEMU_JOB_SIGNAL_SUSPEND) {
            priv->jobSignals ^= QEMU_JOB_SIGNAL_SUSPEND;
            VIR_DEBUG0("Pausing domain for non-live migration");
            if (qemuDomainMigrateOffline(driver, vm) < 0)
                VIR_WARN0("Unable to pause domain");
4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568
        } else if (priv->jobSignals & QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME) {
            unsigned long long ms = priv->jobSignalsData.migrateDowntime;

            priv->jobSignals ^= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME;
            priv->jobSignalsData.migrateDowntime = 0;
            VIR_DEBUG("Setting migration downtime to %llums", ms);
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorSetMigrationDowntime(priv->mon, ms);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (rc < 0)
                VIR_WARN0("Unable to set migration downtime");
4569 4570
        }

4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        rc = qemuMonitorGetMigrationStatus(priv->mon,
                                           &status,
                                           &memProcessed,
                                           &memRemaining,
                                           &memTotal);
        qemuDomainObjExitMonitorWithDriver(driver, vm);

        if (rc < 0) {
            priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED;
            goto cleanup;
        }

        if (gettimeofday(&now, NULL) < 0) {
            priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED;
            virReportSystemError(errno, "%s",
                                 _("cannot get time of day"));
            goto cleanup;
        }
        priv->jobInfo.timeElapsed =
            ((now.tv_sec * 1000ull) + (now.tv_usec / 1000)) -
            priv->jobStart;

        switch (status) {
        case QEMU_MONITOR_MIGRATION_STATUS_INACTIVE:
            priv->jobInfo.type = VIR_DOMAIN_JOB_NONE;
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Migration is not active"));
            break;

        case QEMU_MONITOR_MIGRATION_STATUS_ACTIVE:
            priv->jobInfo.dataTotal = memTotal;
            priv->jobInfo.dataRemaining = memRemaining;
            priv->jobInfo.dataProcessed = memProcessed;

            priv->jobInfo.memTotal = memTotal;
            priv->jobInfo.memRemaining = memRemaining;
            priv->jobInfo.memProcessed = memProcessed;
            break;

        case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED:
            priv->jobInfo.type = VIR_DOMAIN_JOB_COMPLETED;
            ret = 0;
            break;

        case QEMU_MONITOR_MIGRATION_STATUS_ERROR:
            priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED;
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Migration unexpectedly failed"));
            break;

        case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
            priv->jobInfo.type = VIR_DOMAIN_JOB_CANCELLED;
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Migration was cancelled by client"));
            break;
        }

        virDomainObjUnlock(vm);
        qemuDriverUnlock(driver);

        nanosleep(&ts, NULL);

        qemuDriverLock(driver);
        virDomainObjLock(vm);
    }

cleanup:
    return ret;
}


4643
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
4644 4645 4646
#define QEMUD_SAVE_VERSION 2

enum qemud_save_formats {
4647 4648 4649
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
4650 4651
    /*
     * Deprecated by xz and never used as part of a release
4652
     * QEMUD_SAVE_FORMAT_LZMA
4653 4654
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
4655
    QEMUD_SAVE_FORMAT_LZOP = 4,
4656 4657 4658
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
4659 4660

    QEMUD_SAVE_FORMAT_LAST
4661
};
4662

4663 4664 4665 4666 4667
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
4668 4669
              "xz",
              "lzop")
4670

4671 4672 4673 4674 4675
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
    int version;
    int xml_len;
    int was_running;
4676 4677
    int compressed;
    int unused[15];
4678 4679
};

4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708
struct fileOpHookData {
    virDomainPtr dom;
    const char *path;
    char *xml;
    struct qemud_save_header *header;
};

static int qemudDomainSaveFileOpHook(int fd, void *data) {
    struct fileOpHookData *hdata = data;
    int ret = 0;

    if (safewrite(fd, hdata->header, sizeof(*hdata->header)) != sizeof(*hdata->header)) {
        ret = errno;
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                         _("failed to write save header to '%s'"), hdata->path);
        goto endjob;
    }

    if (safewrite(fd, hdata->xml, hdata->header->xml_len) != hdata->header->xml_len) {
        ret = errno;
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                         _("failed to write xml to '%s'"), hdata->path);
        goto endjob;
    }
endjob:
    return ret;
}


4709 4710
static int qemudDomainSaveFlag(virDomainPtr dom, const char *path,
                               int compressed)
4711
{
4712
    struct qemud_driver *driver = dom->conn->privateData;
4713
    virDomainObjPtr vm = NULL;
4714
    char *xml = NULL;
4715
    struct qemud_save_header header;
4716 4717
    struct fileOpHookData hdata;
    int bypassSecurityDriver = 0;
4718
    int ret = -1;
4719
    int rc;
4720
    virDomainEventPtr event = NULL;
4721
    qemuDomainObjPrivatePtr priv;
4722 4723 4724 4725 4726

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

4727
    qemuDriverLock(driver);
4728 4729

    header.compressed = compressed;
4730

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

D
Daniel P. Berrange 已提交
4733
    if (!vm) {
4734 4735
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4736 4737
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4738
        goto cleanup;
D
Daniel P. Berrange 已提交
4739
    }
4740
    priv = vm->privateData;
4741

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

D
Daniel P. Berrange 已提交
4745
    if (!virDomainObjIsActive(vm)) {
4746 4747
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4748
        goto endjob;
D
Daniel P. Berrange 已提交
4749
    }
4750

4751 4752 4753
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

4754 4755 4756
    /* Pause */
    if (vm->state == VIR_DOMAIN_RUNNING) {
        header.was_running = 1;
4757
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4758
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
4759 4760
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto endjob;
4761
        }
4762
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4763
        vm->state = VIR_DOMAIN_PAUSED;
4764 4765 4766
    }

    /* Get XML for the domain */
4767
    xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
4768
    if (!xml) {
4769 4770
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
4771
        goto endjob;
4772 4773 4774
    }
    header.xml_len = strlen(xml) + 1;

4775 4776 4777 4778 4779 4780
    /* Setup hook data needed by virFileOperation hook function */
    hdata.dom = dom;
    hdata.path = path;
    hdata.xml = xml;
    hdata.header = &header;

4781 4782
    /* Write header to file, followed by XML */

4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802
    /* First try creating the file as root */
    if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
                               S_IRUSR|S_IWUSR,
                               getuid(), getgid(),
                               qemudDomainSaveFileOpHook, &hdata,
                               0)) != 0) {

        /* If we failed as root, and the error was permission-denied
           (EACCES), assume it's on a network-connected share where
           root access is restricted (eg, root-squashed NFS). If the
           qemu user (driver->user) is non-root, just set a flag to
           bypass security driver shenanigans, and retry the operation
           after doing setuid to qemu user */

        if ((rc != EACCES) ||
            driver->user == getuid()) {
            virReportSystemError(rc, _("Failed to create domain save file '%s'"),
                                 path);
            goto endjob;
        }
4803

4804 4805 4806 4807 4808
#ifdef __linux__
        /* On Linux we can also verify the FS-type of the directory. */
        char *dirpath, *p;
        struct statfs st;
        int statfs_ret;
4809

4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876
        if ((dirpath = strdup(path)) == NULL) {
            virReportOOMError();
            goto endjob;
        }

        do {
            // Try less and less of the path until we get to a
            // directory we can stat. Even if we don't have 'x'
            // permission on any directory in the path on the NFS
            // server (assuming it's NFS), we will be able to stat the
            // mount point, and that will properly tell us if the
            // fstype is NFS.

            if ((p = strrchr(dirpath, '/')) == NULL) {
                qemuReportError(VIR_ERR_INVALID_ARG,
                                _("Invalid relative path '%s' for domain save file"),
                                path);
                VIR_FREE(dirpath);
                goto endjob;
            }

            if (p == dirpath)
                *(p+1) = '\0';
            else
                *p = '\0';

            statfs_ret = statfs(dirpath, &st);

        } while ((statfs_ret == -1) && (p != dirpath));

        if (statfs_ret == -1) {
            virReportSystemError(errno,
                                 _("Failed to create domain save file '%s'"
                                   " statfs of all elements of path failed."),
                                 path);
            VIR_FREE(dirpath);
            goto endjob;
        }

        if (st.f_type != NFS_SUPER_MAGIC) {
            virReportSystemError(rc,
                                 _("Failed to create domain save file '%s'"
                                   " (fstype of '%s' is 0x%X"),
                                 path, dirpath, (unsigned int) st.f_type);
            VIR_FREE(dirpath);
            goto endjob;
        }
        VIR_FREE(dirpath);
#endif

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

        if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
                                   S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
                                   driver->user, driver->group,
                                   qemudDomainSaveFileOpHook, &hdata,
                                   VIR_FILE_OP_AS_UID)) != 0) {
            virReportSystemError(rc, _("Error from child process creating '%s'"),
                                 path);
            goto endjob;
        }

        /* Since we had to setuid to create the file, and the fstype
           is NFS, we assume it's a root-squashing NFS share, and that
           the security driver stuff would have failed anyway */

        bypassSecurityDriver = 1;
4877
    }
4878

4879 4880 4881

    if ((!bypassSecurityDriver) &&
        driver->securityDriver &&
4882
        driver->securityDriver->domainSetSavedStateLabel &&
4883
        driver->securityDriver->domainSetSavedStateLabel(vm, path) == -1)
4884 4885
        goto endjob;

4886 4887
    if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = { "cat", NULL };
M
Matthias Bolte 已提交
4888
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4889
        rc = qemuMonitorMigrateToCommand(priv->mon, 1, args, path);
M
Matthias Bolte 已提交
4890
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4891
    } else {
4892
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
4893 4894 4895 4896 4897
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
M
Matthias Bolte 已提交
4898
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4899
        rc = qemuMonitorMigrateToCommand(priv->mon, 1, args, path);
M
Matthias Bolte 已提交
4900
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4901 4902
    }

4903 4904 4905 4906 4907
    if (rc < 0)
        goto endjob;

    rc = qemuDomainWaitForMigrationComplete(driver, vm);

4908
    if (rc < 0)
4909
        goto endjob;
4910

4911 4912
    if ((!bypassSecurityDriver) &&
        driver->securityDriver &&
4913
        driver->securityDriver->domainRestoreSavedStateLabel &&
4914
        driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1)
4915 4916 4917 4918
        goto endjob;

    ret = 0;

4919
    /* Shut it down */
4920
    qemudShutdownVMDaemon(driver, vm);
4921 4922 4923
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
4924
    if (!vm->persistent) {
4925 4926 4927
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
4928 4929
        vm = NULL;
    }
4930

4931
endjob:
4932 4933 4934 4935 4936 4937 4938 4939 4940 4941
    if (ret != 0 && header.was_running) {
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        rc = qemuMonitorStartCPUs(priv->mon, dom->conn);
        qemuDomainObjExitMonitorWithDriver(driver, vm);
        if (rc < 0)
            VIR_WARN0("Unable to resume guest CPUs after save failure");
        else
            vm->state = VIR_DOMAIN_RUNNING;
    }

4942 4943
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
4944
            vm = NULL;
4945

4946 4947 4948 4949
cleanup:
    VIR_FREE(xml);
    if (ret != 0)
        unlink(path);
4950 4951
    if (vm)
        virDomainObjUnlock(vm);
4952 4953
    if (event)
        qemuDomainEventQueue(driver, event);
4954
    qemuDriverUnlock(driver);
4955
    return ret;
D
Daniel P. Berrange 已提交
4956 4957
}

4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134
static int qemudDomainSave(virDomainPtr dom, const char *path)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int compressed;

    /* Hm, is this safe against qemudReload? */
    if (driver->saveImageFormat == NULL)
        compressed = QEMUD_SAVE_FORMAT_RAW;
    else {
        compressed = qemudSaveCompressionTypeFromString(driver->saveImageFormat);
        if (compressed < 0) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Invalid save image format specified "
                                    "in configuration file"));
            return -1;
        }
    }

    return qemudDomainSaveFlag(dom, path, compressed);
}

static char *
qemuDomainManagedSavePath(struct qemud_driver *driver, virDomainObjPtr vm) {
    char *ret;

    if (virAsprintf(&ret, "%s/%s.save", driver->saveDir, vm->def->name) < 0) {
        virReportOOMError();
        return(NULL);
    }

    return(ret);
}

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

    if (flags != 0) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported flags (0x%x) passed to '%s'"),
                        flags, __FUNCTION__);
        return -1;
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto error;
    }

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

    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto error;

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

    /* FIXME: we should take the flags parameter, and use bits out
     * of there to control whether we are compressing or not
     */
    compressed = QEMUD_SAVE_FORMAT_RAW;

    /* we have to drop our locks here because qemudDomainSaveFlag is
     * going to pick them back up.  Unfortunately it opens a race window
     * between us dropping and qemudDomainSaveFlag picking it back up, but
     * if we want to allow other operations to be able to happen while
     * qemuDomainSaveFlag is running (possibly for a long time), I'm not
     * sure if there is a better solution
     */
    virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    ret = qemudDomainSaveFlag(dom, name, compressed);

cleanup:
    VIR_FREE(name);

    return ret;

error:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    goto cleanup;
}

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

    if (flags != 0) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported flags (0x%x) passed to '%s'"),
                        flags, __FUNCTION__);
        return -1;
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    ret = virFileExists(name);

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

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

    if (flags != 0) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported flags (0x%x) passed to '%s'"),
                        flags, __FUNCTION__);
        return -1;
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    ret = unlink(name);

cleanup:
    VIR_FREE(name);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
D
Daniel P. Berrange 已提交
5135

P
Paolo Bonzini 已提交
5136 5137 5138 5139 5140 5141
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;
5142
    int ret = -1, fd = -1;
5143
    virDomainEventPtr event = NULL;
5144 5145 5146 5147
    const char *args[] = {
        "cat",
        NULL,
    };
5148
    qemuDomainObjPrivatePtr priv;
P
Paolo Bonzini 已提交
5149 5150 5151 5152 5153 5154 5155

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

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5156 5157
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
5158 5159
        goto cleanup;
    }
5160
    priv = vm->privateData;
P
Paolo Bonzini 已提交
5161

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

D
Daniel P. Berrange 已提交
5165
    if (!virDomainObjIsActive(vm)) {
5166 5167
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
5168
        goto endjob;
P
Paolo Bonzini 已提交
5169 5170
    }

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

    if (close(fd) < 0) {
5179
        virReportSystemError(errno,
5180 5181 5182 5183 5184 5185 5186
                             _("unable to save file %s"),
                             path);
        goto endjob;
    }

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSavedStateLabel &&
5187
        driver->securityDriver->domainSetSavedStateLabel(vm, path) == -1)
5188 5189
        goto endjob;

P
Paolo Bonzini 已提交
5190 5191
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
P
Paolo Bonzini 已提交
5192 5193 5194
    resume = (vm->state == VIR_DOMAIN_RUNNING);

    /* Pause domain for non-live dump */
P
Paolo Bonzini 已提交
5195
    if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
5196 5197 5198
        qemuDomainObjEnterMonitor(vm);
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
            qemuDomainObjExitMonitor(vm);
5199
            goto endjob;
5200 5201
        }
        qemuDomainObjExitMonitor(vm);
P
Paolo Bonzini 已提交
5202 5203 5204
        paused = 1;
    }

5205
    qemuDomainObjEnterMonitor(vm);
5206
    ret = qemuMonitorMigrateToCommand(priv->mon, 1, args, path);
5207
    qemuDomainObjExitMonitor(vm);
5208 5209 5210 5211 5212 5213 5214 5215 5216 5217

    if (ret < 0)
        goto endjob;

    ret = qemuDomainWaitForMigrationComplete(driver, vm);

    if (ret < 0)
        goto endjob;

    paused = 1;
5218 5219 5220

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSavedStateLabel &&
5221
        driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1)
5222 5223 5224
        goto endjob;

endjob:
5225
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
5226
        qemudShutdownVMDaemon(driver, vm);
5227 5228 5229 5230 5231
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
5232 5233 5234
    /* 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.  */
5235
    else if (resume && paused) {
5236
        qemuDomainObjEnterMonitor(vm);
5237
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
5238
            if (virGetLastError() == NULL)
5239 5240
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
5241
        }
5242
        qemuDomainObjExitMonitor(vm);
P
Paolo Bonzini 已提交
5243
    }
5244

5245 5246
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5247
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
5248 5249 5250 5251
        virDomainRemoveInactive(&driver->domains,
                                vm);
        vm = NULL;
    }
5252 5253

cleanup:
5254 5255
    if (ret != 0)
        unlink(path);
P
Paolo Bonzini 已提交
5256 5257
    if (vm)
        virDomainObjUnlock(vm);
5258 5259
    if (event)
        qemuDomainEventQueue(driver, event);
5260
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
5261 5262 5263 5264
    return ret;
}


5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276
static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int i, rc;
    int ret = -1;

    /* We need different branches here, because we want to offline
     * in reverse order to onlining, so any partial fail leaves us in a
     * reasonably sensible state */
    if (nvcpus > vm->def->vcpus) {
        for (i = vm->def->vcpus ; i < nvcpus ; i++) {
            /* Online new CPU */
5277
            qemuDomainObjEnterMonitor(vm);
5278
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
5279
            qemuDomainObjExitMonitor(vm);
5280 5281 5282 5283 5284 5285 5286 5287 5288 5289
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

            vm->def->vcpus++;
        }
    } else {
        for (i = vm->def->vcpus - 1 ; i >= nvcpus ; i--) {
            /* Offline old CPU */
5290
            qemuDomainObjEnterMonitor(vm);
5291
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
5292
            qemuDomainObjExitMonitor(vm);
5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

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

    ret = 0;

cleanup:
    return ret;

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


static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) {
5315 5316
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5317 5318
    const char * type;
    int max;
5319
    int ret = -1;
5320

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

5325 5326 5327
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

5328
    if (!vm) {
5329 5330
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5331 5332
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5333
        goto endjob;
5334 5335
    }

5336 5337 5338
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
5339
        goto endjob;
5340 5341
    }

5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
        goto endjob;
    }

    if ((max = qemudGetMaxVCPUs(NULL, type)) < 0) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("could not determine max vcpus for the domain"));
        goto endjob;
    }

    if (nvcpus > max) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("requested vcpus is greater than max allowable"
                          " vcpus for the domain: %d > %d"), nvcpus, max);
        goto endjob;
    }

    ret = qemudDomainHotplugVcpus(vm, nvcpus);

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

5368
cleanup:
5369 5370
    if (vm)
        virDomainObjUnlock(vm);
5371
    return ret;
5372 5373
}

5374 5375 5376 5377 5378 5379

static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
5380 5381
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5382
    int maxcpu, hostcpus;
5383
    virNodeInfo nodeinfo;
5384
    int ret = -1;
5385
    qemuDomainObjPrivatePtr priv;
5386

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

5391 5392 5393
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5394 5395
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5396 5397 5398
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
5399
    if (!virDomainObjIsActive(vm)) {
5400 5401
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",_("cannot pin vcpus on an inactive domain"));
5402
        goto cleanup;
5403 5404
    }

5405 5406 5407
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
5408 5409 5410
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("vcpu number out of range %d > %d"),
                        vcpu, priv->nvcpupids);
5411
        goto cleanup;
5412 5413
    }

5414
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
5415
        goto cleanup;
5416

5417
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
5418
    maxcpu = maplen * 8;
5419 5420
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
5421

5422 5423
    if (priv->vcpupids != NULL) {
        if (virProcessInfoSetAffinity(priv->vcpupids[vcpu],
5424
                                      cpumap, maplen, maxcpu) < 0)
5425
            goto cleanup;
5426
    } else {
5427 5428
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cpu affinity is not supported"));
5429
        goto cleanup;
5430
    }
5431
    ret = 0;
5432

5433
cleanup:
5434 5435
    if (vm)
        virDomainObjUnlock(vm);
5436
    return ret;
5437 5438 5439 5440 5441 5442 5443 5444
}

static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
5445 5446
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5447
    virNodeInfo nodeinfo;
5448
    int i, v, maxcpu, hostcpus;
5449
    int ret = -1;
5450
    qemuDomainObjPrivatePtr priv;
5451

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

5456 5457 5458
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5459 5460
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5461 5462 5463
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
5464
    if (!virDomainObjIsActive(vm)) {
5465 5466 5467
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",
                        _("cannot list vcpu pinning for an inactive domain"));
5468
        goto cleanup;
5469 5470
    }

5471 5472
    priv = vm->privateData;

5473
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
5474
        goto cleanup;
5475

5476
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
5477
    maxcpu = maplen * 8;
5478 5479
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
5480 5481

    /* Clamp to actual number of vcpus */
5482 5483
    if (maxinfo > priv->nvcpupids)
        maxinfo = priv->nvcpupids;
5484

5485 5486 5487 5488 5489 5490
    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;
5491

5492
                if (priv->vcpupids != NULL &&
5493 5494 5495
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
                                        vm->pid,
5496
                                        priv->vcpupids[i]) < 0) {
5497
                    virReportSystemError(errno, "%s",
5498 5499 5500
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
5501
            }
5502 5503
        }

5504 5505
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
5506
            if (priv->vcpupids != NULL) {
5507 5508 5509
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);

5510
                    if (virProcessInfoGetAffinity(priv->vcpupids[v],
5511
                                                  cpumap, maplen, maxcpu) < 0)
5512
                        goto cleanup;
5513
                }
5514
            } else {
5515 5516
                qemuReportError(VIR_ERR_NO_SUPPORT,
                                "%s", _("cpu affinity is not available"));
5517
                goto cleanup;
5518 5519 5520
            }
        }
    }
5521
    ret = maxinfo;
5522

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


5530
static int qemudDomainGetMaxVcpus(virDomainPtr dom) {
5531 5532
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5533
    const char *type;
5534
    int ret = -1;
5535

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

5540
    if (!vm) {
5541 5542
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5543 5544
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5545
        goto cleanup;
5546 5547
    }

5548
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
5549 5550 5551
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
5552
        goto cleanup;
5553 5554
    }

5555
    ret = qemudGetMaxVCPUs(NULL, type);
5556

5557
cleanup:
5558 5559
    if (vm)
        virDomainObjUnlock(vm);
5560 5561 5562
    return ret;
}

5563 5564 5565 5566 5567 5568 5569 5570 5571
static int qemudDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

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

5572 5573
    memset(seclabel, 0, sizeof(*seclabel));

5574 5575 5576
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5577 5578
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5579 5580 5581
        goto cleanup;
    }

5582
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
5583 5584 5585
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602
        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 已提交
5603
    if (virDomainObjIsActive(vm)) {
5604
        if (driver->securityDriver && driver->securityDriver->domainGetSecurityProcessLabel) {
5605
            if (driver->securityDriver->domainGetSecurityProcessLabel(vm, seclabel) == -1) {
5606 5607
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Failed to get security label"));
5608 5609 5610 5611 5612 5613 5614 5615 5616 5617
                goto cleanup;
            }
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
5618
    qemuDriverUnlock(driver);
5619 5620 5621
    return ret;
}

5622 5623
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
5624 5625 5626
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
5627
    int ret = 0;
5628

5629
    qemuDriverLock(driver);
5630
    if (!driver->securityPrimaryDriver) {
5631
        memset(secmodel, 0, sizeof (*secmodel));
5632 5633
        goto cleanup;
    }
5634

5635 5636
    p = driver->caps->host.secModel.model;
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
5637 5638 5639
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security model string exceeds max %d bytes"),
                        VIR_SECURITY_MODEL_BUFLEN-1);
5640 5641
        ret = -1;
        goto cleanup;
5642 5643 5644 5645 5646
    }
    strcpy(secmodel->model, p);

    p = driver->caps->host.secModel.doi;
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
5647 5648 5649
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security DOI string exceeds max %d bytes"),
                        VIR_SECURITY_DOI_BUFLEN-1);
5650 5651
        ret = -1;
        goto cleanup;
5652 5653
    }
    strcpy(secmodel->doi, p);
5654 5655 5656 5657

cleanup:
    qemuDriverUnlock(driver);
    return ret;
5658 5659
}

5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791
/* qemudOpenAsUID() - pipe/fork/setuid/open a file, and return the
   pipe fd to caller, so that it can read from the file. Also return
   the pid of the child process, so the caller can wait for it to exit
   after it's finished reading (to avoid a zombie, if nothing
   else). */

static int qemudOpenAsUID(const char *path, uid_t uid, pid_t *child_pid) {
    int pipefd[2];
    int fd = -1;

    *child_pid = -1;

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

    int forkRet = virFork(child_pid);

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

    if (*child_pid > 0) {

        /* parent */

        /* parent doesn't need the write side of the pipe */
        close(pipefd[1]);
        pipefd[1] = -1;

        if (forkRet < 0) {
            virReportSystemError(errno,
                                 _("failed in parent after forking child to read '%s'"),
                                 path);
            goto parent_cleanup;
        }
        /* caller gets the read side of the pipe */
        fd = pipefd[0];
        pipefd[0] = -1;
parent_cleanup:
        if (pipefd[0] != -1)
            close(pipefd[0]);
        if (pipefd[1] != -1)
            close(pipefd[1]);
        if ((fd < 0) && (*child_pid > 0)) {
            /* a child process was started and subsequently an error
               occurred in the parent, so we need to wait for it to
               exit, but its status is inconsequential. */
            while ((waitpid(*child_pid, NULL, 0) == -1)
                   && (errno == EINTR)) {
                /* empty */
            }
            *child_pid = -1;
        }
        return fd;
    }

    /* child */

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

    /* child doesn't need the read side of the pipe */
    close(pipefd[0]);

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

    if (setuid(uid) != 0) {
        exit_code = errno;
        virReportSystemError(errno,
                             _("cannot setuid(%d) to read '%s'"),
                             uid, path);
        goto child_cleanup;
    }
    if ((fd = open(path, O_RDONLY)) < 0) {
        exit_code = errno;
        virReportSystemError(errno,
                             _("cannot open '%s' as uid %d"),
                             path, uid);
        goto child_cleanup;
    }
    if (VIR_ALLOC_N(buf, bufsize) < 0) {
        exit_code = ENOMEM;
        virReportOOMError();
        goto child_cleanup;
    }

    /* read from fd and write to pipefd[1] until EOF */
    do {
        if ((bytesread = saferead(fd, buf, bufsize)) < 0) {
            exit_code = errno;
            virReportSystemError(errno,
                                 _("child failed reading from '%s'"),
                                 path);
            goto child_cleanup;
        }
        if (safewrite(pipefd[1], buf, bytesread) != bytesread) {
            exit_code = errno;
            virReportSystemError(errno, "%s",
                                 _("child failed writing to pipe"));
            goto child_cleanup;
        }
    } while (bytesread > 0);
    exit_code = 0;

child_cleanup:
    VIR_FREE(buf);
    if (fd != -1)
        close(fd);
    if (pipefd[1] != -1)
        close(pipefd[1]);
    _exit(exit_code);
}

5792
/* TODO: check seclabel restore */
5793
static int qemudDomainRestore(virConnectPtr conn,
5794 5795 5796
                              const char *path) {
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
5797
    virDomainObjPtr vm = NULL;
5798
    int fd = -1;
5799
    pid_t read_pid = -1;
5800 5801
    int ret = -1;
    char *xml = NULL;
5802
    struct qemud_save_header header;
5803
    virDomainEventPtr event = NULL;
5804 5805 5806
    int intermediatefd = -1;
    pid_t intermediate_pid = -1;
    int childstat;
5807

5808
    qemuDriverLock(driver);
5809 5810
    /* Verify the header and read the XML */
    if ((fd = open(path, O_RDONLY)) < 0) {
5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824
        if ((driver->user == 0) || (getuid() != 0)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("cannot read domain image"));
            goto cleanup;
        }

        /* Opening as root failed, but qemu runs as a different user
           that might have better luck. Create a pipe, then fork a
           child process to run as the qemu user, which will hopefully
           have the necessary authority to read the file. */
        if ((fd = qemudOpenAsUID(path, driver->user, &read_pid)) < 0) {
            /* error already reported */
            goto cleanup;
        }
5825 5826 5827
    }

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
5828 5829
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read qemu header"));
5830
        goto cleanup;
5831 5832 5833
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
5834 5835
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("image magic is incorrect"));
5836
        goto cleanup;
5837 5838 5839
    }

    if (header.version > QEMUD_SAVE_VERSION) {
5840 5841 5842
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("image version is not supported (%d > %d)"),
                        header.version, QEMUD_SAVE_VERSION);
5843
        goto cleanup;
5844 5845
    }

5846 5847 5848
    if (header.xml_len <= 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("invalid XML length: %d"), header.xml_len);
5849
        goto cleanup;
5850 5851
    }

5852 5853 5854 5855 5856 5857
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
5858 5859
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read XML"));
5860
        goto cleanup;
5861 5862 5863
    }

    /* Create a domain from this XML */
5864
    if (!(def = virDomainDefParseString(driver->caps, xml,
5865
                                        VIR_DOMAIN_XML_INACTIVE))) {
5866 5867
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
5868
        goto cleanup;
5869 5870
    }

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

5874
    if (!(vm = virDomainAssignDef(driver->caps,
5875
                                  &driver->domains,
5876
                                  def, true))) {
5877 5878
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to assign new VM"));
5879
        goto cleanup;
5880
    }
5881
    def = NULL;
5882

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

5886 5887
    if (header.version == 2) {
        const char *intermediate_argv[3] = { NULL, "-dc", NULL };
5888 5889
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
        if (prog == NULL) {
5890 5891 5892
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("Invalid compressed save format %d"),
                            header.compressed);
5893
            goto endjob;
5894
        }
5895

5896
        if (header.compressed != QEMUD_SAVE_FORMAT_RAW) {
5897
            intermediate_argv[0] = prog;
5898 5899
            intermediatefd = fd;
            fd = -1;
5900
            if (virExec(intermediate_argv, NULL, NULL,
5901
                        &intermediate_pid, intermediatefd, &fd, NULL, 0) < 0) {
5902 5903 5904
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Failed to start decompression binary %s"),
                                intermediate_argv[0]);
5905
                goto endjob;
5906 5907 5908
            }
        }
    }
5909
    /* Set the migration source and start it up. */
5910
    ret = qemudStartVMDaemon(conn, driver, vm, "stdio", fd);
5911 5912 5913 5914 5915 5916 5917
    if (intermediate_pid != -1) {
        /* Wait for intermediate process to exit */
        while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
               errno == EINTR);
    }
    if (intermediatefd != -1)
        close(intermediatefd);
5918
    close(fd);
5919
    fd = -1;
5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948
    if (read_pid != -1) {
        int wait_ret;
        int status;
        /* reap the process that read the file */
        while (((wait_ret = waitpid(read_pid, &status, 0)) == -1)
               && (errno == EINTR)) {
            /* empty */
        }
        read_pid = -1;
        if (wait_ret == -1) {
            virReportSystemError(errno,
                                 _("failed to wait for process reading '%s'"),
                                 path);
            ret = -1;
        } else if (!WIFEXITED(status)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("child process exited abnormally reading '%s'"),
                            path);
            ret = -1;
        } else {
            int exit_status = WEXITSTATUS(status);
            if (exit_status != 0) {
                virReportSystemError(exit_status,
                                     _("child process returned error reading '%s'"),
                                     path);
                ret = -1;
            }
        }
    }
5949
    if (ret < 0) {
5950
        if (!vm->persistent) {
5951 5952 5953
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains,
                                        vm);
5954 5955
            vm = NULL;
        }
5956
        goto endjob;
5957 5958
    }

5959 5960 5961
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
5962

5963 5964
    /* If it was running before, resume it now. */
    if (header.was_running) {
5965
        qemuDomainObjPrivatePtr priv = vm->privateData;
5966
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5967
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
5968
            if (virGetLastError() == NULL)
5969 5970
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("failed to resume domain"));
5971 5972
            qemuDomainObjExitMonitorWithDriver(driver,vm);
            goto endjob;
5973
        }
5974
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5975
        vm->state = VIR_DOMAIN_RUNNING;
5976
        virDomainSaveStatus(driver->caps, driver->stateDir, vm);
5977
    }
5978
    ret = 0;
5979

5980
endjob:
5981 5982 5983
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5984

5985 5986 5987 5988 5989
cleanup:
    virDomainDefFree(def);
    VIR_FREE(xml);
    if (fd != -1)
        close(fd);
5990 5991 5992 5993 5994 5995 5996
    if (read_pid != 0) {
        /* reap the process that read the file */
        while ((waitpid(read_pid, NULL, 0) == -1)
               && (errno == EINTR)) {
            /* empty */
        }
    }
5997 5998
    if (vm)
        virDomainObjUnlock(vm);
5999 6000
    if (event)
        qemuDomainEventQueue(driver, event);
6001
    qemuDriverUnlock(driver);
6002
    return ret;
D
Daniel P. Berrange 已提交
6003 6004 6005
}


6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043
static char *qemudVMDumpXML(struct qemud_driver *driver,
                            virDomainObjPtr vm,
                            int flags)
{
    char *ret = NULL;
    virCPUDefPtr cpu = NULL;
    virDomainDefPtr def;
    virCPUDefPtr def_cpu;

    if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef)
        def = vm->newDef;
    else
        def = vm->def;
    def_cpu = def->cpu;

    /* Update guest CPU requirements according to host CPU */
    if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) && def_cpu && def_cpu->model) {
        if (!driver->caps || !driver->caps->host.cpu) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("cannot get host CPU capabilities"));
            goto cleanup;
        }

        if (!(cpu = virCPUDefCopy(def_cpu))
            || cpuUpdate(cpu, driver->caps->host.cpu))
            goto cleanup;
        def->cpu = cpu;
    }

    ret = virDomainDefFormat(def, flags);

cleanup:
    def->cpu = def_cpu;
    virCPUDefFree(cpu);
    return ret;
}


6044
static char *qemudDomainDumpXML(virDomainPtr dom,
6045
                                int flags) {
6046 6047 6048
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
6049 6050
    unsigned long balloon;
    int err;
6051

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

D
Daniel P. Berrange 已提交
6055
    if (!vm) {
6056 6057
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6058 6059
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6060
        goto cleanup;
D
Daniel P. Berrange 已提交
6061 6062
    }

6063
    /* Refresh current memory based on balloon info */
D
Daniel P. Berrange 已提交
6064
    if (virDomainObjIsActive(vm)) {
6065
        qemuDomainObjPrivatePtr priv = vm->privateData;
6066 6067 6068
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
        if (!priv->jobActive) {
6069
            if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
6070 6071
                goto cleanup;

6072
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
6073
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
6074
            qemuDomainObjExitMonitorWithDriver(driver, vm);
6075 6076 6077 6078
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
                goto cleanup;
            }
6079 6080 6081 6082 6083 6084
            if (err < 0)
                goto cleanup;
            if (err > 0)
                vm->def->memory = balloon;
            /* err == 0 indicates no balloon support, so ignore it */
        }
6085
    }
6086

6087
    ret = qemudVMDumpXML(driver, vm, flags);
6088 6089

cleanup:
6090 6091
    if (vm)
        virDomainObjUnlock(vm);
6092
    qemuDriverUnlock(driver);
6093
    return ret;
D
Daniel P. Berrange 已提交
6094 6095 6096
}


6097 6098 6099 6100
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
                                     unsigned int flags ATTRIBUTE_UNUSED) {
6101
    struct qemud_driver *driver = conn->privateData;
6102 6103 6104 6105
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
6106 6107
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
6108 6109 6110
        goto cleanup;
    }

6111
    qemuDriverLock(driver);
6112
    def = qemuParseCommandLineString(driver->caps, config);
6113
    qemuDriverUnlock(driver);
6114 6115 6116
    if (!def)
        goto cleanup;

6117
    xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
6118 6119 6120 6121 6122 6123

cleanup:
    virDomainDefFree(def);
    return xml;
}

6124 6125 6126 6127 6128 6129
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;
6130
    virDomainChrDef monConfig;
6131
    const char *emulator;
6132
    unsigned long long qemuCmdFlags;
6133 6134 6135 6136 6137 6138 6139 6140
    struct stat sb;
    const char **retargv = NULL;
    const char **retenv = NULL;
    const char **tmp;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *ret = NULL;
    int i;

6141 6142
    qemuDriverLock(driver);

6143
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
6144 6145
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
6146 6147 6148
        goto cleanup;
    }

6149
    def = virDomainDefParseString(driver->caps, xmlData, 0);
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
    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) {
6194
        virReportSystemError(errno,
6195 6196 6197 6198 6199 6200 6201 6202
                             _("Cannot find QEMU binary %s"),
                             emulator);
        goto cleanup;
    }

    if (qemudExtractVersionInfo(emulator,
                                NULL,
                                &qemuCmdFlags) < 0) {
6203 6204 6205
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot determine QEMU argv syntax %s"),
                        emulator);
6206 6207 6208
        goto cleanup;
    }

6209
    if (qemuPrepareMonitorChr(driver, &monConfig, def->name) < 0)
6210
        goto cleanup;
6211 6212

    if (qemudBuildCommandLine(conn, driver, def,
D
Daniel P. Berrange 已提交
6213
                              &monConfig, 0, qemuCmdFlags,
6214 6215
                              &retargv, &retenv,
                              NULL, NULL, /* Don't want it to create TAP devices */
C
Chris Lalancette 已提交
6216
                              NULL, NULL) < 0) {
6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232
        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++;
    }

6233 6234
    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
6235
        virReportOOMError();
6236
        goto cleanup;
6237
    }
6238 6239 6240 6241

    ret = virBufferContentAndReset(&buf);

cleanup:
6242
    qemuDriverUnlock(driver);
6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255
    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;
}


6256
static int qemudListDefinedDomains(virConnectPtr conn,
6257
                            char **const names, int nnames) {
6258
    struct qemud_driver *driver = conn->privateData;
6259
    int n;
6260

6261
    qemuDriverLock(driver);
6262
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
6263
    qemuDriverUnlock(driver);
6264
    return n;
D
Daniel P. Berrange 已提交
6265 6266
}

6267
static int qemudNumDefinedDomains(virConnectPtr conn) {
6268
    struct qemud_driver *driver = conn->privateData;
6269
    int n;
6270

6271
    qemuDriverLock(driver);
6272
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
6273
    qemuDriverUnlock(driver);
6274

6275
    return n;
D
Daniel P. Berrange 已提交
6276 6277 6278
}


6279
static int qemudDomainStart(virDomainPtr dom) {
6280 6281 6282
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
6283
    virDomainEventPtr event = NULL;
6284
    char *managed_save = NULL;
6285

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

6289
    if (!vm) {
6290 6291
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6292 6293
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6294
        goto cleanup;
6295 6296
    }

6297 6298 6299 6300
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
6301 6302
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is already running"));
6303 6304 6305
        goto endjob;
    }

6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334
    /*
     * If there is a managed saved state restore it instead of starting
     * from scratch. In any case the old state is removed.
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
    if ((managed_save) && (virFileExists(managed_save))) {
        /*
         * We should still have a reference left to vm but
         * one should check for 0 anyway
         */
        if (qemuDomainObjEndJob(vm) == 0)
            vm = NULL;
        virDomainObjUnlock(vm);
        qemuDriverUnlock(driver);
        ret = qemudDomainRestore(dom->conn, managed_save);

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

        if (ret == 0) {
            /* qemudDomainRestore should have sent the Started/Restore event */
            VIR_FREE(managed_save);
            return(ret);
        }
        qemuDriverLock(driver);
        virDomainObjLock(vm);
    }

6335
    ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL, -1);
6336
    if (ret != -1)
6337 6338 6339
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
6340

6341
endjob:
6342 6343
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
6344

6345
cleanup:
6346
    VIR_FREE(managed_save);
6347 6348
    if (vm)
        virDomainObjUnlock(vm);
6349
    if (event)
6350
        qemuDomainEventQueue(driver, event);
6351
    qemuDriverUnlock(driver);
6352
    return ret;
D
Daniel P. Berrange 已提交
6353 6354
}

6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369
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;

6370
        if (STRNEQ(def->os.machine, machine->name))
6371 6372 6373
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
6374
            virReportOOMError();
6375 6376 6377 6378 6379 6380 6381 6382 6383
            return -1;
        }

        break;
    }

    return 0;
}

6384 6385 6386 6387 6388 6389 6390
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
    int i, nmachines = 0;

    if (qemudProbeMachineTypes(def->emulator, &machines, &nmachines) < 0) {
6391
        virReportOOMError();
6392 6393 6394 6395 6396 6397 6398
        return -1;
    }

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

6399
        if (STRNEQ(def->os.machine, machines[i]->name))
6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

6412 6413
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
6414 6415 6416 6417 6418 6419
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
6420
        virCapsGuestDomainInfoPtr info;
6421 6422 6423
        int j;

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

6426 6427 6428 6429 6430 6431 6432 6433 6434
            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;
6435 6436
        }

6437 6438 6439 6440
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
6441 6442 6443 6444
                return -1;
            goto out;
        }
    }
6445 6446 6447 6448

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

6449 6450 6451 6452 6453 6454 6455
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
6456

6457
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
6458
    struct qemud_driver *driver = conn->privateData;
6459
    virDomainDefPtr def;
6460
    virDomainObjPtr vm = NULL;
6461
    virDomainPtr dom = NULL;
6462
    virDomainEventPtr event = NULL;
6463
    int dupVM;
6464

6465
    qemuDriverLock(driver);
6466
    if (!(def = virDomainDefParseString(driver->caps, xml,
6467
                                        VIR_DOMAIN_XML_INACTIVE)))
6468
        goto cleanup;
6469

6470
    if (virSecurityDriverVerify(def) < 0)
6471 6472
        goto cleanup;

6473 6474
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
6475

6476
    if (qemudCanonicalizeMachine(driver, def) < 0)
6477 6478
        goto cleanup;

6479 6480 6481
    if (qemuAssignPCIAddresses(def) < 0)
        goto cleanup;

6482
    if (!(vm = virDomainAssignDef(driver->caps,
6483
                                  &driver->domains,
6484
                                  def, false))) {
6485
        goto cleanup;
6486
    }
6487
    def = NULL;
6488
    vm->persistent = 1;
6489

6490
    if (virDomainSaveConfig(driver->configDir,
6491
                            vm->newDef ? vm->newDef : vm->def) < 0) {
6492 6493
        virDomainRemoveInactive(&driver->domains,
                                vm);
6494
        vm = NULL;
6495
        goto cleanup;
6496 6497
    }

6498 6499
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
6500
                                     !dupVM ?
6501 6502
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
6503

6504
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
6505
    if (dom) dom->id = vm->def->id;
6506 6507

cleanup:
6508
    virDomainDefFree(def);
6509 6510
    if (vm)
        virDomainObjUnlock(vm);
6511 6512
    if (event)
        qemuDomainEventQueue(driver, event);
6513
    qemuDriverUnlock(driver);
6514
    return dom;
D
Daniel P. Berrange 已提交
6515 6516
}

6517
static int qemudDomainUndefine(virDomainPtr dom) {
6518 6519
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6520
    virDomainEventPtr event = NULL;
6521
    int ret = -1;
D
Daniel P. Berrange 已提交
6522

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

D
Daniel P. Berrange 已提交
6526
    if (!vm) {
6527 6528
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6529 6530
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6531
        goto cleanup;
D
Daniel P. Berrange 已提交
6532 6533
    }

D
Daniel P. Berrange 已提交
6534
    if (virDomainObjIsActive(vm)) {
6535 6536
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot delete active domain"));
6537
        goto cleanup;
D
Daniel P. Berrange 已提交
6538 6539
    }

6540
    if (!vm->persistent) {
6541 6542
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot undefine transient domain"));
6543
        goto cleanup;
6544 6545
    }

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

6549 6550 6551
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
6552

6553 6554
    virDomainRemoveInactive(&driver->domains,
                            vm);
6555
    vm = NULL;
6556
    ret = 0;
D
Daniel P. Berrange 已提交
6557

6558
cleanup:
6559 6560
    if (vm)
        virDomainObjUnlock(vm);
6561 6562
    if (event)
        qemuDomainEventQueue(driver, event);
6563
    qemuDriverUnlock(driver);
6564
    return ret;
D
Daniel P. Berrange 已提交
6565 6566
}

6567

6568
static int qemudDomainChangeEjectableMedia(struct qemud_driver *driver,
6569
                                           virDomainObjPtr vm,
6570
                                           virDomainDiskDefPtr disk)
6571
{
6572
    virDomainDiskDefPtr origdisk = NULL;
6573
    int i;
6574
    int ret;
6575

6576
    origdisk = NULL;
6577
    for (i = 0 ; i < vm->def->ndisks ; i++) {
6578 6579
        if (vm->def->disks[i]->bus == disk->bus &&
            STREQ(vm->def->disks[i]->dst, disk->dst)) {
6580
            origdisk = vm->def->disks[i];
6581
            break;
6582
        }
6583 6584 6585
    }

    if (!origdisk) {
6586 6587 6588 6589
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No device with bus '%s' and target '%s'"),
                        virDomainDiskBusTypeToString(disk->bus),
                        disk->dst);
6590 6591 6592
        return -1;
    }

6593
    if (!origdisk->info.alias) {
6594 6595
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), origdisk->dst);
6596 6597
        return -1;
    }
6598

6599 6600
    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
6601 6602 6603
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Removable media not supported for %s device"),
                        virDomainDiskDeviceTypeToString(disk->device));
6604
        return -1;
6605
    }
6606

6607 6608
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
6609
        driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0)
6610 6611
        return -1;

6612
    qemuDomainObjPrivatePtr priv = vm->privateData;
6613
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6614
    if (disk->src) {
6615
        const char *format = NULL;
6616 6617 6618
        if (disk->type != VIR_DOMAIN_DISK_TYPE_DIR) {
            if (disk->driverType)
                format = disk->driverType;
6619 6620 6621
            else if (origdisk->driverType)
                format = origdisk->driverType;
        }
6622 6623
        ret = qemuMonitorChangeMedia(priv->mon,
                                     origdisk->info.alias,
6624
                                     disk->src, format);
6625
    } else {
6626
        ret = qemuMonitorEjectMedia(priv->mon, origdisk->info.alias);
6627
    }
6628
    qemuDomainObjExitMonitorWithDriver(driver, vm);
6629

6630 6631 6632 6633 6634
    if (ret < 0)
        goto error;

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
6635
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, origdisk) < 0)
6636 6637 6638
        VIR_WARN("Unable to restore security label on ejected image %s", origdisk->src);

    VIR_FREE(origdisk->src);
6639 6640 6641 6642 6643
    origdisk->src = disk->src;
    disk->src = NULL;
    origdisk->type = disk->type;

    virDomainDiskDefFree(disk);
6644

6645
    return ret;
6646 6647 6648 6649

error:
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
6650
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0)
6651
        VIR_WARN("Unable to restore security label on new media %s", disk->src);
6652
    return -1;
6653 6654
}

6655

6656
static int qemudDomainAttachPciDiskDevice(struct qemud_driver *driver,
6657
                                          virDomainObjPtr vm,
6658 6659
                                          virDomainDiskDefPtr disk,
                                          int qemuCmdFlags)
6660
{
6661
    int i, ret;
6662
    const char* type = virDomainDiskBusTypeToString(disk->bus);
6663
    qemuDomainObjPrivatePtr priv = vm->privateData;
6664 6665
    char *devstr = NULL;
    char *drivestr = NULL;
6666 6667

    for (i = 0 ; i < vm->def->ndisks ; i++) {
6668
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
6669 6670
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
6671 6672 6673 6674
            return -1;
        }
    }

6675 6676
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
6677
        driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0)
6678 6679
        return -1;

6680
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
6681 6682
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
            goto error;
6683 6684
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
6685

6686 6687 6688
        if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
            goto error;

6689
        if (!(devstr = qemuBuildDriveDevStr(disk)))
6690 6691 6692
            goto error;
    }

6693
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
6694
        virReportOOMError();
6695
        goto error;
6696 6697
    }

6698
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDrive(priv->mon, drivestr);
        if (ret == 0)
            qemuMonitorAddDevice(priv->mon, devstr);
            /* XXX remove the drive upon fail */
    } else {
        virDomainDevicePCIAddress guestAddr;
        ret = qemuMonitorAddPCIDisk(priv->mon,
                                    disk->src,
                                    type,
                                    &guestAddr);
        if (ret == 0) {
            disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
            memcpy(&disk->info.addr.pci, &guestAddr, sizeof(guestAddr));
        }
    }
6715
    qemuDomainObjExitMonitorWithDriver(driver, vm);
6716

6717 6718
    if (ret < 0)
        goto error;
6719

6720
    virDomainDiskInsertPreAlloced(vm->def, disk);
6721

6722 6723 6724
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

6725 6726 6727
    return 0;

error:
6728 6729 6730
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

6731 6732 6733 6734 6735
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &disk->info) < 0)
        VIR_WARN("Unable to release PCI address on %s", disk->src);

6736 6737
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
6738
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0)
6739
        VIR_WARN("Unable to restore security label on %s", disk->src);
6740 6741

    return -1;
6742
}
6743

6744

6745
static int qemudDomainAttachPciControllerDevice(struct qemud_driver *driver,
6746
                                                virDomainObjPtr vm,
6747 6748
                                                virDomainControllerDefPtr controller,
                                                int qemuCmdFlags)
6749
{
6750 6751
    int i;
    int ret = -1;
6752
    const char* type = virDomainControllerTypeToString(controller->type);
6753
    char *devstr = NULL;
6754 6755 6756
    qemuDomainObjPrivatePtr priv = vm->privateData;

    for (i = 0 ; i < vm->def->ncontrollers ; i++) {
6757 6758
        if ((vm->def->controllers[i]->type == controller->type) &&
            (vm->def->controllers[i]->idx == controller->idx)) {
6759 6760 6761
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s:%d already exists"),
                            type, controller->idx);
6762 6763 6764 6765
            return -1;
        }
    }

6766 6767 6768 6769 6770 6771
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
            goto cleanup;
        if (qemuAssignDeviceControllerAlias(controller) < 0)
            goto cleanup;
    }
6772

6773
    if (!(devstr = qemuBuildControllerDevStr(controller))) {
6774
        virReportOOMError();
6775 6776 6777
        goto cleanup;
    }

6778
    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) {
6779
        virReportOOMError();
6780
        goto cleanup;
6781 6782 6783
    }

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6784 6785 6786 6787 6788 6789 6790
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    } else {
        ret = qemuMonitorAttachPCIDiskController(priv->mon,
                                                 type,
                                                 &controller->info.addr.pci);
    }
6791 6792 6793
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (ret == 0) {
6794 6795
        controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
        virDomainControllerInsertPreAlloced(vm->def, controller);
6796 6797
    }

6798
cleanup:
6799 6800 6801 6802 6803 6804
    if ((ret != 0) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &controller->info) < 0)
        VIR_WARN0("Unable to release PCI address on controller");

6805
    VIR_FREE(devstr);
6806 6807 6808
    return ret;
}

6809

6810
static virDomainControllerDefPtr
6811
qemuDomainFindOrCreateSCSIDiskController(struct qemud_driver *driver,
6812
                                         virDomainObjPtr vm,
6813 6814
                                         int controller,
                                         int qemuCmdFlags)
6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827
{
    int i;
    virDomainControllerDefPtr cont;
    for (i = 0 ; i < vm->def->ncontrollers ; i++) {
        cont = vm->def->controllers[i];

        if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
            continue;

        if (cont->idx == controller)
            return cont;
    }

W
Wolfgang Mauerer 已提交
6828
    /* No SCSI controller present, for backward compatibility we
6829 6830
     * now hotplug a controller */
    if (VIR_ALLOC(cont) < 0) {
6831
        virReportOOMError();
6832 6833 6834 6835 6836 6837
        return NULL;
    }
    cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
    cont->idx = 0;

    VIR_INFO0("No SCSI controller present, hotplugging one");
6838
    if (qemudDomainAttachPciControllerDevice(driver,
6839
                                             vm, cont, qemuCmdFlags) < 0) {
6840 6841 6842 6843 6844 6845
        VIR_FREE(cont);
        return NULL;
    }
    return cont;
}

6846

6847
static int qemudDomainAttachSCSIDisk(struct qemud_driver *driver,
6848
                                     virDomainObjPtr vm,
6849
                                     virDomainDiskDefPtr disk,
6850 6851 6852 6853 6854 6855
                                     int qemuCmdFlags)
{
    int i;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainControllerDefPtr cont;
    char *drivestr = NULL;
6856
    char *devstr = NULL;
6857 6858 6859
    int ret = -1;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
6860
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
6861 6862
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
6863
            return -1;
6864 6865 6866
        }
    }

6867 6868 6869

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
6870
        driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0)
6871 6872
        return -1;

6873
    /* We should have an address already, so make sure */
6874
    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
6875 6876 6877
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected disk address type %s"),
                        virDomainDeviceAddressTypeToString(disk->info.type));
6878
        goto error;
6879 6880
    }

6881 6882 6883
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
6884
        if (!(devstr = qemuBuildDriveDevStr(disk)))
6885 6886 6887 6888 6889 6890
            goto error;
    }

    if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
        goto error;

6891
    for (i = 0 ; i <= disk->info.addr.drive.controller ; i++) {
6892
        cont = qemuDomainFindOrCreateSCSIDiskController(driver, vm, i, qemuCmdFlags);
6893
        if (!cont)
6894
            goto error;
6895 6896 6897
    }

    if (cont->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
6898 6899
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("SCSI controller %d was missing its PCI address"), cont->idx);
6900
        goto error;
6901 6902 6903
    }

    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
6904
        virReportOOMError();
6905
        goto error;
6906 6907 6908
    }

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDrive(priv->mon,
                                  drivestr);
        if (ret == 0)
            ret = qemuMonitorAddDevice(priv->mon,
                                       devstr);
            /* XXX should call 'drive_del' on error but this does not exist yet */
    } else {
        virDomainDeviceDriveAddress driveAddr;
        ret = qemuMonitorAttachDrive(priv->mon,
                                     drivestr,
                                     &cont->info.addr.pci,
                                     &driveAddr);
        if (ret == 0) {
            /* XXX we should probably validate that the addr matches
             * our existing defined addr instead of overwriting */
            disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
            memcpy(&disk->info.addr.drive, &driveAddr, sizeof(driveAddr));
        }
    }
6929 6930
    qemuDomainObjExitMonitorWithDriver(driver, vm);

6931 6932
    if (ret < 0)
        goto error;
6933

6934
    virDomainDiskInsertPreAlloced(vm->def, disk);
6935 6936

    VIR_FREE(devstr);
6937
    VIR_FREE(drivestr);
6938 6939 6940 6941

    return 0;

error:
6942
    VIR_FREE(devstr);
6943
    VIR_FREE(drivestr);
6944

6945 6946
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
6947
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0)
6948
        VIR_WARN("Unable to restore security label on %s", disk->src);
6949 6950

    return -1;
6951 6952
}

6953

6954
static int qemudDomainAttachUsbMassstorageDevice(struct qemud_driver *driver,
6955
                                                 virDomainObjPtr vm,
6956 6957
                                                 virDomainDiskDefPtr disk,
                                                 int qemuCmdFlags)
6958
{
6959
    qemuDomainObjPrivatePtr priv = vm->privateData;
6960
    int i, ret;
6961 6962
    char *drivestr = NULL;
    char *devstr = NULL;
6963

6964
    for (i = 0 ; i < vm->def->ndisks ; i++) {
6965
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
6966 6967
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
6968 6969 6970 6971
            return -1;
        }
    }

6972 6973
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
6974
        driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0)
6975 6976
        return -1;

6977
    if (!disk->src) {
6978 6979
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("disk source path is missing"));
6980
        goto error;
6981 6982
    }

6983
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
6984 6985
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
6986 6987
        if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
            goto error;
6988
        if (!(devstr = qemuBuildDriveDevStr(disk)))
6989 6990 6991
            goto error;
    }

6992
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
6993
        virReportOOMError();
6994
        goto error;
6995 6996
    }

6997
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6998 6999 7000 7001 7002 7003 7004 7005 7006 7007
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDrive(priv->mon,
                                  drivestr);
        if (ret == 0)
            ret = qemuMonitorAddDevice(priv->mon,
                                       devstr);
            /* XXX should call 'drive_del' on error but this does not exist yet */
    } else {
        ret = qemuMonitorAddUSBDisk(priv->mon, disk->src);
    }
7008
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7009

7010 7011 7012
    if (ret < 0)
        goto error;

7013
    virDomainDiskInsertPreAlloced(vm->def, disk);
7014

7015 7016 7017
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7018 7019 7020
    return 0;

error:
7021 7022 7023
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7024 7025
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7026
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0)
7027
        VIR_WARN("Unable to restore security label on %s", disk->src);
7028 7029

    return -1;
7030 7031
}

7032

7033
/* XXX conn required for network -> bridge resolution */
M
Mark McLoughlin 已提交
7034
static int qemudDomainAttachNetDevice(virConnectPtr conn,
7035
                                      struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7036
                                      virDomainObjPtr vm,
7037
                                      virDomainNetDefPtr net,
7038
                                      unsigned long long qemuCmdFlags)
M
Mark McLoughlin 已提交
7039
{
7040
    qemuDomainObjPrivatePtr priv = vm->privateData;
7041
    char *tapfd_name = NULL;
7042
    int tapfd = -1;
7043
    char *nicstr = NULL;
7044
    char *netstr = NULL;
7045
    int ret = -1;
7046
    virDomainDevicePCIAddress guestAddr;
7047
    int vlan;
M
Mark McLoughlin 已提交
7048 7049

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
7050 7051
        qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                        _("installed qemu version does not support host_net_add"));
M
Mark McLoughlin 已提交
7052 7053 7054 7055 7056
        return -1;
    }

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
7057
        if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
7058 7059 7060 7061
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("network device type '%s' cannot be attached: "
                              "qemu is not using a unix socket monitor"),
                            virDomainNetTypeToString(net->type));
7062 7063 7064 7065 7066
            return -1;
        }

        if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
            return -1;
7067 7068 7069 7070 7071 7072 7073 7074 7075
    } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
        if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("network device type '%s' cannot be attached: "
                            "qemu is not using a unix socket monitor"),
                            virDomainNetTypeToString(net->type));
            return -1;
        }

S
Stefan Berger 已提交
7076
        if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
7077
                                           net->data.direct.linkdev,
7078 7079
                                           net->data.direct.mode,
                                           qemuCmdFlags)) < 0)
7080
            return -1;
M
Mark McLoughlin 已提交
7081 7082
    }

7083 7084
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
        goto no_memory;
M
Mark McLoughlin 已提交
7085

7086 7087 7088 7089 7090
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
            goto cleanup;
    }
M
Mark McLoughlin 已提交
7091

7092 7093 7094 7095
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
        goto cleanup;

7096
    vlan = qemuDomainNetVLAN(net);
M
Mark McLoughlin 已提交
7097

7098
    if (vlan < 0) {
7099 7100
        qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                        _("Unable to attach network devices without vlan"));
7101 7102 7103
        goto cleanup;
    }

7104
    if (tapfd != -1) {
7105
        if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0)
7106 7107
            goto no_memory;

7108
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7109
        if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0) {
7110
            qemuDomainObjExitMonitorWithDriver(driver, vm);
7111
            goto cleanup;
7112
        }
7113
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7114 7115
    }

7116
    /* FIXME - need to support vhost-net here (5th arg) */
7117
    if (!(netstr = qemuBuildHostNetStr(net, ' ',
7118
                                       vlan, tapfd_name, 0)))
7119
        goto try_tapfd_close;
M
Mark McLoughlin 已提交
7120

7121
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7122
    if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
7123
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7124
        goto try_tapfd_close;
7125
    }
7126
    qemuDomainObjExitMonitorWithDriver(driver, vm);
M
Mark McLoughlin 已提交
7127

7128 7129 7130
    if (tapfd != -1)
        close(tapfd);
    tapfd = -1;
M
Mark McLoughlin 已提交
7131

7132
    if (!(nicstr = qemuBuildNicStr(net, NULL, vlan)))
7133
        goto try_remove;
M
Mark McLoughlin 已提交
7134

7135
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7136
    if (qemuMonitorAddPCINetwork(priv->mon, nicstr,
7137
                                 &guestAddr) < 0) {
7138
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7139
        goto try_remove;
7140
    }
7141
    net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
7142
    memcpy(&net->info.addr.pci, &guestAddr, sizeof(guestAddr));
7143
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7144

7145
    ret = 0;
M
Mark McLoughlin 已提交
7146 7147 7148

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

7149
cleanup:
7150 7151 7152 7153 7154 7155
    if ((ret != 0) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &net->info) < 0)
        VIR_WARN0("Unable to release PCI address on NIC");

S
Stefan Berger 已提交
7156 7157
    qemuTearNWFilter(net);

7158 7159 7160 7161 7162
    VIR_FREE(nicstr);
    VIR_FREE(netstr);
    VIR_FREE(tapfd_name);
    if (tapfd != -1)
        close(tapfd);
7163

7164
    return ret;
7165

7166
try_remove:
7167
    if (vlan < 0) {
7168
        VIR_WARN0(_("Unable to remove network backend"));
7169 7170 7171 7172
    } else {
        char *hostnet_name;
        if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
            goto no_memory;
7173
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7174
        if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
7175
            VIR_WARN(_("Failed to remove network backend for vlan %d, net %s"),
7176
                     vlan, hostnet_name);
7177
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7178
        VIR_FREE(hostnet_name);
7179
    }
7180
    goto cleanup;
7181

7182
try_tapfd_close:
7183
    if (tapfd_name) {
7184
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7185
        if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
7186
            VIR_WARN(_("Failed to close tapfd with '%s'"), tapfd_name);
7187
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7188
    }
7189

7190 7191
    goto cleanup;

7192
no_memory:
7193
    virReportOOMError();
7194
    goto cleanup;
M
Mark McLoughlin 已提交
7195 7196
}

7197

7198
static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
7199
                                          virDomainObjPtr vm,
7200 7201
                                          virDomainHostdevDefPtr hostdev,
                                          int qemuCmdFlags)
7202
{
7203
    qemuDomainObjPrivatePtr priv = vm->privateData;
7204
    pciDevice *pci;
7205
    int ret;
7206
    virDomainDevicePCIAddress guestAddr;
7207
    char *devstr = NULL;
7208 7209

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

7214
    pci = pciGetDevice(hostdev->source.subsys.u.pci.domain,
7215 7216 7217
                       hostdev->source.subsys.u.pci.bus,
                       hostdev->source.subsys.u.pci.slot,
                       hostdev->source.subsys.u.pci.function);
7218
    if (!pci)
7219
        return -1;
7220

7221 7222 7223 7224
    if (!pciDeviceIsAssignable(pci, !driver->relaxedACS) ||
        (hostdev->managed && pciDettachDevice(pci) < 0) ||
        pciResetDevice(pci, driver->activePciHostdevs) < 0) {
        pciFreeDevice(pci);
7225 7226 7227
        return -1;
    }

7228 7229
    if (pciDeviceListAdd(driver->activePciHostdevs, pci) < 0) {
        pciFreeDevice(pci);
7230
        return -1;
7231 7232
    }

7233
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7234 7235
        if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
            goto error;
7236 7237 7238 7239 7240 7241
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
            goto error;

        if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev)))
            goto error;
    }
7242

7243
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7244 7245 7246 7247 7248 7249
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    else
        ret = qemuMonitorAddPCIHostDevice(priv->mon,
                                          &hostdev->source.subsys.u.pci,
                                          &guestAddr);
7250
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7251
    if (ret < 0)
7252
        goto error;
7253
    hostdev->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
7254
    memcpy(&hostdev->info.addr.pci, &guestAddr, sizeof(guestAddr));
7255 7256 7257

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

7258 7259
    VIR_FREE(devstr);

7260
    return 0;
7261 7262

error:
7263 7264 7265 7266 7267
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        (hostdev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &hostdev->info) < 0)
        VIR_WARN0("Unable to release PCI address on host device");

7268
    VIR_FREE(devstr);
7269
    pciDeviceListDel(driver->activePciHostdevs, pci);
7270 7271

    return -1;
7272 7273
}

7274

7275
static int qemudDomainAttachHostUsbDevice(struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7276
                                          virDomainObjPtr vm,
7277 7278
                                          virDomainHostdevDefPtr hostdev,
                                          int qemuCmdFlags)
7279 7280
{
    int ret;
7281
    qemuDomainObjPrivatePtr priv = vm->privateData;
7282 7283
    char *devstr = NULL;

7284 7285 7286 7287 7288 7289
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
            goto error;
        if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
            goto error;
    }
7290

7291
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
7292
        virReportOOMError();
7293
        goto error;
7294
    }
7295

7296
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7297 7298 7299
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    else
7300
        ret = qemuMonitorAddUSBDeviceExact(priv->mon,
7301 7302
                                           hostdev->source.subsys.u.usb.bus,
                                           hostdev->source.subsys.u.usb.device);
7303
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7304 7305 7306 7307
    if (ret < 0)
        goto error;

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

7309
    VIR_FREE(devstr);
7310

7311 7312 7313 7314 7315
    return 0;

error:
    VIR_FREE(devstr);
    return -1;
7316 7317
}

7318

7319
static int qemudDomainAttachHostDevice(struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7320
                                       virDomainObjPtr vm,
7321 7322
                                       virDomainHostdevDefPtr hostdev,
                                       int qemuCmdFlags)
M
Mark McLoughlin 已提交
7323 7324
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
7325 7326 7327
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev mode '%s' not supported"),
                        virDomainHostdevModeTypeToString(hostdev->mode));
M
Mark McLoughlin 已提交
7328 7329 7330
        return -1;
    }

7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347
    /* Resolve USB product/vendor to bus/device */
    if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
        hostdev->source.subsys.u.usb.vendor) {
        usbDevice *usb
            = usbFindDevice(hostdev->source.subsys.u.usb.vendor,
                            hostdev->source.subsys.u.usb.product);

        if (!usb)
            return -1;

        hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
        hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);

        usbFreeDevice(usb);
    }


7348
    if (driver->securityDriver &&
7349
        driver->securityDriver->domainSetSecurityHostdevLabel &&
7350
        driver->securityDriver->domainSetSecurityHostdevLabel(vm, hostdev) < 0)
7351
        return -1;
M
Mark McLoughlin 已提交
7352 7353

    switch (hostdev->source.subsys.type) {
7354
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
7355
        if (qemudDomainAttachHostPciDevice(driver, vm,
7356
                                           hostdev, qemuCmdFlags) < 0)
7357 7358 7359
            goto error;
        break;

M
Mark McLoughlin 已提交
7360
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
7361
        if (qemudDomainAttachHostUsbDevice(driver, vm,
7362
                                           hostdev, qemuCmdFlags) < 0)
7363 7364 7365
            goto error;
        break;

M
Mark McLoughlin 已提交
7366
    default:
7367 7368 7369
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev subsys type '%s' not supported"),
                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
7370
        goto error;
M
Mark McLoughlin 已提交
7371
    }
7372 7373 7374 7375 7376 7377

    return 0;

error:
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityHostdevLabel &&
7378
        driver->securityDriver->domainRestoreSecurityHostdevLabel(vm, hostdev) < 0)
7379 7380 7381
        VIR_WARN0("Unable to restore host device labelling on hotplug fail");

    return -1;
M
Mark McLoughlin 已提交
7382 7383
}

7384

7385
static int qemudDomainAttachDevice(virDomainPtr dom,
7386 7387
                                   const char *xml)
{
7388 7389 7390
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
7391
    unsigned long long qemuCmdFlags;
7392
    virCgroupPtr cgroup = NULL;
7393
    int ret = -1;
7394

7395
    qemuDriverLock(driver);
7396
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
7397
    if (!vm) {
7398 7399
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7400 7401
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7402
        goto cleanup;
7403 7404
    }

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

D
Daniel P. Berrange 已提交
7408
    if (!virDomainObjIsActive(vm)) {
7409 7410
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot attach device on inactive domain"));
7411
        goto endjob;
7412 7413
    }

7414
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
7415
                                  VIR_DOMAIN_XML_INACTIVE);
7416
    if (dev == NULL)
7417
        goto endjob;
7418

7419 7420 7421
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
7422
        goto endjob;
7423

7424
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
7425
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
7426
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
7427 7428 7429
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Unable to find cgroup for %s\n"),
                                vm->def->name);
7430
                goto endjob;
7431 7432 7433 7434 7435
            }
            if (dev->data.disk->src != NULL &&
                dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
                virCgroupAllowDevicePath(cgroup,
                                         dev->data.disk->src) < 0) {
7436 7437 7438
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unable to allow device %s"),
                                dev->data.disk->src);
7439
                goto endjob;
7440 7441 7442
            }
        }

7443
        switch (dev->data.disk->device) {
7444 7445
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
7446
            ret = qemudDomainChangeEjectableMedia(driver, vm, dev->data.disk);
7447 7448
            if (ret == 0)
                dev->data.disk = NULL;
7449
            break;
7450

7451 7452
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
7453
                ret = qemudDomainAttachUsbMassstorageDevice(driver, vm,
7454
                                                            dev->data.disk, qemuCmdFlags);
7455 7456
                if (ret == 0)
                    dev->data.disk = NULL;
7457
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
7458
                ret = qemudDomainAttachPciDiskDevice(driver, vm,
7459
                                                     dev->data.disk, qemuCmdFlags);
7460 7461
                if (ret == 0)
                    dev->data.disk = NULL;
7462
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
7463
                ret = qemudDomainAttachSCSIDisk(driver, vm,
7464
                                                dev->data.disk, qemuCmdFlags);
7465 7466
                if (ret == 0)
                    dev->data.disk = NULL;
7467
            } else {
7468 7469 7470
                qemuReportError(VIR_ERR_NO_SUPPORT,
                                _("disk bus '%s' cannot be hotplugged."),
                                virDomainDiskBusTypeToString(dev->data.disk->bus));
7471
                /* fallthrough */
7472 7473
            }
            break;
7474

7475
        default:
7476 7477 7478
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk device type '%s' cannot be hotplugged"),
                            virDomainDiskDeviceTypeToString(dev->data.disk->device));
7479 7480
            /* Fallthrough */
        }
7481
        if (ret != 0 && cgroup) {
7482 7483
            virCgroupDenyDevicePath(cgroup,
                                    dev->data.disk->src);
7484
        }
7485 7486
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
7487
            ret = qemudDomainAttachPciControllerDevice(driver, vm,
7488
                                                       dev->data.controller, qemuCmdFlags);
7489 7490
            if (ret == 0)
                dev->data.controller = NULL;
7491
        } else {
7492 7493 7494
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk controller bus '%s' cannot be hotplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
7495 7496
            /* fallthrough */
        }
M
Mark McLoughlin 已提交
7497
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
7498 7499
        ret = qemudDomainAttachNetDevice(dom->conn, driver, vm,
                                         dev->data.net, qemuCmdFlags);
7500 7501
        if (ret == 0)
            dev->data.net = NULL;
M
Mark McLoughlin 已提交
7502
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
7503
        ret = qemudDomainAttachHostDevice(driver, vm,
7504
                                          dev->data.hostdev, qemuCmdFlags);
7505 7506
        if (ret == 0)
            dev->data.hostdev = NULL;
7507
    } else {
7508 7509 7510
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("device type '%s' cannot be attached"),
                        virDomainDeviceTypeToString(dev->type));
7511
        goto endjob;
7512 7513
    }

7514
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
7515 7516
        ret = -1;

7517
endjob:
7518 7519
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
7520

7521
cleanup:
7522 7523 7524
    if (cgroup)
        virCgroupFree(&cgroup);

7525
    virDomainDeviceDefFree(dev);
7526 7527
    if (vm)
        virDomainObjUnlock(vm);
7528
    qemuDriverUnlock(driver);
7529 7530 7531
    return ret;
}

7532 7533 7534 7535
static int qemudDomainAttachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
7536 7537
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
7538 7539 7540 7541 7542 7543
        return -1;
    }

    return qemudDomainAttachDevice(dom, xml);
}

7544

7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621
static virDomainGraphicsDefPtr qemuDomainFindGraphics(virDomainObjPtr vm,
                                                      virDomainGraphicsDefPtr dev)
{
    int i;

    for (i = 0 ; i < vm->def->ngraphics ; i++) {
        if (vm->def->graphics[i]->type == dev->type)
            return vm->def->graphics[i];
    }

    return NULL;
}


static int
qemuDomainChangeGraphics(struct qemud_driver *driver,
                         virDomainObjPtr vm,
                         virDomainGraphicsDefPtr dev)
{
    virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

    if (!olddev) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("cannot find existing graphics device to modify"));
        return -1;
    }

    switch (dev->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
        if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
            (!dev->data.vnc.autoport && (olddev->data.vnc.port != dev->data.vnc.port))) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("cannot change port settings on vnc graphics"));
            return -1;
        }
        if (STRNEQ_NULLABLE(olddev->data.vnc.listenAddr, dev->data.vnc.listenAddr)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("cannot change listen address setting on vnc graphics"));
            return -1;
        }
        if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("cannot change keymap setting on vnc graphics"));
            return -1;
        }

        if (STRNEQ_NULLABLE(olddev->data.vnc.passwd, dev->data.vnc.passwd)) {
            VIR_DEBUG("Updating password on VNC server %p %p", dev->data.vnc.passwd, driver->vncPassword);
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            ret = qemuMonitorSetVNCPassword(priv->mon,
                                            dev->data.vnc.passwd ?
                                            dev->data.vnc.passwd :
                                            driver->vncPassword);
            qemuDomainObjExitMonitorWithDriver(driver, vm);

            /* Steal the new dev's  char * reference */
            VIR_FREE(olddev->data.vnc.passwd);
            olddev->data.vnc.passwd = dev->data.vnc.passwd;
            dev->data.vnc.passwd = NULL;
        } else {
            ret = 0;
        }
        break;

    default:
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unable to change config on '%s' graphics type"),
                        virDomainGraphicsTypeToString(dev->type));
        break;
    }

    return ret;
}


7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
    unsigned long long qemuCmdFlags;
    virCgroupPtr cgroup = NULL;
    int ret = -1;

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

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

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

    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                  VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto endjob;

    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
        goto endjob;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Unable to find cgroup for %s\n"),
                                vm->def->name);
                goto endjob;
            }
            if (dev->data.disk->src != NULL &&
                dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
                virCgroupAllowDevicePath(cgroup,
                                         dev->data.disk->src) < 0) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unable to allow device %s"),
                                dev->data.disk->src);
                goto endjob;
            }
        }

        switch (dev->data.disk->device) {
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
            ret = qemudDomainChangeEjectableMedia(driver, vm, dev->data.disk);
            if (ret == 0)
                dev->data.disk = NULL;
            break;


        default:
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk bus '%s' cannot be updated."),
                            virDomainDiskBusTypeToString(dev->data.disk->bus));
            break;
        }

        if (ret != 0 && cgroup) {
            virCgroupDenyDevicePath(cgroup,
                                    dev->data.disk->src);
        }
        break;

7710 7711 7712 7713
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;

7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739
    default:
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("disk device type '%s' cannot be updated"),
                        virDomainDiskDeviceTypeToString(dev->data.disk->device));
        break;
    }

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

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

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

    virDomainDeviceDefFree(dev);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}


7740
static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
7741
                                          virDomainObjPtr vm,
7742 7743
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
7744 7745 7746
{
    int i, ret = -1;
    virDomainDiskDefPtr detach = NULL;
7747
    qemuDomainObjPrivatePtr priv = vm->privateData;
7748 7749 7750 7751 7752 7753 7754 7755 7756

    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) {
7757 7758
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk %s not found"), dev->data.disk->dst);
7759
        goto cleanup;
7760 7761
    }

7762 7763
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
7764 7765
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("device cannot be detached without a PCI address"));
7766
        goto cleanup;
7767 7768
    }

7769
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
            qemuDomainObjExitMonitor(vm);
            goto cleanup;
        }
    } else {
        if (qemuMonitorRemovePCIDevice(priv->mon,
                                       &detach->info.addr.pci) < 0) {
            qemuDomainObjExitMonitor(vm);
            goto cleanup;
        }
7781
    }
7782
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7783

7784 7785 7786 7787 7788 7789 7790 7791 7792 7793
    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 {
7794
        VIR_FREE(vm->def->disks);
7795
        vm->def->ndisks = 0;
7796
    }
7797
    virDomainDiskDefFree(detach);
7798

7799 7800
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7801
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, dev->data.disk) < 0)
7802 7803
        VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);

7804
    ret = 0;
7805 7806

cleanup:
7807 7808 7809
    return ret;
}

7810
static int qemudDomainDetachPciControllerDevice(struct qemud_driver *driver,
7811
                                                virDomainObjPtr vm,
7812 7813
                                                virDomainDeviceDefPtr dev,
                                                unsigned long long qemuCmdFlags)
7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827
{
    int i, ret = -1;
    virDomainControllerDefPtr detach = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    for (i = 0 ; i < vm->def->ncontrollers ; i++) {
        if ((vm->def->controllers[i]->type == dev->data.controller->type) &&
            (vm->def->controllers[i]->idx == dev->data.controller->idx)) {
            detach = vm->def->controllers[i];
            break;
        }
    }

    if (!detach) {
7828 7829 7830 7831
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk controller %s:%d not found"),
                        virDomainControllerTypeToString(dev->data.controller->type),
                        dev->data.controller->idx);
7832 7833 7834 7835 7836
        goto cleanup;
    }

    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
7837 7838
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("device cannot be detached without a PCI address"));
7839 7840 7841
        goto cleanup;
    }

7842 7843 7844 7845 7846
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceControllerAlias(detach) < 0)
            goto cleanup;
    }

7847
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuMonitorDelDevice(priv->mon, detach->info.alias)) {
            qemuDomainObjExitMonitor(vm);
            goto cleanup;
        }
    } else {
        if (qemuMonitorRemovePCIDevice(priv->mon,
                                       &detach->info.addr.pci) < 0) {
            qemuDomainObjExitMonitor(vm);
            goto cleanup;
        }
7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874
    }
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (vm->def->ncontrollers > 1) {
        memmove(vm->def->controllers + i,
                vm->def->controllers + i + 1,
                sizeof(*vm->def->controllers) *
                (vm->def->ncontrollers - (i + 1)));
        vm->def->ncontrollers--;
        if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers) < 0) {
            /* ignore, harmless */
        }
    } else {
        VIR_FREE(vm->def->controllers);
        vm->def->ncontrollers = 0;
    }
7875 7876 7877 7878 7879

    if (qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0) {
        VIR_WARN0("Unable to release PCI address on controller");
    }

7880 7881 7882 7883 7884 7885 7886 7887
    virDomainControllerDefFree(detach);

    ret = 0;

cleanup:
    return ret;
}

7888
static int
7889
qemudDomainDetachNetDevice(struct qemud_driver *driver,
7890
                           virDomainObjPtr vm,
7891 7892
                           virDomainDeviceDefPtr dev,
                           unsigned long long qemuCmdFlags)
7893 7894 7895
{
    int i, ret = -1;
    virDomainNetDefPtr detach = NULL;
7896
    qemuDomainObjPrivatePtr priv = vm->privateData;
7897 7898
    int vlan;
    char *hostnet_name = NULL;
7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909

    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) {
7910 7911 7912 7913 7914
        qemuReportError(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]);
7915 7916 7917
        goto cleanup;
    }

7918 7919
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
7920 7921
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a PCI address"));
7922 7923 7924
        goto cleanup;
    }

7925
    if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
7926 7927
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("unable to determine original VLAN"));
7928 7929 7930 7931
        goto cleanup;
    }

    if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) {
7932
        virReportOOMError();
7933 7934 7935
        goto cleanup;
    }

7936
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
            qemuDomainObjExitMonitor(vm);
            goto cleanup;
        }
    } else {
        if (qemuMonitorRemovePCIDevice(priv->mon,
                                       &detach->info.addr.pci) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto cleanup;
        }
7948
    }
7949

7950
    if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
7951
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7952
        goto cleanup;
7953
    }
7954
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7955

7956 7957
#if WITH_MACVTAP
    if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
S
Stefan Berger 已提交
7958 7959
        if (detach->ifname)
            delMacvtap(detach->ifname);
7960 7961 7962
    }
#endif

7963
    if ((driver->macFilter) && (detach->ifname != NULL)) {
7964
        if ((errno = networkDisallowMacOnPort(driver,
7965 7966
                                              detach->ifname,
                                              detach->mac))) {
7967
            virReportSystemError(errno,
7968 7969 7970 7971 7972
             _("failed to remove ebtables rule on  '%s'"),
                                 detach->ifname);
        }
    }

S
Stefan Berger 已提交
7973 7974
    qemuTearNWFilter(detach);

7975 7976 7977 7978 7979 7980 7981 7982 7983 7984
    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 {
7985
        VIR_FREE(vm->def->nets);
7986
        vm->def->nnets = 0;
7987
    }
7988
    virDomainNetDefFree(detach);
7989

7990 7991 7992
    ret = 0;

cleanup:
7993
    VIR_FREE(hostnet_name);
7994 7995 7996
    return ret;
}

7997
static int qemudDomainDetachHostPciDevice(struct qemud_driver *driver,
7998
                                          virDomainObjPtr vm,
7999 8000
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
8001
{
8002
    virDomainHostdevDefPtr detach = NULL;
8003
    qemuDomainObjPrivatePtr priv = vm->privateData;
8004
    int i, ret;
8005
    pciDevice *pci;
8006 8007

    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
8008 8009 8010 8011
        if (vm->def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
            vm->def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
            continue;

8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026
        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) {
8027 8028 8029 8030 8031 8032
        qemuReportError(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);
8033 8034 8035
        return -1;
    }

8036 8037
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
8038 8039
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a PCI address"));
8040 8041 8042
        return -1;
    }

8043
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
            qemuDomainObjExitMonitor(vm);
            return -1;
        }
    } else {
        if (qemuMonitorRemovePCIDevice(priv->mon,
                                       &detach->info.addr.pci) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            return -1;
        }
8055
    }
8056
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8057 8058 8059

    ret = 0;

8060
    pci = pciGetDevice(detach->source.subsys.u.pci.domain,
8061 8062 8063 8064 8065 8066
                       detach->source.subsys.u.pci.bus,
                       detach->source.subsys.u.pci.slot,
                       detach->source.subsys.u.pci.function);
    if (!pci)
        ret = -1;
    else {
8067
        pciDeviceSetManaged(pci, detach->managed);
8068 8069
        pciDeviceListDel(driver->activePciHostdevs, pci);
        if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
8070
            ret = -1;
8071
        qemudReattachManagedDevice(pci);
8072
        pciFreeDevice(pci);
8073 8074
    }

8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086
    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;
8087
    }
8088
    virDomainHostdevDefFree(detach);
8089 8090 8091 8092

    return ret;
}

8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108
static int qemudDomainDetachHostUsbDevice(struct qemud_driver *driver,
                                          virDomainObjPtr vm,
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
{
    virDomainHostdevDefPtr detach = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int i, ret;

    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
        if (vm->def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
            vm->def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;

        unsigned bus = vm->def->hostdevs[i]->source.subsys.u.usb.bus;
        unsigned device = vm->def->hostdevs[i]->source.subsys.u.usb.device;
8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124
        unsigned product = vm->def->hostdevs[i]->source.subsys.u.usb.product;
        unsigned vendor = vm->def->hostdevs[i]->source.subsys.u.usb.vendor;

        if (dev->data.hostdev->source.subsys.u.usb.bus &&
            dev->data.hostdev->source.subsys.u.usb.device) {
            if (dev->data.hostdev->source.subsys.u.usb.bus == bus &&
                dev->data.hostdev->source.subsys.u.usb.device == device) {
                detach = vm->def->hostdevs[i];
                break;
            }
        } else {
            if (dev->data.hostdev->source.subsys.u.usb.product == product &&
                dev->data.hostdev->source.subsys.u.usb.vendor == vendor) {
                detach = vm->def->hostdevs[i];
                break;
            }
8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174
        }
    }

    if (!detach) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("host usb device %03d.%03d not found"),
                        dev->data.hostdev->source.subsys.u.usb.bus,
                        dev->data.hostdev->source.subsys.u.usb.device);
        return -1;
    }

    if (!detach->info.alias) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a device alias"));
        return -1;
    }

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached with this QEMU version"));
        return -1;
    }

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
        qemuDomainObjExitMonitorWithDriver(driver, vm);
        return -1;
    }
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    ret = 0;

    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;
    }
    virDomainHostdevDefFree(detach);

    return ret;
}

8175
static int qemudDomainDetachHostDevice(struct qemud_driver *driver,
8176
                                       virDomainObjPtr vm,
8177 8178
                                       virDomainDeviceDefPtr dev,
                                       unsigned long long qemuCmdFlags)
8179 8180 8181 8182 8183
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
    int ret;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
8184 8185 8186
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev mode '%s' not supported"),
                        virDomainHostdevModeTypeToString(hostdev->mode));
8187 8188 8189 8190 8191
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
8192
        ret = qemudDomainDetachHostPciDevice(driver, vm, dev, qemuCmdFlags);
8193
        break;
8194 8195 8196
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        ret = qemudDomainDetachHostUsbDevice(driver, vm, dev, qemuCmdFlags);
        break;
8197
    default:
8198 8199 8200
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev subsys type '%s' not supported"),
                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
8201 8202 8203
        return -1;
    }

8204
    if (driver->securityDriver &&
8205
        driver->securityDriver->domainRestoreSecurityHostdevLabel &&
8206
        driver->securityDriver->domainRestoreSecurityHostdevLabel(vm, dev->data.hostdev) < 0)
8207
        VIR_WARN0("Failed to restore host device labelling");
8208

8209 8210 8211
    return ret;
}

8212 8213
static int qemudDomainDetachDevice(virDomainPtr dom,
                                   const char *xml) {
8214 8215
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8216
    unsigned long long qemuCmdFlags;
8217 8218
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;
8219

8220
    qemuDriverLock(driver);
8221
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8222
    if (!vm) {
8223 8224
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8225 8226
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8227
        goto cleanup;
8228 8229
    }

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

D
Daniel P. Berrange 已提交
8233
    if (!virDomainObjIsActive(vm)) {
8234 8235
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot detach device on inactive domain"));
8236
        goto endjob;
8237 8238
    }

8239
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
8240
                                  VIR_DOMAIN_XML_INACTIVE);
8241
    if (dev == NULL)
8242
        goto endjob;
8243

8244 8245 8246 8247
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
        goto endjob;
8248 8249 8250

    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
8251
        dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
8252
        ret = qemudDomainDetachPciDiskDevice(driver, vm, dev, qemuCmdFlags);
8253
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
8254
        ret = qemudDomainDetachNetDevice(driver, vm, dev, qemuCmdFlags);
8255 8256
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
8257 8258
            ret = qemudDomainDetachPciControllerDevice(driver, vm, dev,
                                                       qemuCmdFlags);
8259
        } else {
8260 8261 8262
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk controller bus '%s' cannot be hotunplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
8263 8264
            /* fallthrough */
        }
8265
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
8266
        ret = qemudDomainDetachHostDevice(driver, vm, dev, qemuCmdFlags);
8267
    } else {
8268 8269
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("This type of device cannot be hot unplugged"));
8270
    }
8271

8272
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
8273 8274
        ret = -1;

8275
endjob:
8276 8277
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
8278

8279 8280
cleanup:
    virDomainDeviceDefFree(dev);
8281 8282
    if (vm)
        virDomainObjUnlock(vm);
8283
    qemuDriverUnlock(driver);
8284 8285 8286
    return ret;
}

8287 8288 8289 8290
static int qemudDomainDetachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
8291 8292
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
8293 8294 8295 8296 8297 8298
        return -1;
    }

    return qemudDomainDetachDevice(dom, xml);
}

8299
static int qemudDomainGetAutostart(virDomainPtr dom,
8300
                                   int *autostart) {
8301 8302 8303
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
8304

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

8309
    if (!vm) {
8310 8311
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8312 8313
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8314
        goto cleanup;
8315 8316 8317
    }

    *autostart = vm->autostart;
8318
    ret = 0;
8319

8320
cleanup:
8321 8322
    if (vm)
        virDomainObjUnlock(vm);
8323
    return ret;
8324 8325
}

8326
static int qemudDomainSetAutostart(virDomainPtr dom,
8327
                                   int autostart) {
8328 8329
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8330 8331
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
8332

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

8336
    if (!vm) {
8337 8338
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8339 8340
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8341
        goto cleanup;
8342 8343
    }

8344
    if (!vm->persistent) {
8345 8346
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot set autostart for transient domain"));
8347
        goto cleanup;
8348 8349
    }

8350 8351
    autostart = (autostart != 0);

8352
    if (vm->autostart != autostart) {
8353
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
8354
            goto cleanup;
8355
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
8356
            goto cleanup;
8357

8358 8359
        if (autostart) {
            int err;
8360

8361
            if ((err = virFileMakePath(driver->autostartDir))) {
8362
                virReportSystemError(err,
8363 8364
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
8365 8366
                goto cleanup;
            }
8367

8368
            if (symlink(configFile, autostartLink) < 0) {
8369
                virReportSystemError(errno,
8370 8371
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
8372 8373 8374 8375
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
8376
                virReportSystemError(errno,
8377 8378
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
8379 8380
                goto cleanup;
            }
8381 8382
        }

8383
        vm->autostart = autostart;
8384
    }
8385
    ret = 0;
8386

8387 8388 8389
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
8390 8391
    if (vm)
        virDomainObjUnlock(vm);
8392
    qemuDriverUnlock(driver);
8393
    return ret;
8394 8395
}

8396 8397 8398 8399 8400

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

8403
    qemuDriverLock(driver);
8404
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8405 8406
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
8407
        goto cleanup;
8408 8409 8410 8411 8412 8413 8414
    }

    if (nparams)
        *nparams = 1;

    ret = strdup("posix");
    if (!ret)
8415
        virReportOOMError();
8416 8417 8418

cleanup:
    qemuDriverUnlock(driver);
8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431
    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;

8432
    qemuDriverLock(driver);
8433
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8434 8435
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
8436
        goto cleanup;
8437 8438 8439 8440 8441
    }

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

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

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
8448 8449
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
8450 8451 8452 8453 8454 8455 8456 8457 8458
        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) {
8459 8460
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for cpu_shares tunable, expected a 'ullong'"));
8461 8462 8463 8464 8465
                goto cleanup;
            }

            rc = virCgroupSetCpuShares(group, params[i].value.ul);
            if (rc != 0) {
8466
                virReportSystemError(-rc, "%s",
8467 8468 8469 8470
                                     _("unable to set cpu shares tunable"));
                goto cleanup;
            }
        } else {
8471 8472
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Invalid parameter `%s'"), param->field);
8473 8474 8475 8476 8477 8478 8479 8480 8481
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
8482
    qemuDriverUnlock(driver);
8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496
    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;

8497
    qemuDriverLock(driver);
8498
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8499 8500
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
8501
        goto cleanup;
8502 8503 8504
    }

    if ((*nparams) != 1) {
8505 8506
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
8507
        goto cleanup;
8508 8509 8510 8511 8512
    }

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

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

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

    rc = virCgroupGetCpuShares(group, &val);
    if (rc != 0) {
8526
        virReportSystemError(-rc, "%s",
8527 8528 8529 8530 8531
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
    params[0].value.ul = val;
    params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
C
Chris Lalancette 已提交
8532
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
8533 8534
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Field cpu_shares too long for destination"));
C
Chris Lalancette 已提交
8535 8536
        goto cleanup;
    }
8537 8538 8539 8540 8541 8542 8543

    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
8544
    qemuDriverUnlock(driver);
8545 8546 8547 8548
    return ret;
}


8549 8550 8551 8552 8553 8554 8555 8556 8557
/* 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)
{
8558
    struct qemud_driver *driver = dom->conn->privateData;
8559
    int i, ret = -1;
8560
    virDomainObjPtr vm;
8561
    virDomainDiskDefPtr disk = NULL;
8562

8563
    qemuDriverLock(driver);
8564
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8565
    qemuDriverUnlock(driver);
8566
    if (!vm) {
8567 8568
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8569 8570
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8571
        goto cleanup;
8572
    }
8573 8574 8575 8576

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

D
Daniel P. Berrange 已提交
8577
    if (!virDomainObjIsActive (vm)) {
8578 8579
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8580
        goto endjob;
8581 8582
    }

8583 8584 8585 8586 8587 8588 8589 8590
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
8591 8592
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path: %s"), path);
8593
        goto endjob;
8594 8595
    }

8596
    if (!disk->info.alias) {
8597 8598
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), disk->dst);
8599
        goto endjob;
8600
    }
8601

8602
    qemuDomainObjPrivatePtr priv = vm->privateData;
8603 8604
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
8605
                                       disk->info.alias,
8606 8607 8608 8609 8610 8611
                                       &stats->rd_req,
                                       &stats->rd_bytes,
                                       &stats->wr_req,
                                       &stats->wr_bytes,
                                       &stats->errs);
    qemuDomainObjExitMonitor(vm);
8612

8613
endjob:
8614 8615
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
8616

8617
cleanup:
8618 8619
    if (vm)
        virDomainObjUnlock(vm);
8620
    return ret;
8621 8622
}

8623
#ifdef __linux__
8624 8625 8626 8627 8628
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
8629 8630
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8631
    int i;
8632
    int ret = -1;
8633

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

8638
    if (!vm) {
8639 8640
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8641 8642
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8643
        goto cleanup;
8644 8645
    }

D
Daniel P. Berrange 已提交
8646
    if (!virDomainObjIsActive(vm)) {
8647 8648
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8649
        goto cleanup;
8650 8651 8652
    }

    /* Check the path is one of the domain's network interfaces. */
8653 8654
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
8655 8656 8657 8658
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
8659 8660
    }

8661
    if (ret == 0)
8662
        ret = linuxDomainInterfaceStats(path, stats);
8663
    else
8664 8665
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path, '%s' is not a known interface"), path);
8666

8667
cleanup:
8668 8669
    if (vm)
        virDomainObjUnlock(vm);
8670 8671
    return ret;
}
8672
#else
8673 8674 8675 8676
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
8677 8678
    qemuReportError(VIR_ERR_NO_SUPPORT,
                    "%s", __FUNCTION__);
8679 8680
    return -1;
}
8681
#endif
8682

8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698
static int
qemudDomainMemoryStats (virDomainPtr dom,
                        struct _virDomainMemoryStat *stats,
                        unsigned int nr_stats)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned int ret = -1;

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

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8699 8700
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8701 8702 8703
        goto cleanup;
    }

8704 8705 8706
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

8707 8708 8709 8710 8711 8712
    if (virDomainObjIsActive(vm)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        qemuDomainObjEnterMonitor(vm);
        ret = qemuMonitorTextGetMemoryStats(priv->mon, stats, nr_stats);
        qemuDomainObjExitMonitor(vm);
    } else {
8713 8714
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8715 8716
    }

8717 8718 8719
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

8720 8721 8722 8723 8724 8725
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

8726 8727 8728 8729 8730 8731 8732
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
8733 8734 8735
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
8736

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

8741
    if (!vm) {
8742 8743
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8744 8745
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8746
        goto cleanup;
8747 8748 8749
    }

    if (!path || path[0] == '\0') {
8750 8751
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("NULL or empty path"));
8752
        goto cleanup;
8753 8754 8755
    }

    /* Check the path belongs to this domain. */
8756 8757
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
8758 8759 8760 8761
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
8762 8763
    }

8764 8765 8766 8767 8768
    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) {
8769 8770
            virReportSystemError(errno,
                                 _("%s: failed to open"), path);
8771 8772
            goto cleanup;
        }
8773

8774 8775 8776 8777 8778 8779
        /* 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) {
8780 8781
            virReportSystemError(errno,
                                 _("%s: failed to seek or read"), path);
8782 8783 8784 8785 8786
            goto cleanup;
        }

        ret = 0;
    } else {
8787 8788
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("invalid path"));
8789 8790
    }

8791 8792 8793
cleanup:
    if (fd >= 0)
        close (fd);
8794 8795
    if (vm)
        virDomainObjUnlock(vm);
8796 8797 8798
    return ret;
}

R
Richard W.M. Jones 已提交
8799 8800 8801 8802 8803 8804
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
8805 8806
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8807
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
8808 8809
    int fd = -1, ret = -1;

8810
    qemuDriverLock(driver);
8811
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8812
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
8813 8814

    if (!vm) {
8815 8816
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8817 8818
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8819 8820 8821
        goto cleanup;
    }

8822
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
8823 8824
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
8825
        goto cleanup;
R
Richard W.M. Jones 已提交
8826 8827
    }

8828 8829 8830
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
8831
    if (!virDomainObjIsActive(vm)) {
8832 8833
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8834
        goto endjob;
R
Richard W.M. Jones 已提交
8835 8836
    }

8837
    if (virAsprintf(&tmp, driver->cacheDir,  "/qemu.mem.XXXXXX") < 0) {
8838
        virReportOOMError();
8839
        goto endjob;
8840 8841
    }

R
Richard W.M. Jones 已提交
8842 8843
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
8844 8845
        virReportSystemError(errno,
                             _("mkstemp(\"%s\") failed"), tmp);
8846
        goto endjob;
R
Richard W.M. Jones 已提交
8847 8848
    }

8849
    qemuDomainObjPrivatePtr priv = vm->privateData;
8850
    qemuDomainObjEnterMonitor(vm);
8851
    if (flags == VIR_MEMORY_VIRTUAL) {
8852 8853
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
8854
            goto endjob;
8855
        }
8856
    } else {
8857 8858
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
8859
            goto endjob;
8860
        }
R
Richard W.M. Jones 已提交
8861
    }
8862
    qemuDomainObjExitMonitor(vm);
R
Richard W.M. Jones 已提交
8863 8864 8865

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
8866 8867 8868
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
8869
        goto endjob;
R
Richard W.M. Jones 已提交
8870 8871 8872
    }

    ret = 0;
8873

8874
endjob:
8875 8876
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
8877

8878
cleanup:
8879
    VIR_FREE(tmp);
R
Richard W.M. Jones 已提交
8880 8881
    if (fd >= 0) close (fd);
    unlink (tmp);
8882 8883
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
8884 8885 8886
    return ret;
}

8887

8888
static int
8889 8890 8891 8892
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
8893
{
8894 8895 8896
    struct qemud_driver *driver = conn->privateData;
    int ret;

8897
    qemuDriverLock(driver);
8898 8899
    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
                                        callback, opaque, freecb);
8900
    qemuDriverUnlock(driver);
8901

8902
    return ret;
8903 8904
}

8905

8906
static int
8907 8908
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
8909
{
8910 8911 8912
    struct qemud_driver *driver = conn->privateData;
    int ret;

8913
    qemuDriverLock(driver);
8914 8915 8916 8917 8918 8919
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
                                               callback);
8920
    qemuDriverUnlock(driver);
8921

8922
    return ret;
8923 8924
}

8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967

static int
qemuDomainEventRegisterAny(virConnectPtr conn,
                           virDomainPtr dom,
                           int eventID,
                           virConnectDomainEventGenericCallback callback,
                           void *opaque,
                           virFreeCallback freecb)
{
    struct qemud_driver *driver = conn->privateData;
    int ret;

    qemuDriverLock(driver);
    ret = virDomainEventCallbackListAddID(conn,
                                          driver->domainEventCallbacks,
                                          dom, eventID,
                                          callback, opaque, freecb);
    qemuDriverUnlock(driver);

    return ret;
}


static int
qemuDomainEventDeregisterAny(virConnectPtr conn,
                             int callbackID)
{
    struct qemud_driver *driver = conn->privateData;
    int ret;

    qemuDriverLock(driver);
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDeleteID(conn, driver->domainEventCallbacks,
                                                     callbackID);
    else
        ret = virDomainEventCallbackListRemoveID(conn, driver->domainEventCallbacks,
                                                 callbackID);
    qemuDriverUnlock(driver);

    return ret;
}


8968 8969
static void qemuDomainEventDispatchFunc(virConnectPtr conn,
                                        virDomainEventPtr event,
8970
                                        virConnectDomainEventGenericCallback cb,
8971 8972
                                        void *cbopaque,
                                        void *opaque)
8973
{
8974
    struct qemud_driver *driver = opaque;
8975

8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019
    /* 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);
9020 9021
}

D
Daniel Veillard 已提交
9022 9023
/* Migration support. */

C
Chris Lalancette 已提交
9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042
/* 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) {
9043 9044
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9045 9046 9047 9048 9049
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch == 0) {
9050 9051
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream does not have a callback registered"));
C
Chris Lalancette 已提交
9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079
        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) {
9080 9081
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9082 9083 9084 9085 9086
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch == 0) {
9087 9088
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream does not have a callback registered"));
C
Chris Lalancette 已提交
9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145
        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) {
9146 9147
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9148 9149 9150 9151 9152
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch != 0) {
9153 9154
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream already has a callback registered"));
C
Chris Lalancette 已提交
9155 9156 9157 9158 9159 9160 9161 9162
        goto cleanup;
    }

    if ((qemust->watch = virEventAddHandle(qemust->fd,
                                           events,
                                           qemuStreamMigEvent,
                                           st,
                                           NULL)) < 0) {
9163 9164
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot register file watch on stream"));
C
Chris Lalancette 已提交
9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196
        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;

9197
    if (VIR_ALLOC(qemust) < 0) {
9198
        virReportOOMError();
C
Chris Lalancette 已提交
9199
        return NULL;
9200
    }
C
Chris Lalancette 已提交
9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261

    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) {
9262 9263
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277
        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;
9278
            virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316
                                 _("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;
9317
    unsigned long long qemuCmdFlags;
C
Chris Lalancette 已提交
9318 9319 9320 9321
    struct qemuStreamMigFile *qemust = NULL;

    qemuDriverLock(driver);
    if (!dom_xml) {
9322 9323
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
9324 9325 9326
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9327
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
9328 9329 9330 9331
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
9332 9333
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
9334 9335 9336 9337
        goto cleanup;
    }

    /* Parse the domain XML. */
9338
    if (!(def = virDomainDefParseString(driver->caps, dom_xml,
C
Chris Lalancette 已提交
9339
                                        VIR_DOMAIN_XML_INACTIVE))) {
9340 9341
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
C
Chris Lalancette 已提交
9342 9343 9344 9345
        goto cleanup;
    }

    /* Target domain name, maybe renamed. */
9346 9347 9348 9349 9350 9351
    if (dname) {
        VIR_FREE(def->name);
        def->name = strdup(dname);
        if (def->name == NULL)
            goto cleanup;
    }
C
Chris Lalancette 已提交
9352

9353 9354
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
C
Chris Lalancette 已提交
9355

9356
    if (!(vm = virDomainAssignDef(driver->caps,
C
Chris Lalancette 已提交
9357
                                  &driver->domains,
9358
                                  def, true))) {
9359 9360
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to assign new VM"));
C
Chris Lalancette 已提交
9361 9362 9363 9364
        goto cleanup;
    }
    def = NULL;

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

C
Chris Lalancette 已提交
9368 9369 9370 9371 9372
    /* 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) {
9373
        virReportOOMError();
9374
        goto endjob;
C
Chris Lalancette 已提交
9375 9376 9377 9378 9379
    }
    unlink(unixfile);

    /* check that this qemu version supports the interactive exec */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
9380 9381 9382
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot determine QEMU argv syntax %s"),
                        vm->def->emulator);
9383
        goto endjob;
C
Chris Lalancette 已提交
9384 9385 9386 9387 9388 9389
    }
    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 {
9390 9391
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("Destination qemu is too old to support tunnelled migration"));
9392
        goto endjob;
C
Chris Lalancette 已提交
9393 9394
    }
    if (internalret < 0) {
9395
        virReportOOMError();
9396
        goto endjob;
C
Chris Lalancette 已提交
9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410
    }
    /* 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;
        }
9411
        goto endjob;
C
Chris Lalancette 已提交
9412 9413 9414 9415
    }

    qemust = qemuStreamMigOpen(st, unixfile);
    if (qemust == NULL) {
9416
        qemudShutdownVMDaemon(driver, vm);
9417
        if (!vm->persistent) {
9418 9419
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
9420 9421
            vm = NULL;
        }
9422
        virReportSystemError(errno,
C
Chris Lalancette 已提交
9423 9424
                             _("cannot open unix socket '%s' for tunnelled migration"),
                             unixfile);
9425
        goto endjob;
C
Chris Lalancette 已提交
9426 9427 9428 9429 9430 9431 9432 9433 9434 9435
    }

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

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

9436
endjob:
9437 9438 9439
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9440

C
Chris Lalancette 已提交
9441 9442
cleanup:
    virDomainDefFree(def);
9443 9444
    if (unixfile)
        unlink(unixfile);
C
Chris Lalancette 已提交
9445 9446 9447 9448 9449 9450 9451 9452 9453
    VIR_FREE(unixfile);
    if (vm)
        virDomainObjUnlock(vm);
    if (event)
        qemuDomainEventQueue(driver, event);
    qemuDriverUnlock(driver);
    return ret;
}

D
Daniel Veillard 已提交
9454 9455 9456 9457
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
9458
static int ATTRIBUTE_NONNULL (5)
D
Daniel Veillard 已提交
9459 9460 9461 9462 9463
qemudDomainMigratePrepare2 (virConnectPtr dconn,
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
9464
                            unsigned long flags,
D
Daniel Veillard 已提交
9465 9466 9467 9468 9469
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
    static int port = 0;
9470 9471
    struct qemud_driver *driver = dconn->privateData;
    virDomainDefPtr def = NULL;
D
Daniel Veillard 已提交
9472 9473
    virDomainObjPtr vm = NULL;
    int this_port;
9474
    char *hostname;
D
Daniel Veillard 已提交
9475 9476
    char migrateFrom [64];
    const char *p;
9477
    virDomainEventPtr event = NULL;
9478
    int ret = -1;
9479
    int internalret;
9480 9481

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

9483
    qemuDriverLock(driver);
C
Chris Lalancette 已提交
9484 9485 9486 9487
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9488 9489
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
9490 9491 9492
        goto cleanup;
    }

D
Daniel Veillard 已提交
9493
    if (!dom_xml) {
9494 9495
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
9496
        goto cleanup;
D
Daniel Veillard 已提交
9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513
    }

    /* 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 */
9514
        if ((hostname = virGetHostnameLocalhost(0)) == NULL)
9515
            goto cleanup;
D
Daniel Veillard 已提交
9516

9517 9518 9519 9520 9521
        /* 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 已提交
9522
        /* Caller frees */
9523 9524 9525
        internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
        VIR_FREE(hostname);
        if (internalret < 0) {
9526
            virReportOOMError();
9527
            goto cleanup;
D
Daniel Veillard 已提交
9528 9529 9530 9531 9532 9533
        }
    } 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.
         */
9534
        if (!STRPREFIX (uri_in, "tcp:")) {
9535 9536
            qemuReportError (VIR_ERR_INVALID_ARG,
                             "%s", _("only tcp URIs are supported for KVM/QEMU migrations"));
9537
            goto cleanup;
D
Daniel Veillard 已提交
9538 9539 9540 9541
        }

        /* Get the port number. */
        p = strrchr (uri_in, ':');
9542 9543 9544 9545 9546 9547 9548 9549
        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) {
9550
                virReportOOMError();
9551 9552 9553 9554 9555 9556 9557
                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)) {
9558 9559
                qemuReportError(VIR_ERR_INVALID_ARG,
                                "%s", _("URI ended with incorrect ':port'"));
9560 9561
                goto cleanup;
            }
D
Daniel Veillard 已提交
9562 9563 9564
        }
    }

9565
    if (*uri_out)
9566 9567
        VIR_DEBUG("Generated uri_out=%s", *uri_out);

D
Daniel Veillard 已提交
9568
    /* Parse the domain XML. */
9569
    if (!(def = virDomainDefParseString(driver->caps, dom_xml,
9570
                                        VIR_DOMAIN_XML_INACTIVE))) {
9571 9572
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
9573
        goto cleanup;
D
Daniel Veillard 已提交
9574 9575 9576
    }

    /* Target domain name, maybe renamed. */
9577 9578 9579 9580 9581 9582
    if (dname) {
        VIR_FREE(def->name);
        def->name = strdup(dname);
        if (def->name == NULL)
            goto cleanup;
    }
D
Daniel Veillard 已提交
9583

9584 9585
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
9586

9587
    if (!(vm = virDomainAssignDef(driver->caps,
D
Daniel Veillard 已提交
9588
                                  &driver->domains,
9589
                                  def, true))) {
9590 9591
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to assign new VM"));
9592
        goto cleanup;
D
Daniel Veillard 已提交
9593
    }
9594
    def = NULL;
D
Daniel Veillard 已提交
9595

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

D
Daniel Veillard 已提交
9599 9600 9601 9602 9603 9604 9605
    /* 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);
9606
    if (qemudStartVMDaemon (dconn, driver, vm, migrateFrom, -1) < 0) {
9607 9608 9609
        /* Note that we don't set an error here because qemudStartVMDaemon
         * should have already done that.
         */
9610
        if (!vm->persistent) {
9611 9612
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
9613 9614
            vm = NULL;
        }
9615
        goto endjob;
D
Daniel Veillard 已提交
9616
    }
9617 9618 9619 9620

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

9623
endjob:
9624 9625 9626
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9627

9628 9629 9630 9631 9632
cleanup:
    virDomainDefFree(def);
    if (ret != 0) {
        VIR_FREE(*uri_out);
    }
9633 9634
    if (vm)
        virDomainObjUnlock(vm);
9635 9636
    if (event)
        qemuDomainEventQueue(driver, event);
9637
    qemuDriverUnlock(driver);
9638
    return ret;
C
Chris Lalancette 已提交
9639 9640 9641

}

9642 9643 9644 9645

/* Perform migration using QEMU's native TCP migrate support,
 * not encrypted obviously
 */
9646
static int doNativeMigrate(struct qemud_driver *driver,
9647 9648 9649 9650 9651 9652 9653
                           virDomainObjPtr vm,
                           const char *uri,
                           unsigned long flags ATTRIBUTE_UNUSED,
                           const char *dname ATTRIBUTE_UNUSED,
                           unsigned long resource)
{
    int ret = -1;
9654
    xmlURIPtr uribits = NULL;
9655
    qemuDomainObjPrivatePtr priv = vm->privateData;
9656 9657 9658 9659 9660 9661

    /* 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) {
9662
            virReportOOMError();
9663 9664 9665 9666 9667 9668 9669 9670
            goto cleanup;
        }
        uribits = xmlParseURI(tmpuri);
        VIR_FREE(tmpuri);
    } else {
        uribits = xmlParseURI(uri);
    }
    if (!uribits) {
9671 9672
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot parse URI %s"), uri);
9673 9674 9675
        goto cleanup;
    }

9676
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9677
    if (resource > 0 &&
9678
        qemuMonitorSetMigrationSpeed(priv->mon, resource) < 0) {
9679
        qemuDomainObjExitMonitorWithDriver(driver, vm);
9680
        goto cleanup;
9681
    }
9682

9683
    if (qemuMonitorMigrateToHost(priv->mon, 1, uribits->server, uribits->port) < 0) {
9684
        qemuDomainObjExitMonitorWithDriver(driver, vm);
9685 9686
        goto cleanup;
    }
9687
    qemuDomainObjExitMonitorWithDriver(driver, vm);
9688

9689
    if (qemuDomainWaitForMigrationComplete(driver, vm) < 0)
9690 9691 9692 9693 9694 9695 9696 9697 9698 9699
        goto cleanup;

    ret = 0;

cleanup:
    xmlFreeURI(uribits);
    return ret;
}


9700 9701
#define TUNNEL_SEND_BUF_SIZE 65536

9702
static int doTunnelSendAll(virStreamPtr st,
9703 9704
                           int sock)
{
9705 9706 9707 9708 9709 9710 9711 9712
    char *buffer;
    int nbytes = TUNNEL_SEND_BUF_SIZE;

    if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0) {
        virReportOOMError();
        virStreamAbort(st);
        return -1;
    }
9713 9714 9715 9716 9717

    /* XXX should honour the 'resource' parameter here */
    for (;;) {
        nbytes = saferead(sock, buffer, nbytes);
        if (nbytes < 0) {
9718
            virReportSystemError(errno, "%s",
9719
                                 _("tunnelled migration failed to read from qemu"));
9720 9721
            virStreamAbort(st);
            VIR_FREE(buffer);
9722 9723 9724 9725 9726 9727 9728
            return -1;
        }
        else if (nbytes == 0)
            /* EOF; get out of here */
            break;

        if (virStreamSend(st, buffer, nbytes) < 0) {
9729 9730
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("Failed to write migration data to remote libvirtd"));
9731
            VIR_FREE(buffer);
9732 9733 9734 9735
            return -1;
        }
    }

9736 9737
    VIR_FREE(buffer);

9738 9739 9740 9741 9742 9743 9744
    if (virStreamFinish(st) < 0)
        /* virStreamFinish set the error for us */
        return -1;

    return 0;
}

C
Chris Lalancette 已提交
9745
static int doTunnelMigrate(virDomainPtr dom,
9746
                           struct qemud_driver *driver,
9747
                           virConnectPtr dconn,
C
Chris Lalancette 已提交
9748
                           virDomainObjPtr vm,
9749
                           const char *dom_xml,
C
Chris Lalancette 已提交
9750 9751 9752 9753 9754
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
9755
    qemuDomainObjPrivatePtr priv = vm->privateData;
9756 9757
    int client_sock = -1;
    int qemu_sock = -1;
C
Chris Lalancette 已提交
9758 9759
    struct sockaddr_un sa_qemu, sa_client;
    socklen_t addrlen;
9760
    virDomainPtr ddomain = NULL;
C
Chris Lalancette 已提交
9761
    int retval = -1;
9762
    virStreamPtr st = NULL;
C
Chris Lalancette 已提交
9763 9764
    char *unixfile = NULL;
    int internalret;
9765
    unsigned long long qemuCmdFlags;
C
Chris Lalancette 已提交
9766 9767 9768
    int status;
    unsigned long long transferred, remaining, total;

9769 9770 9771 9772 9773 9774 9775 9776
    /*
     * 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 已提交
9777 9778
     */

9779

9780
    /* Stage 1. setup local support infrastructure */
C
Chris Lalancette 已提交
9781 9782 9783

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
                    driver->stateDir, vm->def->name) < 0) {
9784
        virReportOOMError();
9785
        goto cleanup;
C
Chris Lalancette 已提交
9786 9787 9788 9789
    }

    qemu_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (qemu_sock < 0) {
9790
        virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
9791
                             _("cannot open tunnelled migration socket"));
9792
        goto cleanup;
C
Chris Lalancette 已提交
9793 9794 9795 9796 9797
    }
    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) {
9798 9799 9800
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Unix socket '%s' too big for destination"),
                        unixfile);
9801
        goto cleanup;
C
Chris Lalancette 已提交
9802 9803 9804
    }
    unlink(unixfile);
    if (bind(qemu_sock, (struct sockaddr *)&sa_qemu, sizeof(sa_qemu)) < 0) {
9805
        virReportSystemError(errno,
C
Chris Lalancette 已提交
9806 9807
                             _("Cannot bind to unix socket '%s' for tunnelled migration"),
                             unixfile);
9808
        goto cleanup;
C
Chris Lalancette 已提交
9809 9810
    }
    if (listen(qemu_sock, 1) < 0) {
9811
        virReportSystemError(errno,
C
Chris Lalancette 已提交
9812 9813
                             _("Cannot listen on unix socket '%s' for tunnelled migration"),
                             unixfile);
9814
        goto cleanup;
C
Chris Lalancette 已提交
9815 9816 9817 9818
    }

    /* check that this qemu version supports the unix migration */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
9819 9820 9821
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot extract Qemu version from '%s'"),
                        vm->def->emulator);
9822 9823 9824 9825 9826
        goto cleanup;
    }

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX) &&
        !(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
9827 9828
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("Source qemu is too old to support tunnelled migration"));
9829
        goto cleanup;
C
Chris Lalancette 已提交
9830
    }
9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851


    /* 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 */
9852
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
9853
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX)
9854
        internalret = qemuMonitorMigrateToUnix(priv->mon, 1, unixfile);
C
Chris Lalancette 已提交
9855 9856
    else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
        const char *args[] = { "nc", "-U", unixfile, NULL };
9857
        internalret = qemuMonitorMigrateToCommand(priv->mon, 1, args, "/dev/null");
9858 9859
    } else {
        internalret = -1;
C
Chris Lalancette 已提交
9860
    }
9861
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
9862
    if (internalret < 0) {
9863 9864
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("tunnelled migration monitor command failed"));
9865
        goto finish;
C
Chris Lalancette 已提交
9866 9867
    }

9868 9869 9870
    /* From this point onwards we *must* call cancel to abort the
     * migration on source if anything goes wrong */

C
Chris Lalancette 已提交
9871 9872 9873
    /* it is also possible that the migrate didn't fail initially, but
     * rather failed later on.  Check the output of "info migrate"
     */
9874
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9875 9876
    if (qemuMonitorGetMigrationStatus(priv->mon,
                                      &status,
C
Chris Lalancette 已提交
9877 9878 9879
                                      &transferred,
                                      &remaining,
                                      &total) < 0) {
9880
        qemuDomainObjExitMonitorWithDriver(driver, vm);
9881
        goto cancel;
C
Chris Lalancette 已提交
9882
    }
9883
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
9884 9885

    if (status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
9886 9887
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s",_("migrate failed"));
9888
        goto cancel;
C
Chris Lalancette 已提交
9889 9890 9891 9892 9893 9894
    }

    addrlen = sizeof(sa_client);
    while ((client_sock = accept(qemu_sock, (struct sockaddr *)&sa_client, &addrlen)) < 0) {
        if (errno == EAGAIN || errno == EINTR)
            continue;
9895
        virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
9896
                             _("tunnelled migration failed to accept from qemu"));
9897
        goto cancel;
C
Chris Lalancette 已提交
9898 9899
    }

9900
    retval = doTunnelSendAll(st, client_sock);
9901

9902
cancel:
9903
    if (retval != 0) {
9904
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
9905
        qemuMonitorMigrateCancel(priv->mon);
9906
        qemuDomainObjExitMonitorWithDriver(driver, vm);
9907
    }
C
Chris Lalancette 已提交
9908

9909
finish:
C
Chris Lalancette 已提交
9910 9911 9912
    dname = dname ? dname : dom->name;
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri, flags, retval);
9913 9914 9915 9916 9917 9918 9919

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

C
Chris Lalancette 已提交
9920 9921 9922
    if (ddomain)
        virUnrefDomain(ddomain);

9923 9924 9925 9926
    if (unixfile) {
        unlink(unixfile);
        VIR_FREE(unixfile);
    }
C
Chris Lalancette 已提交
9927

9928 9929 9930
    if (st)
        /* don't call virStreamFree(), because that resets any pending errors */
        virUnrefStream(st);
9931 9932 9933 9934
    return retval;
}


9935 9936 9937 9938
/* 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,
9939
                              struct qemud_driver *driver,
9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964
                              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) {
9965 9966
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("domainMigratePrepare2 did not set uri"));
9967
        goto cleanup;
9968 9969
    }

9970
    if (doNativeMigrate(driver, vm, uri_out, flags, dname, resource) < 0)
9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987
        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;
}


9988
static int doPeer2PeerMigrate(virDomainPtr dom,
9989
                              struct qemud_driver *driver,
9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005
                              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) {
10006 10007
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("Failed to connect to remote libvirt URI %s"), uri);
10008 10009 10010
        return -1;
    }
    if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
10011
                                  VIR_DRV_FEATURE_MIGRATION_P2P)) {
10012 10013
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("Destination libvirt does not support peer-to-peer migration protocol"));
10014 10015 10016
        goto cleanup;
    }

10017 10018 10019
    dom_xml = qemudVMDumpXML(driver, vm,
                             VIR_DOMAIN_XML_SECURE |
                             VIR_DOMAIN_XML_UPDATE_CPU);
10020
    if (!dom_xml) {
10021 10022
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
10023 10024 10025
        goto cleanup;
    }

10026
    if (flags & VIR_MIGRATE_TUNNELLED)
10027
        ret = doTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
10028
    else
10029
        ret = doNonTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
10030 10031 10032

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

10036
    return ret;
D
Daniel Veillard 已提交
10037 10038
}

10039

D
Daniel Veillard 已提交
10040 10041 10042 10043 10044 10045
/* 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,
10046
                           unsigned long flags,
10047
                           const char *dname,
D
Daniel Veillard 已提交
10048 10049
                           unsigned long resource)
{
10050 10051
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
10052
    virDomainEventPtr event = NULL;
10053
    int ret = -1;
10054
    int resume = 0;
10055
    qemuDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
10056

10057
    qemuDriverLock(driver);
10058
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
10059
    if (!vm) {
10060 10061
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10062 10063
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
10064
        goto cleanup;
D
Daniel Veillard 已提交
10065
    }
10066
    priv = vm->privateData;
D
Daniel Veillard 已提交
10067

10068 10069
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
10070
    priv->jobActive = QEMU_JOB_MIGRATION;
10071

D
Daniel P. Berrange 已提交
10072
    if (!virDomainObjIsActive(vm)) {
10073 10074
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
10075
        goto endjob;
D
Daniel Veillard 已提交
10076 10077
    }

10078 10079 10080
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

10081
    resume = vm->state == VIR_DOMAIN_RUNNING;
10082
    if (!(flags & VIR_MIGRATE_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
10083
        if (qemuDomainMigrateOffline(driver, vm) < 0)
10084
            goto endjob;
10085 10086
    }

10087
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
10088
        if (doPeer2PeerMigrate(dom, driver, vm, uri, flags, dname, resource) < 0)
10089
            /* doPeer2PeerMigrate already set the error, so just get out */
10090
            goto endjob;
10091
    } else {
10092
        if (doNativeMigrate(driver, vm, uri, flags, dname, resource) < 0)
10093
            goto endjob;
10094 10095
    }

D
Daniel Veillard 已提交
10096
    /* Clean up the source domain. */
10097
    qemudShutdownVMDaemon(driver, vm);
10098
    resume = 0;
10099 10100 10101 10102

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
C
Chris Lalancette 已提交
10103
    if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
10104
        virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm);
10105 10106
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains, vm);
10107 10108
        vm = NULL;
    }
10109
    ret = 0;
D
Daniel Veillard 已提交
10110

10111
endjob:
10112
    if (resume && vm->state == VIR_DOMAIN_PAUSED) {
10113
        /* we got here through some sort of failure; start the domain again */
10114
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
10115
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
10116 10117 10118 10119
            /* 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
             */
10120
            VIR_ERROR(_("Failed to resume guest %s after failure"),
10121
                      vm->def->name);
10122
        }
10123
        qemuDomainObjExitMonitorWithDriver(driver, vm);
10124

10125
        vm->state = VIR_DOMAIN_RUNNING;
10126 10127 10128 10129
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }
10130 10131 10132
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
10133

10134
cleanup:
10135 10136
    if (vm)
        virDomainObjUnlock(vm);
10137 10138
    if (event)
        qemuDomainEventQueue(driver, event);
10139
    qemuDriverUnlock(driver);
10140
    return ret;
D
Daniel Veillard 已提交
10141 10142 10143 10144 10145 10146 10147 10148 10149
}

/* 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 已提交
10150
                           unsigned long flags,
D
Daniel Veillard 已提交
10151 10152
                           int retcode)
{
10153 10154 10155
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
10156
    virDomainEventPtr event = NULL;
10157
    virErrorPtr orig_err;
C
Chris Lalancette 已提交
10158
    int newVM = 1;
D
Daniel Veillard 已提交
10159

10160 10161 10162
    /* Migration failed. Save the current error so nothing squashes it */
    orig_err = virSaveLastError();

10163
    qemuDriverLock(driver);
10164
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
10165
    if (!vm) {
10166 10167
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
10168
        goto cleanup;
D
Daniel Veillard 已提交
10169 10170
    }

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

D
Daniel Veillard 已提交
10174 10175 10176 10177
    /* 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 已提交
10178 10179 10180 10181 10182
        if (flags & VIR_MIGRATE_PERSIST_DEST) {
            if (vm->persistent)
                newVM = 0;
            vm->persistent = 1;

10183
            if (virDomainSaveConfig(driver->configDir, vm->def) < 0) {
C
Chris Lalancette 已提交
10184 10185 10186 10187 10188 10189 10190 10191 10192 10193
                /* 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;
10194
                goto endjob;
C
Chris Lalancette 已提交
10195 10196 10197 10198 10199 10200 10201 10202 10203
            }

            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_DEFINED,
                                             newVM ?
                                             VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                             VIR_DOMAIN_EVENT_DEFINED_UPDATED);
            if (event)
                qemuDomainEventQueue(driver, event);
10204
            event = NULL;
C
Chris Lalancette 已提交
10205 10206

        }
10207
        qemuDomainObjPrivatePtr priv = vm->privateData;
D
Daniel Veillard 已提交
10208
        dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
10209

10210 10211 10212 10213 10214 10215 10216 10217
        if (!(flags & VIR_MIGRATE_PAUSED)) {
            /* 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
             */
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            if (qemuMonitorStartCPUs(priv->mon, dconn) < 0) {
                if (virGetLastError() == NULL)
10218 10219
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("resume operation failed"));
10220 10221 10222
                qemuDomainObjExitMonitorWithDriver(driver, vm);
                goto endjob;
            }
10223
            qemuDomainObjExitMonitorWithDriver(driver, vm);
10224 10225

            vm->state = VIR_DOMAIN_RUNNING;
10226 10227
        }

10228 10229 10230
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
10231 10232 10233 10234 10235 10236
        if (vm->state == VIR_DOMAIN_PAUSED) {
            qemuDomainEventQueue(driver, event);
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
        }
10237
        virDomainSaveStatus(driver->caps, driver->stateDir, vm);
D
Daniel Veillard 已提交
10238
    } else {
10239
        qemudShutdownVMDaemon(driver, vm);
10240 10241 10242
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
10243
        if (!vm->persistent) {
10244 10245
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
10246 10247
            vm = NULL;
        }
D
Daniel Veillard 已提交
10248
    }
10249

10250
endjob:
10251 10252 10253
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
10254

10255
cleanup:
10256 10257 10258 10259
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
10260 10261
    if (vm)
        virDomainObjUnlock(vm);
10262 10263
    if (event)
        qemuDomainEventQueue(driver, event);
10264
    qemuDriverUnlock(driver);
10265
    return dom;
D
Daniel Veillard 已提交
10266 10267
}

10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283
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;

10284
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE);
10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301
    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) {
10302 10303
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("device %s is not a PCI device"), dev->name);
10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323
        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;

10324
    pci = pciGetDevice(domain, bus, slot, function);
10325 10326 10327
    if (!pci)
        return -1;

10328
    if (pciDettachDevice(pci) < 0)
10329 10330 10331 10332
        goto out;

    ret = 0;
out:
10333
    pciFreeDevice(pci);
10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346
    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;

10347
    pci = pciGetDevice(domain, bus, slot, function);
10348 10349 10350
    if (!pci)
        return -1;

10351
    if (pciReAttachDevice(pci) < 0)
10352 10353 10354 10355
        goto out;

    ret = 0;
out:
10356
    pciFreeDevice(pci);
10357 10358 10359 10360 10361 10362
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
10363
    struct qemud_driver *driver = dev->conn->privateData;
10364 10365 10366 10367 10368 10369 10370
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

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

10371
    pci = pciGetDevice(domain, bus, slot, function);
10372 10373 10374
    if (!pci)
        return -1;

10375 10376
    qemuDriverLock(driver);

10377
    if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
10378 10379 10380 10381
        goto out;

    ret = 0;
out:
10382
    qemuDriverUnlock(driver);
10383
    pciFreeDevice(pci);
10384 10385 10386
    return ret;
}

10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397
static int
qemuCPUCompare(virConnectPtr conn,
               const char *xmlDesc,
               unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = conn->privateData;
    int ret = VIR_CPU_COMPARE_ERROR;

    qemuDriverLock(driver);

    if (!driver->caps || !driver->caps->host.cpu) {
10398 10399
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cannot get host CPU capabilities"));
10400 10401
    }
    else
10402
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
10403 10404 10405 10406 10407 10408

    qemuDriverUnlock(driver);

    return ret;
}

10409

10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422
static char *
qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED,
                const char **xmlCPUs,
                unsigned int ncpus,
                unsigned int flags ATTRIBUTE_UNUSED)
{
    char *cpu;

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

    return cpu;
}

10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465

static int qemuDomainGetJobInfo(virDomainPtr dom,
                                virDomainJobInfoPtr info) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    priv = vm->privateData;

    if (virDomainObjIsActive(vm)) {
        if (priv->jobActive) {
            memcpy(info, &priv->jobInfo, sizeof(*info));
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

    ret = 0;

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


10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487
static int qemuDomainAbortJob(virDomainPtr dom) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    priv = vm->privateData;

    if (virDomainObjIsActive(vm)) {
        if (priv->jobActive) {
            VIR_DEBUG("Requesting cancellation of job on vm %s", vm->def->name);
10488
            priv->jobSignals |= QEMU_JOB_SIGNAL_CANCEL;
10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508
        } else {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            "%s", _("no job is active on the domain"));
            goto cleanup;
        }
    } else {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

    ret = 0;

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


10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    if (flags != 0) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported flags (0x%x) passed to '%s'"), flags, __FUNCTION__);
        return -1;
    }

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

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

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

    priv = vm->privateData;

    if (priv->jobActive != QEMU_JOB_MIGRATION) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not being migrated"));
        goto cleanup;
    }

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

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

C
Chris Lalancette 已提交
10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250
static char *qemuFindQemuImgBinary(void)
{
    char *ret;

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

    return ret;
}

static int qemuDomainSnapshotWriteSnapshotMetadata(virDomainObjPtr vm,
                                                   char *snapshotDir)
{
    int fd = -1;
    char *newxml = NULL;
    int ret = -1;
    char *snapDir = NULL;
    char *snapFile = NULL;
    int err;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    virUUIDFormat(vm->def->uuid, uuidstr);
    newxml = virDomainSnapshotDefFormat(uuidstr, vm->current_snapshot->def, 1);
    if (newxml == NULL) {
        virReportOOMError();
        return -1;
    }

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

    if (virAsprintf(&snapFile, "%s/%s.xml", snapDir,
                    vm->current_snapshot->def->name) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    fd = open(snapFile, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
    if (fd < 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("failed to create snapshot file '%s'"), snapFile);
        goto cleanup;
    }
    if (safewrite(fd, newxml, strlen(newxml)) != strlen(newxml)) {
        virReportSystemError(errno, _("Failed to write snapshot data to %s"),
                             snapFile);
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(snapFile);
    VIR_FREE(snapDir);
    VIR_FREE(newxml);
    if (fd != -1)
        close(fd);
    return ret;
}

static int qemuDomainSnapshotSetActive(virDomainObjPtr vm,
                                       char *snapshotDir)
{
    if (vm->current_snapshot) {
        vm->current_snapshot->def->active = 1;

        return qemuDomainSnapshotWriteSnapshotMetadata(vm, snapshotDir);
    }

    return 0;
}

static int qemuDomainSnapshotSetInactive(virDomainObjPtr vm,
                                         char *snapshotDir)
{
    if (vm->current_snapshot) {
        vm->current_snapshot->def->active = 0;

        return qemuDomainSnapshotWriteSnapshotMetadata(vm, snapshotDir);
    }

    return 0;
}


static int qemuDomainSnapshotIsAllowed(virDomainObjPtr vm)
{
    int i;

    /* FIXME: we need to figure out what else here might succeed; in
     * particular, if it's a raw device but on LVM, we could probably make
     * that succeed as well
     */
    for (i = 0; i < vm->def->ndisks; i++) {
        if (vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
            (!vm->def->disks[i]->driverType ||
             STRNEQ(vm->def->disks[i]->driverType, "qcow2"))) {
            qemuReportError(VIR_ERR_OPERATION_INVALID,
                            _("Disk device '%s' does not support snapshotting"),
                            vm->def->disks[i]->info.alias);
            return 0;
        }
    }

    return 1;
}

static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
                                                        const char *xmlDesc,
                                                        unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainSnapshotDefPtr def;
    qemuDomainObjPrivatePtr priv;
    const char *qemuimgarg[] = { NULL, "snapshot", "-c", NULL, NULL, NULL };
    int i;

    qemuDriverLock(driver);
    virUUIDFormat(domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    /* in a perfect world, we would allow qemu to tell us this.  The problem
     * is that qemu only does this check device-by-device; so if you had a
     * domain that booted from a large qcow2 device, but had a secondary raw
     * device attached, you wouldn't find out that you can't snapshot your
     * guest until *after* it had spent the time to snapshot the boot device.
     * This is probably a bug in qemu, but we'll work around it here for now.
     */
    if (!qemuDomainSnapshotIsAllowed(vm))
        goto cleanup;

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

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

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

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

        for (i = 0; i < vm->def->ndisks; i++) {
            /* FIXME: we also need to handle LVM here */
            /* FIXME: if we fail halfway through this loop, we are in an
             * inconsistent state.  I'm not quite sure what to do about that
             */
            if (vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                if (!vm->def->disks[i]->driverType ||
                    STRNEQ(vm->def->disks[i]->driverType, "qcow2")) {
                    qemuReportError(VIR_ERR_OPERATION_INVALID,
                                    _("Disk device '%s' does not support snapshotting"),
                                    vm->def->disks[i]->info.alias);
                    goto cleanup;
                }

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

                if (virRun(qemuimgarg, NULL) < 0) {
                    virReportSystemError(errno,
                                         _("Failed to run '%s' to create snapshot '%s' from disk '%s'"),
                                         qemuimgarg[0], snap->def->name,
                                         vm->def->disks[i]->src);
                    goto cleanup;
                }
            }
        }
    }
    else {
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        if (qemuMonitorCreateSnapshot(priv->mon, def->name) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto cleanup;
        }
        qemuDomainObjExitMonitorWithDriver(driver, vm);

    }

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

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

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

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

    if (qemuDomainSnapshotWriteSnapshotMetadata(vm, driver->snapshotDir) < 0)
        /* qemuDomainSnapshotWriteSnapshotMetadata set the error */
        goto cleanup;

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

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

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
                                       unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

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

static int qemuDomainSnapshotNum(virDomainPtr domain,
                                 unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    n = virDomainSnapshotObjListNum(&vm->snapshots);

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

static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
                                                           unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no snapshot with matching name '%s'"), name);
        goto cleanup;
    }

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

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

static int qemuDomainHasCurrentSnapshot(virDomainPtr domain,
                                        unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    ret = (vm->current_snapshot != NULL);

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

static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
                                                      unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!vm->current_snapshot) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                        _("the domain does not have a current snapshot"));
        goto cleanup;
    }

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

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

static char *qemuDomainSnapshotDumpXML(virDomainSnapshotPtr snapshot,
                                       unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

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

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

static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
                                      unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainEventPtr event = NULL;
    qemuDomainObjPrivatePtr priv;
    int rc;

    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

    vm->current_snapshot = snap;

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

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

        if (virDomainObjIsActive(vm)) {
            priv = vm->privateData;
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (rc < 0)
                goto cleanup;
        }
        else {
            if (qemuDomainSnapshotSetActive(vm, driver->snapshotDir) < 0)
                goto cleanup;

            rc = qemudStartVMDaemon(snapshot->domain->conn, driver, vm, NULL,
                                    -1);
            if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
                goto cleanup;
            if (rc < 0)
                goto cleanup;
        }

        if (snap->def->state == VIR_DOMAIN_PAUSED) {
            /* qemu unconditionally starts the domain running again after
             * loadvm, so let's pause it to keep consistency
             */
            priv = vm->privateData;
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorStopCPUs(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (rc < 0)
                goto cleanup;
        }

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

        if (virDomainObjIsActive(vm)) {
            qemudShutdownVMDaemon(driver, vm);
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
                                             VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
        }

        if (qemuDomainSnapshotSetActive(vm, driver->snapshotDir) < 0)
            goto cleanup;
    }

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

    ret = 0;

cleanup:
    if (vm && qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

    if (event)
        qemuDomainEventQueue(driver, event);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    return ret;
}

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

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

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

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

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

                if (virRun(qemuimgarg, NULL) < 0) {
                    /* we continue on even in the face of error, since other
                     * disks in this VM may have this snapshot in place
                     */
                    continue;
                }
            }
        }
    }
    else {
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        /* we continue on even in the face of error */
        qemuMonitorDeleteSnapshot(priv->mon, snap->def->name);
        qemuDomainObjExitMonitorWithDriver(driver, vm);
    }

    if (snap == vm->current_snapshot) {
        if (snap->def->parent) {
            parentsnap = virDomainSnapshotFindByName(&vm->snapshots,
                                                     snap->def->parent);
            if (!parentsnap) {
                qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                                _("no domain snapshot parent with matching name '%s'"),
                                snap->def->parent);
                goto cleanup;
            }

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

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

    virDomainSnapshotObjListRemove(&vm->snapshots, snap);

    ret = 0;

cleanup:
    VIR_FREE(snapFile);
    VIR_FREE(qemuimgarg[0]);

    return ret;
}

struct snap_remove {
    struct qemud_driver *driver;
    virDomainObjPtr vm;
    char *parent;
    int err;
};

static void qemuDomainSnapshotDiscardChildren(void *payload,
                                              const char *name ATTRIBUTE_UNUSED,
                                              void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    struct snap_remove *curr = data;
    struct snap_remove this;

    if (snap->def->parent && STREQ(snap->def->parent, curr->parent)) {
        this.driver = curr->driver;
        this.vm = curr->vm;
        this.parent = snap->def->name;
        this.err = 0;
        virHashForEach(curr->vm->snapshots.objs,
                       qemuDomainSnapshotDiscardChildren, &this);

        if (this.err)
            curr->err = this.err;
        else
            this.err = qemuDomainSnapshotDiscard(curr->driver, curr->vm, snap);
    }
}

static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                                    unsigned int flags)
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    struct snap_remove rem;

    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    snap = virDomainSnapshotFindByName(&vm->snapshots, snapshot->name);
    if (!snap) {
        qemuReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                        _("no domain snapshot with matching name '%s'"),
                        snapshot->name);
        goto cleanup;
    }

    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN) {
        rem.driver = driver;
        rem.vm = vm;
        rem.parent = snap->def->name;
        rem.err = 0;
        virHashForEach(vm->snapshots.objs, qemuDomainSnapshotDiscardChildren,
                       &rem);
        if (rem.err < 0)
            goto cleanup;
    }

    ret = qemuDomainSnapshotDiscard(driver, vm, snap);

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

11252 11253 11254 11255 11256
static virDriver qemuDriver = {
    VIR_DRV_QEMU,
    "QEMU",
    qemudOpen, /* open */
    qemudClose, /* close */
D
Daniel Veillard 已提交
11257
    qemudSupportsFeature, /* supports_feature */
11258 11259
    qemudGetType, /* type */
    qemudGetVersion, /* version */
11260
    NULL, /* libvirtVersion (impl. in libvirt.c) */
11261
    virGetHostname, /* getHostname */
11262
    qemudGetMaxVCPUs, /* getMaxVcpus */
11263
    nodeGetInfo, /* nodeGetInfo */
11264 11265 11266
    qemudGetCapabilities, /* getCapabilities */
    qemudListDomains, /* listDomains */
    qemudNumDomains, /* numOfDomains */
11267
    qemudDomainCreate, /* domainCreateXML */
11268 11269 11270 11271 11272
    qemudDomainLookupByID, /* domainLookupByID */
    qemudDomainLookupByUUID, /* domainLookupByUUID */
    qemudDomainLookupByName, /* domainLookupByName */
    qemudDomainSuspend, /* domainSuspend */
    qemudDomainResume, /* domainResume */
11273
    qemudDomainShutdown, /* domainShutdown */
11274 11275 11276
    NULL, /* domainReboot */
    qemudDomainDestroy, /* domainDestroy */
    qemudDomainGetOSType, /* domainGetOSType */
11277
    qemudDomainGetMaxMemory, /* domainGetMaxMemory */
11278
    NULL, /* domainSetMaxMemory */
11279
    qemudDomainSetMemory, /* domainSetMemory */
11280 11281 11282
    qemudDomainGetInfo, /* domainGetInfo */
    qemudDomainSave, /* domainSave */
    qemudDomainRestore, /* domainRestore */
P
Paolo Bonzini 已提交
11283
    qemudDomainCoreDump, /* domainCoreDump */
11284
    qemudDomainSetVcpus, /* domainSetVcpus */
11285 11286
    qemudDomainPinVcpu, /* domainPinVcpu */
    qemudDomainGetVcpus, /* domainGetVcpus */
11287
    qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
11288 11289
    qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
    qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
11290
    qemudDomainDumpXML, /* domainDumpXML */
11291
    qemuDomainXMLFromNative, /* domainXmlFromNative */
11292
    qemuDomainXMLToNative, /* domainXMLToNative */
11293 11294
    qemudListDefinedDomains, /* listDefinedDomains */
    qemudNumDefinedDomains, /* numOfDefinedDomains */
11295 11296 11297
    qemudDomainStart, /* domainCreate */
    qemudDomainDefine, /* domainDefineXML */
    qemudDomainUndefine, /* domainUndefine */
11298
    qemudDomainAttachDevice, /* domainAttachDevice */
11299
    qemudDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
11300
    qemudDomainDetachDevice, /* domainDetachDevice */
11301
    qemudDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
11302
    qemuDomainUpdateDeviceFlags, /* domainUpdateDeviceFlags */
11303 11304
    qemudDomainGetAutostart, /* domainGetAutostart */
    qemudDomainSetAutostart, /* domainSetAutostart */
11305 11306 11307
    qemuGetSchedulerType, /* domainGetSchedulerType */
    qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
    qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
11308 11309
    NULL, /* domainMigratePrepare (v1) */
    qemudDomainMigratePerform, /* domainMigratePerform */
11310
    NULL, /* domainMigrateFinish */
11311
    qemudDomainBlockStats, /* domainBlockStats */
11312
    qemudDomainInterfaceStats, /* domainInterfaceStats */
11313
    qemudDomainMemoryStats, /* domainMemoryStats */
11314
    qemudDomainBlockPeek, /* domainBlockPeek */
R
Richard W.M. Jones 已提交
11315
    qemudDomainMemoryPeek, /* domainMemoryPeek */
11316 11317
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
11318 11319
    qemuDomainEventRegister, /* domainEventRegister */
    qemuDomainEventDeregister, /* domainEventDeregister */
D
Daniel Veillard 已提交
11320 11321
    qemudDomainMigratePrepare2, /* domainMigratePrepare2 */
    qemudDomainMigrateFinish2, /* domainMigrateFinish2 */
11322 11323 11324
    qemudNodeDeviceDettach, /* nodeDeviceDettach */
    qemudNodeDeviceReAttach, /* nodeDeviceReAttach */
    qemudNodeDeviceReset, /* nodeDeviceReset */
C
Chris Lalancette 已提交
11325
    qemudDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
11326 11327 11328 11329
    qemuIsEncrypted, /* isEncrypted */
    qemuIsSecure, /* isSecure */
    qemuDomainIsActive, /* domainIsActive */
    qemuDomainIsPersistent, /* domainIsPersistent */
11330
    qemuCPUCompare, /* cpuCompare */
11331
    qemuCPUBaseline, /* cpuBaseline */
11332
    qemuDomainGetJobInfo, /* domainGetJobInfo */
11333
    qemuDomainAbortJob, /* domainAbortJob */
11334
    qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
11335 11336
    qemuDomainEventRegisterAny, /* domainEventRegisterAny */
    qemuDomainEventDeregisterAny, /* domainEventDeregisterAny */
11337 11338 11339
    qemuDomainManagedSave, /* domainManagedSave */
    qemuDomainHasManagedSaveImage, /* domainHasManagedSaveImage */
    qemuDomainManagedSaveRemove, /* domainManagedSaveRemove */
C
Chris Lalancette 已提交
11340 11341 11342 11343 11344 11345 11346 11347 11348
    qemuDomainSnapshotCreateXML, /* domainSnapshotCreateXML */
    qemuDomainSnapshotDumpXML, /* domainSnapshotDumpXML */
    qemuDomainSnapshotNum, /* domainSnapshotNum */
    qemuDomainSnapshotListNames, /* domainSnapshotListNames */
    qemuDomainSnapshotLookupByName, /* domainSnapshotLookupByName */
    qemuDomainHasCurrentSnapshot, /* domainHasCurrentSnapshot */
    qemuDomainSnapshotCurrent, /* domainSnapshotCurrent */
    qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */
    qemuDomainSnapshotDelete, /* domainSnapshotDelete */
11349 11350 11351
};


11352
static virStateDriver qemuStateDriver = {
11353
    .name = "QEMU",
11354 11355 11356 11357
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
11358
};
11359

S
Stefan Berger 已提交
11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374
static int
qemudVMFilterRebuild(virConnectPtr conn,
                     virHashIterator iter, void *data)
{
    (void)conn;
    virHashForEach(qemu_driver->domains.objs, iter, data);
    return 0;
}


static virNWFilterCallbackDriver qemuCallbackDriver = {
    .name = "QEMU",
    .vmFilterRebuild = qemudVMFilterRebuild,
};

11375
int qemuRegister(void) {
11376 11377
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
S
Stefan Berger 已提交
11378
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
11379 11380
    return 0;
}