qemu_driver.c 355.4 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
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
38
#include <sys/utsname.h>
39 40 41 42
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
43 44
#include <pwd.h>
#include <stdio.h>
45
#include <sys/wait.h>
46
#include <sys/ioctl.h>
47
#include <sys/un.h>
D
Daniel P. Berrange 已提交
48

49
#ifdef __linux__
50 51 52 53
# include <sys/vfs.h>
# ifndef NFS_SUPER_MAGIC
#  define NFS_SUPER_MAGIC 0x6969
# endif /* NFS_SUPER_MAGIC */
54
#endif /* __linux__ */
55

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

88

89 90
#define VIR_FROM_THIS VIR_FROM_QEMU

91 92 93 94 95 96 97 98 99 100 101 102
/* 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 */
103 104 105 106 107
    QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME = 1 << 2, /* Request migration downtime change */
};

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

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

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

    int nvcpupids;
    int *vcpupids;
126 127

    qemuDomainPCIAddressSetPtr pciaddrs;
128
    int persistentAddrs;
129 130
};

131 132
static int qemudShutdown(void);

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

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

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

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

155
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
156

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

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

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

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

static void *qemuDomainObjPrivateAlloc(void)
{
    qemuDomainObjPrivatePtr priv;

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

    return priv;
}

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

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

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


193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
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 已提交
211 212
        if (priv->monJSON)
            virBufferAddLit(buf, " json='1'");
213 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
        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) {
239
        virReportOOMError();
240 241 242
        goto error;
    }

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

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

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

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

268 269 270 271 272 273 274 275 276
    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);
277 278 279
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unsupported monitor type '%s'"),
                        virDomainChrTypeToString(priv->monConfig->type));
280 281 282
        goto error;
    }

283
    n = virXPathNodeSet("./vcpus/vcpu", ctxt, &nodes);
284 285 286 287 288
    if (n < 0)
        goto error;
    if (n) {
        priv->nvcpupids = n;
        if (VIR_REALLOC_N(priv->vcpupids, priv->nvcpupids) < 0) {
289
            virReportOOMError();
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
            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:
310 311
    virDomainChrDefFree(priv->monConfig);
    priv->monConfig = NULL;
312 313 314 315 316 317
    VIR_FREE(nodes);
    return -1;
}



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

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

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

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

    virDomainObjRef(obj);

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

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

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

    virDomainObjRef(obj);
    qemuDriverUnlock(driver);

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

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

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

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


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

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


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

    refs = qemuMonitorUnref(priv->mon);

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

477
    virDomainObjLock(obj);
478 479 480 481 482

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


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

    refs = qemuMonitorUnref(priv->mon);

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

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

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


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

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

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

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

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


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


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


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

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

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

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

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

670 671 672 673 674 675 676 677 678

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

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

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

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

D
Daniel Veillard 已提交
699

700
    return 0;
701 702
}

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

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

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

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

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

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


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

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

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

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

760 761 762 763 764 765
static virDomainDiskDefPtr
findDomainDiskByAlias(virDomainObjPtr vm,
                      const char *alias)
{
    int i;

766 767 768
    if (STRPREFIX(alias, QEMU_DRIVE_HOST_PREFIX))
        alias += strlen(QEMU_DRIVE_HOST_PREFIX);

769 770 771 772 773 774 775 776 777 778 779 780 781 782
    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;
}

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

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

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

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

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

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

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

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

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

    *secretRet = passphrase;
    *secretLen = size;

861 862 863
    ret = 0;

cleanup:
864 865
    return ret;
}
866

867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
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);
888
    return ret;
889 890
}

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

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


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


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


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

    virDomainObjLock(vm);
984 985 986 987 988 989 990 991 992 993 994 995 996 997
    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);
    }
998 999
    virDomainObjUnlock(vm);

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

    return 0;
}


1013 1014 1015 1016
static int
qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                        virDomainObjPtr vm,
                        const char *diskAlias,
1017 1018
                        int action,
                        const char *reason)
1019 1020
{
    struct qemud_driver *driver = qemu_driver;
1021
    virDomainEventPtr ioErrorEvent = NULL;
1022
    virDomainEventPtr ioErrorEvent2 = NULL;
1023
    virDomainEventPtr lifecycleEvent = NULL;
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
    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 = "";
    }

1039
    ioErrorEvent = virDomainEventIOErrorNewFromObj(vm, srcPath, devAlias, action);
1040
    ioErrorEvent2 = virDomainEventIOErrorReasonNewFromObj(vm, srcPath, devAlias, action, reason);
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053

    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);
    }
1054 1055
    virDomainObjUnlock(vm);

1056
    if (ioErrorEvent || ioErrorEvent2 || lifecycleEvent) {
1057
        qemuDriverLock(driver);
1058 1059
        if (ioErrorEvent)
            qemuDomainEventQueue(driver, ioErrorEvent);
1060 1061
        if (ioErrorEvent2)
            qemuDomainEventQueue(driver, ioErrorEvent2);
1062 1063
        if (lifecycleEvent)
            qemuDomainEventQueue(driver, lifecycleEvent);
1064 1065 1066 1067 1068 1069 1070
        qemuDriverUnlock(driver);
    }

    return 0;
}


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 1156 1157 1158 1159 1160 1161 1162
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;
}


1163 1164 1165
static qemuMonitorCallbacks monitorCallbacks = {
    .eofNotify = qemuHandleMonitorEOF,
    .diskSecretLookup = findVolumeQcowPassphrase,
1166
    .domainStop = qemuHandleDomainStop,
1167
    .domainReset = qemuHandleDomainReset,
1168
    .domainRTCChange = qemuHandleDomainRTCChange,
1169
    .domainWatchdog = qemuHandleDomainWatchdog,
1170
    .domainIOError = qemuHandleDomainIOError,
1171
    .domainGraphics = qemuHandleDomainGraphics,
1172 1173
};

1174
static int
1175
qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
1176
{
1177
    qemuDomainObjPrivatePtr priv = vm->privateData;
1178
    int ret;
1179

1180 1181 1182 1183
    /* Hold an extra reference because we can't allow 'vm' to be
     * deleted while the monitor is active */
    virDomainObjRef(vm);

1184 1185
    if ((priv->mon = qemuMonitorOpen(vm,
                                     priv->monConfig,
D
Daniel P. Berrange 已提交
1186
                                     priv->monJSON,
1187
                                     &monitorCallbacks)) == NULL) {
1188
        VIR_ERROR(_("Failed to connect monitor for %s"), vm->def->name);
1189
        return -1;
1190
    }
1191

1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorSetCapabilities(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

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

    return ret;
1202
}
1203 1204 1205 1206

/*
 * Open an existing VM's monitor, re-detect VCPU threads
 * and re-reserve the security labels in use
1207
 */
1208 1209
static void
qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
1210
{
1211 1212
    virDomainObjPtr obj = payload;
    struct qemud_driver *driver = opaque;
1213
    qemuDomainObjPrivatePtr priv;
1214
    unsigned long long qemuCmdFlags;
1215 1216

    virDomainObjLock(obj);
1217

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

1220 1221
    priv = obj->privateData;

1222
    /* XXX check PID liveliness & EXE path */
1223
    if (qemuConnectMonitor(driver, obj) < 0)
1224
        goto error;
1225

1226 1227 1228 1229
    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
        goto error;
    }

1230 1231 1232 1233 1234 1235 1236 1237 1238
    /* 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;

1239 1240 1241
    if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(obj->def)))
        goto error;

1242
    if (driver->securityDriver &&
1243
        driver->securityDriver->domainReserveSecurityLabel &&
1244
        driver->securityDriver->domainReserveSecurityLabel(obj) < 0)
1245
        goto error;
1246

1247 1248
    if (obj->def->id >= driver->nextvmid)
        driver->nextvmid = obj->def->id + 1;
1249

1250 1251
    virDomainObjUnlock(obj);
    return;
1252

1253
error:
1254 1255 1256
    /* 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 */
1257
    qemudShutdownVMDaemon(driver, obj);
1258 1259 1260 1261
    if (!obj->persistent)
        virDomainRemoveInactive(&driver->domains, obj);
    else
        virDomainObjUnlock(obj);
1262
}
1263

1264
/**
1265
 * qemudReconnectDomains
1266 1267 1268 1269 1270 1271 1272
 *
 * Try to re-open the resources for live VMs that we care
 * about.
 */
static void
qemuReconnectDomains(struct qemud_driver *driver)
{
1273
    virHashForEach(driver->domains.objs, qemuReconnectDomain, driver);
1274 1275
}

1276

1277 1278 1279 1280 1281 1282
static int
qemudSecurityInit(struct qemud_driver *qemud_drv)
{
    int ret;
    virSecurityDriverPtr security_drv;

1283 1284 1285
    qemuSecurityStackedSetDriver(qemud_drv);
    qemuSecurityDACSetDriver(qemud_drv);

1286 1287 1288 1289 1290 1291
    ret = virSecurityDriverStartup(&security_drv,
                                   qemud_drv->securityDriverName);
    if (ret == -1) {
        VIR_ERROR0(_("Failed to start security driver"));
        return -1;
    }
1292 1293 1294

    /* No primary security driver wanted to be enabled: just setup
     * the DAC driver on its own */
1295
    if (ret == -2) {
1296
        qemud_drv->securityDriver = &qemuDACSecurityDriver;
1297
        VIR_INFO0(_("No security driver available"));
1298 1299 1300 1301 1302
    } else {
        qemud_drv->securityPrimaryDriver = security_drv;
        qemud_drv->securitySecondaryDriver = &qemuDACSecurityDriver;
        qemud_drv->securityDriver = &qemuStackedSecurityDriver;
        VIR_INFO("Initialized security driver %s", security_drv->name);
1303 1304
    }

1305
    return 0;
1306
}
1307 1308


1309 1310
static virCapsPtr
qemuCreateCapabilities(virCapsPtr oldcaps,
1311
                       struct qemud_driver *driver)
1312 1313 1314 1315 1316
{
    virCapsPtr caps;

    /* Basic host arch / guest machine capabilities */
    if (!(caps = qemudCapsInit(oldcaps))) {
1317
        virReportOOMError();
1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
        return NULL;
    }

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


    /* Security driver data */
1329
    if (driver->securityPrimaryDriver) {
1330 1331
        const char *doi, *model;

1332 1333
        doi = virSecurityDriverGetDOI(driver->securityPrimaryDriver);
        model = virSecurityDriverGetModel(driver->securityPrimaryDriver);
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346

        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:
1347
    virReportOOMError();
1348 1349 1350
    virCapabilitiesFree(caps);
    return NULL;
}
1351

C
Chris Lalancette 已提交
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
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);
        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)));
1403
            VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1404 1405 1406 1407 1408 1409 1410
            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);
1411
            VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1412 1413 1414 1415
            VIR_FREE(xmlStr);
            continue;
        }

1416
        virDomainSnapshotAssignDef(&vm->snapshots, def);
C
Chris Lalancette 已提交
1417

1418
        VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
        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);
}

1440 1441 1442 1443 1444 1445
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
1446
qemudStartup(int privileged) {
1447
    char *base = NULL;
D
Daniel P. Berrange 已提交
1448
    char driverConf[PATH_MAX];
1449
    int rc;
1450

1451
    if (VIR_ALLOC(qemu_driver) < 0)
1452 1453
        return -1;

1454
    if (virMutexInit(&qemu_driver->lock) < 0) {
1455
        VIR_ERROR("%s", _("cannot initialize mutex"));
1456 1457 1458
        VIR_FREE(qemu_driver);
        return -1;
    }
1459
    qemuDriverLock(qemu_driver);
1460
    qemu_driver->privileged = privileged;
1461

1462 1463 1464
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;

1465 1466 1467
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;

1468
    /* Init callback list */
1469
    if (VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
1470
        goto out_of_memory;
1471 1472 1473 1474 1475 1476
    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
        goto out_of_memory;

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

1478
    if (privileged) {
1479 1480
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1)
1481
            goto out_of_memory;
1482

D
Daniel P. Berrange 已提交
1483
        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
1484
            goto out_of_memory;
1485 1486

        if (virAsprintf(&qemu_driver->stateDir,
1487
                      "%s/run/libvirt/qemu", LOCAL_STATE_DIR) == -1)
1488
            goto out_of_memory;
1489 1490 1491 1492 1493 1494 1495 1496

        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;
1497 1498 1499
        if (virAsprintf(&qemu_driver->saveDir,
                      "%s/lib/libvirt/qemu/save/", LOCAL_STATE_DIR) == -1)
            goto out_of_memory;
C
Chris Lalancette 已提交
1500 1501 1502
        if (virAsprintf(&qemu_driver->snapshotDir,
                        "%s/lib/libvirt/qemu/snapshot", LOCAL_STATE_DIR) == -1)
            goto out_of_memory;
1503
    } else {
1504
        uid_t uid = geteuid();
1505
        char *userdir = virGetUserDirectory(uid);
1506
        if (!userdir)
1507
            goto error;
1508

1509
        if (virAsprintf(&qemu_driver->logDir,
1510 1511
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
1512
            goto out_of_memory;
1513
        }
1514

1515 1516
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
1517
            goto out_of_memory;
1518 1519
        }
        VIR_FREE(userdir);
1520 1521 1522

        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
            goto out_of_memory;
1523 1524 1525 1526
        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;
1527 1528
        if (virAsprintf(&qemu_driver->saveDir, "%s/qemu/save", base) == -1)
            goto out_of_memory;
C
Chris Lalancette 已提交
1529 1530
        if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
            goto out_of_memory;
1531 1532
    }

L
Laine Stump 已提交
1533
    if (virFileMakePath(qemu_driver->stateDir) != 0) {
1534
        char ebuf[1024];
1535
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
1536
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
1537
        goto error;
1538
    }
L
Laine Stump 已提交
1539
    if (virFileMakePath(qemu_driver->libDir) != 0) {
1540
        char ebuf[1024];
1541
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
1542 1543 1544
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
L
Laine Stump 已提交
1545
    if (virFileMakePath(qemu_driver->cacheDir) != 0) {
1546
        char ebuf[1024];
1547
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
1548 1549 1550
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
1551 1552 1553 1554 1555 1556
    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 已提交
1557 1558 1559 1560 1561 1562
    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;
    }
1563 1564 1565 1566

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

1571
    if (virAsprintf(&qemu_driver->configDir, "%s/qemu", base) == -1)
1572 1573
        goto out_of_memory;

1574
    if (virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1)
1575 1576
        goto out_of_memory;

1577
    VIR_FREE(base);
1578

1579 1580 1581 1582 1583 1584 1585
    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)));
    }

1586 1587 1588 1589
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
        goto error;
    }

1590 1591
    if (qemudSecurityInit(qemu_driver) < 0)
        goto error;
D
Daniel P. Berrange 已提交
1592

1593
    if ((qemu_driver->caps = qemuCreateCapabilities(NULL,
1594
                                                    qemu_driver)) == NULL)
1595
        goto error;
1596

1597
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
1598 1599
        goto error;

1600 1601
    if (privileged) {
        if (chown(qemu_driver->libDir, qemu_driver->user, qemu_driver->group) < 0) {
1602
            virReportSystemError(errno,
1603 1604 1605 1606 1607
                                 _("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) {
1608
            virReportSystemError(errno,
1609 1610 1611 1612
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
1613 1614 1615 1616 1617 1618
        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 已提交
1619 1620 1621 1622 1623 1624
        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;
        }
1625 1626
    }

1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
    /* 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) {
1641
            virReportSystemError(rc,
1642 1643 1644 1645 1646 1647
                                 _("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) {
1648
            virReportSystemError(errno,
1649 1650 1651 1652 1653 1654 1655 1656 1657
                                 _("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;
    }

1658
    /* Get all the running persistent or transient configs first */
1659
    if (virDomainLoadAllConfigs(qemu_driver->caps,
1660 1661 1662 1663 1664 1665 1666 1667 1668
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
                                1, NULL, NULL) < 0)
        goto error;

    qemuReconnectDomains(qemu_driver);

    /* Then inactive persistent configs */
1669
    if (virDomainLoadAllConfigs(qemu_driver->caps,
1670 1671
                                &qemu_driver->domains,
                                qemu_driver->configDir,
1672
                                qemu_driver->autostartDir,
1673
                                0, NULL, NULL) < 0)
1674
        goto error;
C
Chris Lalancette 已提交
1675 1676 1677 1678 1679


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

1680 1681
    qemuDriverUnlock(qemu_driver);

1682 1683
    qemudAutostartConfigs(qemu_driver);

1684

1685 1686
    return 0;

1687
out_of_memory:
1688
    virReportOOMError();
1689 1690 1691
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
1692
    VIR_FREE(base);
1693
    qemudShutdown();
1694 1695 1696
    return -1;
}

1697 1698 1699 1700
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;

1701 1702 1703 1704 1705 1706 1707 1708
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }
1709 1710
}

1711 1712 1713 1714 1715 1716 1717 1718
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
1719 1720 1721
    if (!qemu_driver)
        return 0;

1722
    qemuDriverLock(qemu_driver);
1723
    virDomainLoadAllConfigs(qemu_driver->caps,
1724 1725
                            &qemu_driver->domains,
                            qemu_driver->configDir,
1726
                            qemu_driver->autostartDir,
1727
                            0, qemudNotifyLoadDomain, qemu_driver);
1728
    qemuDriverUnlock(qemu_driver);
1729

1730
    qemudAutostartConfigs(qemu_driver);
1731 1732

    return 0;
1733 1734
}

1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
/**
 * 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) {
1745
    int active = 0;
1746

1747 1748 1749
    if (!qemu_driver)
        return 0;

1750
    /* XXX having to iterate here is not great because it requires many locks */
1751
    qemuDriverLock(qemu_driver);
1752
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
1753 1754
    qemuDriverUnlock(qemu_driver);
    return active;
1755 1756
}

1757 1758 1759 1760 1761 1762 1763
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
1764
    int i;
1765

1766
    if (!qemu_driver)
1767
        return -1;
1768

1769
    qemuDriverLock(qemu_driver);
1770
    pciDeviceListFree(qemu_driver->activePciHostdevs);
1771 1772
    virCapabilitiesFree(qemu_driver->caps);

1773
    virDomainObjListDeinit(&qemu_driver->domains);
1774

1775
    VIR_FREE(qemu_driver->securityDriverName);
1776
    VIR_FREE(qemu_driver->logDir);
1777 1778
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
1779
    VIR_FREE(qemu_driver->stateDir);
1780 1781
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
1782
    VIR_FREE(qemu_driver->saveDir);
C
Chris Lalancette 已提交
1783
    VIR_FREE(qemu_driver->snapshotDir);
1784
    VIR_FREE(qemu_driver->vncTLSx509certdir);
J
Jim Meyering 已提交
1785
    VIR_FREE(qemu_driver->vncListen);
1786
    VIR_FREE(qemu_driver->vncPassword);
1787
    VIR_FREE(qemu_driver->vncSASLdir);
1788
    VIR_FREE(qemu_driver->saveImageFormat);
1789 1790
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
D
Daniel P. Berrange 已提交
1791

1792 1793 1794 1795 1796 1797
    if (qemu_driver->cgroupDeviceACL) {
        for (i = 0 ; qemu_driver->cgroupDeviceACL[i] != NULL ; i++)
            VIR_FREE(qemu_driver->cgroupDeviceACL[i]);
        VIR_FREE(qemu_driver->cgroupDeviceACL);
    }

1798 1799
    /* Free domain callback list */
    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
1800 1801 1802 1803
    virDomainEventQueueFree(qemu_driver->domainEventQueue);

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

1805 1806 1807
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);

1808 1809
    virCgroupFree(&qemu_driver->cgroup);

1810
    qemuDriverUnlock(qemu_driver);
1811
    virMutexDestroy(&qemu_driver->lock);
1812
    VIR_FREE(qemu_driver);
1813 1814

    return 0;
1815 1816
}

1817
typedef int qemuLogHandleOutput(virDomainObjPtr vm,
1818 1819
                                const char *output,
                                int fd);
1820 1821 1822 1823 1824

/*
 * Returns -1 for error, 0 on success
 */
static int
1825
qemudReadLogOutput(virDomainObjPtr vm,
1826 1827
                   int fd,
                   char *buf,
G
Guido Günther 已提交
1828
                   size_t buflen,
1829
                   qemuLogHandleOutput func,
1830 1831 1832
                   const char *what,
                   int timeout)
{
1833
    int retries = (timeout*10);
1834
    int got = 0;
1835 1836 1837
    buf[0] = '\0';

    while (retries) {
1838
        ssize_t func_ret, ret;
1839
        int isdead = 0;
G
Guido Günther 已提交
1840

1841
        func_ret = func(vm, buf, fd);
1842

1843 1844
        if (kill(vm->pid, 0) == -1 && errno == ESRCH)
            isdead = 1;
1845

1846 1847
        /* Any failures should be detected before we read the log, so we
         * always have something useful to report on failure. */
1848 1849
        ret = saferead(fd, buf+got, buflen-got-1);
        if (ret < 0) {
1850
            virReportSystemError(errno,
1851 1852 1853 1854 1855
                                 _("Failure while reading %s log output"),
                                 what);
            return -1;
        }

1856 1857 1858
        got += ret;
        buf[got] = '\0';
        if (got == buflen-1) {
1859
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
1860 1861
                            _("Out of space while reading %s log output: %s"),
                            what, buf);
1862 1863 1864 1865
            return -1;
        }

        if (isdead) {
1866
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
1867 1868
                            _("Process exited while reading %s log output: %s"),
                            what, buf);
1869 1870 1871
            return -1;
        }

1872 1873
        if (func_ret <= 0)
            return func_ret;
1874 1875 1876 1877

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

1879
    qemuReportError(VIR_ERR_INTERNAL_ERROR,
1880 1881
                    _("Timed out while reading %s log output: %s"),
                    what, buf);
1882 1883 1884
    return -1;
}

1885

1886 1887 1888 1889 1890 1891 1892 1893
/*
 * 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
 */
1894
static int
1895
qemudExtractTTYPath(const char *haystack,
1896 1897
                    size_t *offset,
                    char **path)
1898
{
1899
    static const char needle[] = "char device redirected to";
1900
    char *tmp, *dev;
1901

1902
    VIR_FREE(*path);
1903
    /* First look for our magic string */
1904 1905 1906 1907 1908
    if (!(tmp = strstr(haystack + *offset, needle))) {
        return 1;
    }
    tmp += sizeof(needle);
    dev = tmp;
1909

1910 1911 1912 1913 1914
    /*
     * And look for first whitespace character and nul terminate
     * to mark end of the pty path
     */
    while (*tmp) {
1915
        if (c_isspace(*tmp)) {
1916 1917
            *path = strndup(dev, tmp-dev);
            if (*path == NULL) {
1918
                virReportOOMError();
1919 1920
                return -1;
            }
1921

1922
            /* ... now further update offset till we get EOL */
1923
            *offset = tmp - haystack;
1924 1925
            return 0;
        }
1926
        tmp++;
1927 1928 1929 1930 1931
    }

    /*
     * We found a path, but didn't find any whitespace,
     * so it must be still incomplete - we should at
1932 1933
     * least see a \n - indicate that we want to carry
     * on trying again
1934
     */
1935
    return 1;
1936 1937
}

1938
static int
1939
qemudFindCharDevicePTYsMonitor(virDomainObjPtr vm,
1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
                               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) {                                           \
1955 1956 1957
                if (chr->data.file.path == NULL) {                        \
                    /* neither the log output nor 'info chardev' had a */ \
                    /* pty path for this chardev, report an error */      \
1958 1959 1960
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,               \
                                    _("no assigned pty for device %s"), id); \
                    return -1;                                            \
1961 1962 1963 1964 1965
                } else {                                                  \
                    /* 'info chardev' had no pty path for this chardev, */\
                    /* but the log output had, so we're fine */           \
                    continue;                                             \
                }                                                         \
1966 1967
            }                                                             \
                                                                          \
1968
            VIR_FREE(chr->data.file.path);                                \
1969
            chr->data.file.path = strdup(path);                           \
1970 1971
                                                                          \
            if (chr->data.file.path == NULL) {                            \
1972
                virReportOOMError();                                      \
1973 1974
                return -1;                                                \
            }                                                             \
1975 1976 1977 1978 1979 1980
        }                                                                 \
    }

    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");
1981
#undef LOOKUP_PTYS
1982 1983 1984 1985

    return 0;
}

1986
static int
1987
qemudFindCharDevicePTYs(virDomainObjPtr vm,
1988 1989
                        const char *output,
                        int fd ATTRIBUTE_UNUSED)
1990
{
1991
    size_t offset = 0;
1992
    int ret, i;
1993 1994

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

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

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

2018 2019 2020 2021
    /* 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) {
2022
            if ((ret = qemudExtractTTYPath(output, &offset,
2023 2024 2025 2026 2027
                                           &chr->data.file.path)) != 0)
                return ret;
        }
    }

2028
    return 0;
2029 2030
}

2031 2032 2033 2034 2035
static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED)
{
    VIR_FREE(payload);
}

2036
static int
2037
qemudWaitForMonitor(struct qemud_driver* driver,
2038
                    virDomainObjPtr vm, off_t pos)
2039
{
2040
    char buf[4096]; /* Plenty of space to get startup greeting */
2041
    int logfd;
2042
    int ret = -1;
2043

2044
    if ((logfd = qemudLogReadFD(driver->logDir, vm->def->name, pos))
2045
        < 0)
2046
        return -1;
2047

2048
    ret = qemudReadLogOutput(vm, logfd, buf, sizeof(buf),
2049
                             qemudFindCharDevicePTYs,
2050
                             "console", 30);
2051
    if (close(logfd) < 0) {
2052
        char ebuf[4096];
2053
        VIR_WARN(_("Unable to close logfile: %s"),
2054 2055
                 virStrerror(errno, ebuf, sizeof ebuf));
    }
2056

2057
    if (ret < 0)
2058
        return -1;
2059

2060
    VIR_DEBUG("Connect monitor to %p '%s'", vm, vm->def->name);
2061
    if (qemuConnectMonitor(driver, vm) < 0)
2062 2063
        return -1;

2064 2065 2066 2067 2068 2069
    /* 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) {
2070
        virReportOOMError();
2071 2072 2073
        goto cleanup;
    }

2074
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2075 2076
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ret = qemuMonitorGetPtyPaths(priv->mon, paths);
2077
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2078 2079 2080

    VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret);
    if (ret == 0) {
2081
        ret = qemudFindCharDevicePTYsMonitor(vm, paths);
2082 2083 2084 2085 2086 2087 2088 2089
    }

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

    return ret;
2090 2091
}

2092
static int
2093
qemuDetectVcpuPIDs(struct qemud_driver *driver,
2094 2095 2096
                   virDomainObjPtr vm) {
    pid_t *cpupids = NULL;
    int ncpupids;
2097
    qemuDomainObjPrivatePtr priv = vm->privateData;
2098

2099
    if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
2100 2101
        priv->nvcpupids = 1;
        if (VIR_ALLOC_N(priv->vcpupids, priv->nvcpupids) < 0) {
2102
            virReportOOMError();
2103 2104
            return -1;
        }
2105
        priv->vcpupids[0] = vm->pid;
2106 2107 2108
        return 0;
    }

2109
    /* What follows is now all KVM specific */
2110

2111
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2112
    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) < 0) {
2113
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2114
        return -1;
2115
    }
2116
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2117

2118 2119 2120
    /* Treat failure to get VCPU<->PID mapping as non-fatal */
    if (ncpupids == 0)
        return 0;
2121

2122
    if (ncpupids != vm->def->vcpus) {
2123 2124 2125
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"),
                        ncpupids, (int)vm->def->vcpus);
2126 2127 2128
        VIR_FREE(cpupids);
        return -1;
    }
2129

2130 2131
    priv->nvcpupids = ncpupids;
    priv->vcpupids = cpupids;
2132 2133 2134
    return 0;
}

2135 2136 2137
/*
 * To be run between fork/exec of QEMU only
 */
2138
static int
2139 2140
qemudInitCpuAffinity(virDomainObjPtr vm)
{
2141
    int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN;
2142
    virNodeInfo nodeinfo;
2143 2144
    unsigned char *cpumap;
    int cpumaplen;
2145 2146

    DEBUG0("Setting CPU affinity");
2147

2148
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
2149 2150 2151 2152
        return -1;

    /* setaffinity fails if you set bits for CPUs which
     * aren't present, so we have to limit ourselves */
2153 2154 2155
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
2156

2157 2158
    cpumaplen = VIR_CPU_MAPLEN(maxcpu);
    if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) {
2159
        virReportOOMError();
2160 2161 2162
        return -1;
    }

D
Daniel P. Berrange 已提交
2163
    if (vm->def->cpumask) {
2164 2165 2166
        /* 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 已提交
2167
            if (vm->def->cpumask[i])
2168
                VIR_USE_CPU(cpumap, i);
D
Daniel P. Berrange 已提交
2169
    } else {
2170 2171 2172 2173
        /* 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 已提交
2174
        for (i = 0 ; i < maxcpu ; i++)
2175
            VIR_USE_CPU(cpumap, i);
D
Daniel P. Berrange 已提交
2176
    }
2177

2178 2179 2180 2181 2182 2183 2184 2185
    /* 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;
2186
    }
2187
    VIR_FREE(cpumap);
2188 2189 2190 2191 2192

    return 0;
}


2193
static int
2194 2195 2196 2197
qemuInitPasswords(virConnectPtr conn,
                  struct qemud_driver *driver,
                  virDomainObjPtr vm,
                  unsigned long long qemuCmdFlags) {
2198
    int ret = 0;
2199
    qemuDomainObjPrivatePtr priv = vm->privateData;
2200

2201 2202 2203
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) {
2204

2205
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
2206
        ret = qemuMonitorSetVNCPassword(priv->mon,
2207 2208 2209
                                        vm->def->graphics[0]->data.vnc.passwd ?
                                        vm->def->graphics[0]->data.vnc.passwd :
                                        driver->vncPassword);
2210
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2211 2212
    }

2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235
    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);
2236
            VIR_FREE(secret);
2237 2238 2239 2240 2241 2242 2243
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (ret < 0)
                goto cleanup;
        }
    }

cleanup:
2244
    return ret;
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 2468 2469 2470 2471 2472 2473 2474 2475 2476
#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
2477
qemuDetectPCIAddresses(virDomainObjPtr vm,
2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494
                       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) {
2495 2496 2497
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for VirtIO disk %s"),
                            vm->def->disks[i]->dst);
2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508
            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) {
2509 2510 2511
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for %s NIC"),
                            vm->def->nets[i]->model);
2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522
            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) {
2523 2524 2525
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for controller %s"),
                            virDomainControllerTypeToString(vm->def->controllers[i]->type));
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
            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) {
2537 2538 2539
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for video adapter %s"),
                            virDomainVideoTypeToString(vm->def->videos[i]->type));
2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550
            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) {
2551 2552 2553
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for sound adapter %s"),
                            virDomainSoundModelTypeToString(vm->def->sounds[i]->model));
2554 2555 2556 2557 2558 2559 2560 2561 2562 2563
            return -1;
        }
    }


    if (vm->def->watchdog &&
        qemuGetPCIWatchdogVendorProduct(vm->def->watchdog, &vendor, &product) == 0) {
        if (qemuAssignNextPCIAddress(&(vm->def->watchdog->info),
                                     vendor, product,
                                     addrs,  naddrs) < 0) {
2564 2565 2566
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for watchdog %s"),
                            virDomainWatchdogModelTypeToString(vm->def->watchdog->model));
2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598
            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);

2599
    ret = qemuDetectPCIAddresses(vm, addrs, naddrs);
2600 2601 2602 2603 2604 2605

    VIR_FREE(addrs);

    return ret;
}

2606
static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
2607 2608
    int i;

2609
    for (i = 5900 ; i < 65535 ; i++) {
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641
        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;
}

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 2671 2672 2673 2674 2675 2676 2677 2678 2679

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


2680
static pciDeviceList *
2681
qemuGetPciHostDeviceList(virDomainDefPtr def)
2682 2683
{
    pciDeviceList *list;
2684 2685
    int i;

2686
    if (!(list = pciDeviceListNew()))
2687
        return NULL;
2688 2689 2690 2691 2692 2693 2694 2695 2696 2697

    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;

2698
        dev = pciGetDevice(hostdev->source.subsys.u.pci.domain,
2699 2700 2701
                           hostdev->source.subsys.u.pci.bus,
                           hostdev->source.subsys.u.pci.slot,
                           hostdev->source.subsys.u.pci.function);
2702
        if (!dev) {
2703
            pciDeviceListFree(list);
2704 2705
            return NULL;
        }
2706

2707 2708 2709
        if (pciDeviceListAdd(list, dev) < 0) {
            pciFreeDevice(dev);
            pciDeviceListFree(list);
2710
            return NULL;
2711 2712
        }

2713
        pciDeviceSetManaged(dev, hostdev->managed);
2714 2715
    }

2716 2717 2718 2719
    return list;
}

static int
2720 2721 2722 2723
qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                            virDomainDefPtr def)
{
    pciDeviceList *pcidevs;
2724
    int i;
2725
    int ret = -1;
2726 2727 2728 2729

    if (!def->nhostdevs)
        return 0;

2730
    if (!(pcidevs = qemuGetPciHostDeviceList(def)))
2731 2732
        return -1;

2733 2734
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2735 2736 2737
        pciDeviceListSteal(pcidevs, dev);
        if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            pciFreeDevice(dev);
2738
            goto cleanup;
2739 2740 2741
        }
    }

2742 2743 2744
    ret = 0;

cleanup:
2745
    pciDeviceListFree(pcidevs);
2746 2747 2748
    return ret;
}

2749

2750
static int
2751 2752
qemuPrepareHostPCIDevices(struct qemud_driver *driver,
                          virDomainDefPtr def)
2753 2754 2755
{
    pciDeviceList *pcidevs;
    int i;
2756
    int ret = -1;
2757

2758
    if (!(pcidevs = qemuGetPciHostDeviceList(def)))
2759 2760
        return -1;

2761
    /* We have to use 3 loops here. *All* devices must
2762 2763
     * be detached before we reset any of them, because
     * in some cases you have to reset the whole PCI,
2764 2765
     * which impacts all devices on it. Also, all devices
     * must be reset before being marked as active.
2766 2767 2768 2769 2770 2771 2772
     */

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

2773 2774
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2775
        if (!pciDeviceIsAssignable(dev, !driver->relaxedACS))
2776 2777
            goto cleanup;

2778
        if (pciDeviceGetManaged(dev) &&
2779
            pciDettachDevice(dev) < 0)
2780 2781
            goto cleanup;
    }
2782 2783 2784

    /* Now that all the PCI hostdevs have be dettached, we can safely
     * reset them */
2785 2786
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2787
        if (pciResetDevice(dev, driver->activePciHostdevs) < 0)
2788 2789
            goto cleanup;
    }
2790

2791
    /* Now mark all the devices as active */
2792 2793
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2794 2795 2796
        pciDeviceListSteal(pcidevs, dev);
        if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            pciFreeDevice(dev);
2797 2798
            goto cleanup;
        }
2799 2800
    }

2801
    ret = 0;
2802

2803
cleanup:
2804
    pciDeviceListFree(pcidevs);
2805
    return ret;
2806 2807
}

2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818

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;
2819
        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
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 2849 2850 2851 2852 2853 2854 2855 2856 2857
            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;
}


2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868
static void
qemudReattachManagedDevice(pciDevice *dev)
{
    int retries = 100;

    if (pciDeviceGetManaged(dev)) {
        while (pciWaitForDeviceCleanup(dev, "kvm_assigned_device")
               && retries) {
            usleep(100*1000);
            retries--;
        }
2869
        if (pciReAttachDevice(dev) < 0) {
2870 2871 2872 2873 2874 2875 2876 2877
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to re-attach PCI device: %s"),
                      err ? err->message : "");
            virResetError(err);
        }
    }
}

2878
static void
2879
qemuDomainReAttachHostDevices(struct qemud_driver *driver,
2880
                              virDomainDefPtr def)
2881
{
2882
    pciDeviceList *pcidevs;
2883 2884
    int i;

2885 2886
    if (!def->nhostdevs)
        return;
2887

2888
    if (!(pcidevs = qemuGetPciHostDeviceList(def))) {
2889
        virErrorPtr err = virGetLastError();
2890
        VIR_ERROR(_("Failed to allocate pciDeviceList: %s"),
2891 2892 2893
                  err ? err->message : "");
        virResetError(err);
        return;
2894 2895
    }

2896 2897
    /* Again 3 loops; mark all devices as inactive before reset
     * them and reset all the devices before re-attach */
2898

2899 2900
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2901
        pciDeviceListDel(driver->activePciHostdevs, dev);
2902
    }
2903

2904 2905
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2906
        if (pciResetDevice(dev, driver->activePciHostdevs) < 0) {
2907
            virErrorPtr err = virGetLastError();
2908
            VIR_ERROR(_("Failed to reset PCI device: %s"),
2909 2910 2911
                      err ? err->message : "");
            virResetError(err);
        }
2912
    }
2913

2914 2915
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2916
        qemudReattachManagedDevice(dev);
2917
    }
2918

2919
    pciDeviceListFree(pcidevs);
2920 2921
}

2922 2923 2924 2925 2926 2927 2928 2929 2930 2931
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

2932
static int qemuSetupCgroup(struct qemud_driver *driver,
2933 2934 2935 2936
                           virDomainObjPtr vm)
{
    virCgroupPtr cgroup = NULL;
    int rc;
2937
    unsigned int i;
2938 2939 2940 2941
    const char *const *deviceACL =
        driver->cgroupDeviceACL ?
        (const char *const *)driver->cgroupDeviceACL :
        defaultDeviceACL;
2942 2943 2944 2945 2946 2947

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

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

2954 2955
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        rc = virCgroupDenyAllDevices(cgroup);
2956
        if (rc != 0) {
2957 2958 2959 2960 2961
            if (rc == -EPERM) {
                VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
                goto done;
            }

2962
            virReportSystemError(-rc,
2963
                                 _("Unable to deny all devices for %s"), vm->def->name);
2964 2965 2966
            goto cleanup;
        }

2967 2968 2969 2970 2971 2972 2973 2974
        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) {
2975
                virReportSystemError(-rc,
2976 2977 2978 2979 2980
                                     _("Unable to allow device %s for %s"),
                                     vm->def->disks[i]->src, vm->def->name);
                goto cleanup;
            }
        }
2981

2982
        rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
2983
        if (rc != 0) {
2984
            virReportSystemError(-rc, "%s",
2985
                                 _("unable to allow /dev/pts/ devices"));
2986 2987 2988
            goto cleanup;
        }

2989 2990 2991
        if (vm->def->nsounds) {
            rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR);
            if (rc != 0) {
2992
                virReportSystemError(-rc, "%s",
2993 2994 2995 2996 2997 2998 2999 3000 3001 3002
                                     _("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) {
3003
                virReportSystemError(-rc,
3004 3005 3006 3007
                                     _("unable to allow device %s"),
                                     deviceACL[i]);
                goto cleanup;
            }
3008 3009 3010 3011
        }
    }

done:
3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023
    virCgroupFree(&cgroup);
    return 0;

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


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

    rc = virCgroupAddTask(cgroup, getpid());
    if (rc != 0) {
3068
        virReportSystemError(-rc,
3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085
                             _("unable to add domain %s task %d to cgroup"),
                             def->name, getpid());
        goto cleanup;
    }

    ret = 0;

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


struct qemudHookData {
    virConnectPtr conn;
    virDomainObjPtr vm;
    struct qemud_driver *driver;
3086 3087 3088
};

static int qemudSecurityHook(void *data) {
3089 3090
    struct qemudHookData *h = data;

3091 3092 3093
    /* This must take place before exec(), so that all QEMU
     * memory allocation is on the correct NUMA node
     */
3094
    if (qemuAddToCgroup(h->driver, h->vm->def) < 0)
3095 3096
        return -1;

3097 3098 3099
    /* This must be done after cgroup placement to avoid resetting CPU
     * affinity */
    if (qemudInitCpuAffinity(h->vm) < 0)
3100
        return -1;
3101

3102 3103
    if (h->driver->securityDriver &&
        h->driver->securityDriver->domainSetSecurityProcessLabel &&
3104
        h->driver->securityDriver->domainSetSecurityProcessLabel(h->driver->securityDriver, h->vm) < 0)
3105 3106 3107
        return -1;

    return 0;
3108 3109
}

3110
static int
3111
qemuPrepareMonitorChr(struct qemud_driver *driver,
3112
                      virDomainChrDefPtr monConfig,
3113 3114
                      const char *vm)
{
3115
    monConfig->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_MONITOR;
3116

3117 3118
    monConfig->type = VIR_DOMAIN_CHR_TYPE_UNIX;
    monConfig->data.nix.listen = 1;
3119

D
Daniel P. Berrange 已提交
3120
    if (!(monConfig->info.alias = strdup("monitor"))) {
3121
        virReportOOMError();
D
Daniel P. Berrange 已提交
3122 3123 3124
        return -1;
    }

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

    return 0;
}

C
Chris Lalancette 已提交
3134 3135 3136 3137 3138
static int qemuDomainSnapshotSetActive(virDomainObjPtr vm,
                                       char *snapshotDir);
static int qemuDomainSnapshotSetInactive(virDomainObjPtr vm,
                                         char *snapshotDir);

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

3160
    struct qemudHookData hookData;
3161 3162 3163 3164
    hookData.conn = conn;
    hookData.vm = vm;
    hookData.driver = driver;

3165
    FD_ZERO(&keepfd);
3166

3167 3168
    DEBUG0("Beginning VM startup process");

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

3175 3176 3177 3178 3179
    /* Must be run before security labelling */
    DEBUG0("Preparing host devices");
    if (qemuPrepareHostDevices(driver, vm->def) < 0)
        goto cleanup;

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

3188
    DEBUG0("Generating setting domain security labels (if required)");
3189 3190
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityAllLabel &&
3191
        driver->securityDriver->domainSetSecurityAllLabel(vm) < 0)
3192 3193
        goto cleanup;

3194 3195 3196
    /* Ensure no historical cgroup for this VM is lying around bogus
     * settings */
    DEBUG0("Ensuring no historical cgroup is lying around");
3197
    qemuRemoveCgroup(driver, vm, 1);
3198

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

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

3219
    DEBUG0("Creating domain log file");
3220
    if ((logfile = qemudLogFD(driver, vm->def->name)) < 0)
3221
        goto cleanup;
3222

3223 3224
    emulator = vm->def->emulator;

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

3236
    DEBUG0("Determing emulator version");
3237
    if (qemudExtractVersionInfo(emulator,
3238
                                NULL,
3239
                                &qemuCmdFlags) < 0)
3240
        goto cleanup;
3241

3242
    DEBUG0("Setting up domain cgroup (if required)");
3243
    if (qemuSetupCgroup(driver, vm) < 0)
3244 3245
        goto cleanup;

3246
    if (VIR_ALLOC(priv->monConfig) < 0) {
3247
        virReportOOMError();
3248 3249 3250
        goto cleanup;
    }

3251
    DEBUG0("Preparing monitor state");
3252
    if (qemuPrepareMonitorChr(driver, priv->monConfig, vm->def->name) < 0)
3253
        goto cleanup;
3254

D
Daniel P. Berrange 已提交
3255 3256 3257
#if HAVE_YAJL
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON)
        priv->monJSON = 1;
3258
    else
D
Daniel P. Berrange 已提交
3259
#endif
3260
        priv->monJSON = 0;
D
Daniel P. Berrange 已提交
3261

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

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

3275
    /*
M
Matthew Booth 已提交
3276
     * Normally PCI addresses are assigned in the virDomainCreate
3277 3278 3279 3280 3281
     * 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
     */
3282
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
3283
        DEBUG0("Assigning domain PCI addresses");
3284
        /* Populate cache with current addresses */
3285 3286 3287 3288 3289 3290 3291
        if (priv->pciaddrs) {
            qemuDomainPCIAddressSetFree(priv->pciaddrs);
            priv->pciaddrs = NULL;
        }
        if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(vm->def)))
            goto cleanup;

3292 3293

        /* Assign any remaining addresses */
3294 3295
        if (qemuAssignDevicePCISlots(vm->def, priv->pciaddrs) < 0)
            goto cleanup;
3296 3297 3298 3299

        priv->persistentAddrs = 1;
    } else {
        priv->persistentAddrs = 0;
3300 3301
    }

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

    if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
3311
        goto cleanup;
3312

3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328
    /* 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;
    }

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

3353
    if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
3354
        VIR_WARN(_("Unable to seek to end of logfile: %s"),
3355
                 virStrerror(errno, ebuf, sizeof ebuf));
3356

3357 3358 3359
    for (i = 0 ; i < ntapfds ; i++)
        FD_SET(tapfds[i], &keepfd);

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

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

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

3388
    for (i = 0 ; argv[i] ; i++)
3389 3390
        VIR_FREE(argv[i]);
    VIR_FREE(argv);
3391

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

3396 3397 3398
    if (ret == -1) /* The VM failed to start; tear filters before taps */
        virNWFilterTearVMNWFilters(vm);

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

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

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

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

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

D
Daniel P. Berrange 已提交
3421 3422 3423
    /* 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)) {
3424
        DEBUG0("Determining domain device PCI addresses");
D
Daniel P. Berrange 已提交
3425 3426 3427
        if (qemuInitPCIAddresses(driver, vm) < 0)
            goto abort;
    }
3428

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

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

3449

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

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

3457
    return 0;
3458 3459

cleanup:
3460 3461 3462
    /* 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 */
3463
    qemuDomainReAttachHostDevices(driver, vm->def);
3464

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

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

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

    return -1;
3490 3491 3492
}


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

D
Daniel P. Berrange 已提交
3502
    if (!virDomainObjIsActive(vm))
3503
        return;
3504

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

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

3511
    virNWFilterTearVMNWFilters(vm);
S
Stefan Berger 已提交
3512

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

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

3534 3535 3536
    if (priv->mon &&
        qemuMonitorClose(priv->mon) == 0) {
        virDomainObjUnref(vm);
3537
        priv->mon = NULL;
3538
    }
3539

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

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

3550 3551 3552 3553 3554 3555 3556 3557 3558 3559
    /* 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);
    }

3560
    /* Reset Security Labels */
3561
    if (driver->securityDriver &&
3562
        driver->securityDriver->domainRestoreSecurityAllLabel)
3563
        driver->securityDriver->domainRestoreSecurityAllLabel(vm);
3564 3565
    if (driver->securityDriver &&
        driver->securityDriver->domainReleaseSecurityLabel)
3566
        driver->securityDriver->domainReleaseSecurityLabel(vm);
3567

3568 3569 3570 3571 3572 3573 3574
    /* 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 已提交
3575
    virDomainDefClearDeviceAliases(vm->def);
3576 3577 3578 3579 3580
    if (!priv->persistentAddrs) {
        virDomainDefClearPCIAddresses(vm->def);
        qemuDomainPCIAddressSetFree(priv->pciaddrs);
        priv->pciaddrs = NULL;
    }
3581

3582
    qemuDomainReAttachHostDevices(driver, vm->def);
3583

S
Stefan Berger 已提交
3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594
#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

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

3605
    qemudRemoveDomainStatus(driver, vm);
D
Daniel P. Berrange 已提交
3606

3607
    vm->pid = -1;
3608
    vm->def->id = -1;
3609
    vm->state = VIR_DOMAIN_SHUTOFF;
3610 3611
    VIR_FREE(priv->vcpupids);
    priv->nvcpupids = 0;
3612 3613

    if (vm->newDef) {
3614
        virDomainDefFree(vm->def);
3615
        vm->def = vm->newDef;
3616
        vm->def->id = -1;
3617 3618
        vm->newDef = NULL;
    }
3619 3620 3621 3622 3623

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
3624 3625 3626
}


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

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

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

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

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

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
3689
    struct qemud_driver *driver = conn->privateData;
3690 3691

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

    conn->privateData = NULL;

    return 0;
}

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

3714
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
3715
    return "QEMU";
3716 3717
}

3718

3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731
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;
}


3732 3733 3734 3735
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
3736

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

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

    close(fd);
    return maxvcpus;
}


3752
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
3753 3754 3755
    if (!type)
        return 16;

3756
    if (STRCASEEQ(type, "qemu"))
3757 3758
        return 16;

3759
    if (STRCASEEQ(type, "kvm"))
3760
        return kvmGetMaxVCPUs();
3761

3762
    if (STRCASEEQ(type, "kqemu"))
3763
        return 1;
3764

3765 3766
    qemuReportError(VIR_ERR_INVALID_ARG,
                    _("unknown type '%s'"), type);
3767 3768 3769
    return -1;
}

3770

3771
static char *qemudGetCapabilities(virConnectPtr conn) {
3772
    struct qemud_driver *driver = conn->privateData;
3773
    virCapsPtr caps = NULL;
3774
    char *xml = NULL;
3775

3776
    qemuDriverLock(driver);
3777

3778
    if ((caps = qemuCreateCapabilities(qemu_driver->caps,
3779
                                       qemu_driver)) == NULL) {
3780 3781 3782
        virCapabilitiesFree(caps);
        goto cleanup;
    }
3783

3784
    virCapabilitiesFree(qemu_driver->caps);
3785 3786 3787
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
3788
        virReportOOMError();
3789 3790

cleanup:
3791
    qemuDriverUnlock(driver);
3792

3793
    return xml;
3794 3795 3796
}


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

3804 3805 3806 3807 3808 3809
    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 已提交
3810 3811 3812 3813
        return -1;
    }

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

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

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

D
Daniel P. Berrange 已提交
3849

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

    fclose(pidinfo);

    return 0;
}


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

3865
    qemuDriverLock(driver);
3866
    vm  = virDomainFindByID(&driver->domains, id);
3867
    qemuDriverUnlock(driver);
3868 3869

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

3875
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
3876
    if (dom) dom->id = vm->def->id;
3877 3878

cleanup:
3879 3880
    if (vm)
        virDomainObjUnlock(vm);
3881 3882
    return dom;
}
3883

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

3890
    qemuDriverLock(driver);
3891
    vm = virDomainFindByUUID(&driver->domains, uuid);
3892 3893
    qemuDriverUnlock(driver);

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

3902
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
3903
    if (dom) dom->id = vm->def->id;
3904 3905

cleanup:
3906 3907
    if (vm)
        virDomainObjUnlock(vm);
3908 3909
    return dom;
}
3910

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

3917
    qemuDriverLock(driver);
3918
    vm = virDomainFindByName(&driver->domains, name);
3919 3920
    qemuDriverUnlock(driver);

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

3927
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
3928
    if (dom) dom->id = vm->def->id;
3929 3930

cleanup:
3931 3932
    if (vm)
        virDomainObjUnlock(vm);
3933 3934 3935
    return dom;
}

3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946

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

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


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

3984
    qemuDriverLock(driver);
3985
    if (qemudExtractVersion(driver) < 0)
3986
        goto cleanup;
3987

3988
    *version = qemu_driver->qemuVersion;
3989 3990 3991
    ret = 0;

cleanup:
3992
    qemuDriverUnlock(driver);
3993
    return ret;
D
Daniel P. Berrange 已提交
3994 3995
}

3996
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
3997
    struct qemud_driver *driver = conn->privateData;
3998
    int n;
3999

4000
    qemuDriverLock(driver);
4001
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
4002
    qemuDriverUnlock(driver);
4003

4004
    return n;
D
Daniel P. Berrange 已提交
4005
}
4006

4007
static int qemudNumDomains(virConnectPtr conn) {
4008
    struct qemud_driver *driver = conn->privateData;
4009
    int n;
4010

4011
    qemuDriverLock(driver);
4012
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
4013
    qemuDriverUnlock(driver);
4014

4015
    return n;
D
Daniel P. Berrange 已提交
4016
}
4017

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

4026
    qemuDriverLock(driver);
4027
    if (!(def = virDomainDefParseString(driver->caps, xml,
4028
                                        VIR_DOMAIN_XML_INACTIVE)))
4029
        goto cleanup;
4030

4031
    if (virSecurityDriverVerify(def) < 0)
4032 4033
        goto cleanup;

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

4037 4038 4039 4040 4041 4042
    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

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

4043
    if (!(vm = virDomainAssignDef(driver->caps,
4044
                                  &driver->domains,
4045
                                  def, false)))
4046 4047 4048
        goto cleanup;

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

4050 4051 4052
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup; /* XXXX free the 'vm' we created ? */

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

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

4065
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4066
    if (dom) dom->id = vm->def->id;
4067

4068 4069 4070
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4071

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


4083
static int qemudDomainSuspend(virDomainPtr dom) {
4084 4085 4086
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4087
    virDomainEventPtr event = NULL;
4088
    qemuDomainObjPrivatePtr priv;
4089

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

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

    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"));
4123
            goto endjob;
4124
        }
4125 4126
        if (vm->state != VIR_DOMAIN_PAUSED) {
            int rc;
4127
            int state = vm->state;
4128

4129
            vm->state = VIR_DOMAIN_PAUSED;
4130 4131 4132
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorStopCPUs(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4133 4134
            if (rc < 0) {
                vm->state = state;
4135
                goto endjob;
4136
            }
4137 4138 4139 4140 4141 4142 4143
            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 已提交
4144
    }
4145

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

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

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


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

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

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

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

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

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

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


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

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

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

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

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

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

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

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


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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4404 4405 4406 4407 4408
    /* 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;
4409
    }
4410

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

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

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

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

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

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

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

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

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

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

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

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

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


4496 4497 4498 4499 4500 4501 4502 4503
/** qemuDomainMigrateOffline:
 * Pause domain for non-live migration.
 */
static int
qemuDomainMigrateOffline(struct qemud_driver *driver,
                         virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4504
    int state = vm->state;
4505 4506
    int ret;

4507
    vm->state = VIR_DOMAIN_PAUSED;
4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorStopCPUs(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (ret == 0) {
        virDomainEventPtr event;

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
        if (event)
            qemuDomainEventQueue(driver, event);
4520 4521
    } else
        vm->state = state;
4522 4523 4524 4525 4526

    return ret;
}


4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540
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 */
4541
        struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
4542 4543 4544
        struct timeval now;
        int rc;

4545 4546
        if (priv->jobSignals & QEMU_JOB_SIGNAL_CANCEL) {
            priv->jobSignals ^= QEMU_JOB_SIGNAL_CANCEL;
4547 4548 4549 4550 4551 4552 4553
            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");
            }
4554 4555 4556 4557 4558
        } 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");
4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569
        } 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");
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 4643
        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;
}


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

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

    QEMUD_SAVE_FORMAT_LAST
4662
};
4663

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

4672 4673 4674 4675 4676
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
    int version;
    int xml_len;
    int was_running;
4677 4678
    int compressed;
    int unused[15];
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 4709
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;
}


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

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

4732
    qemuDriverLock(driver);
4733 4734

    header.compressed = compressed;
4735

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

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

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

D
Daniel P. Berrange 已提交
4750
    if (!virDomainObjIsActive(vm)) {
4751 4752
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4753
        goto endjob;
D
Daniel P. Berrange 已提交
4754
    }
4755

4756 4757 4758
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

4759 4760 4761
    /* Pause */
    if (vm->state == VIR_DOMAIN_RUNNING) {
        header.was_running = 1;
4762
        vm->state = VIR_DOMAIN_PAUSED;
4763
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4764
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
4765
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4766
            vm->state = VIR_DOMAIN_RUNNING;
4767
            goto endjob;
4768
        }
4769
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4770 4771 4772
    }

    /* Get XML for the domain */
4773
    xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
4774
    if (!xml) {
4775 4776
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
4777
        goto endjob;
4778 4779 4780
    }
    header.xml_len = strlen(xml) + 1;

4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794
    /* path might be a pre-existing block dev, in which case
     * we need to skip the create step, and also avoid unlink
     * in the failure case */
    if (stat(path, &sb) < 0) {
        /* Avoid throwing an error here, since it is possible
         * that with NFS we can't actually stat() the file.
         * The subsequent codepaths will still raise an error
         * if a truely fatal problem is hit */
        is_reg = 1;
    } else {
        is_reg = S_ISREG(sb.st_mode);
    }


4795 4796 4797 4798 4799
    /* Setup hook data needed by virFileOperation hook function */
    hdata.dom = dom;
    hdata.path = path;
    hdata.xml = xml;
    hdata.header = &header;
4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818
    offset = sizeof(header) + header.xml_len;

    /* Due to way we append QEMU state on our header with dd,
     * we need to ensure there's a 512 byte boundary. Unfortunately
     * we don't have an explicit offset in the header, so we fake
     * it by padding the XML string with NULLs */
    if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
        unsigned long long pad =
            QEMU_MONITOR_MIGRATE_TO_FILE_BS -
            (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS);

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

4820 4821
    /* Write header to file, followed by XML */

4822
    /* First try creating the file as root */
4823 4824 4825 4826
    if (!is_reg) {
        int fd = open(path, O_WRONLY | O_TRUNC);
        if (fd < 0) {
            virReportSystemError(errno, _("unable to open %s"), path);
4827 4828
            goto endjob;
        }
4829
        if (qemudDomainSaveFileOpHook(fd, &hdata) != 0) {
4830 4831 4832 4833 4834
            close(fd);
            goto endjob;
        }
        if (close(fd) < 0) {
            virReportSystemError(errno, _("unable to close %s"), path);
4835 4836
            goto endjob;
        }
4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855
    } else {
        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;
            }
4856

4857 4858 4859 4860 4861
#ifdef __linux__
            /* On Linux we can also verify the FS-type of the directory. */
            char *dirpath, *p;
            struct statfs st;
            int statfs_ret;
4862

4863 4864
            if ((dirpath = strdup(path)) == NULL) {
                virReportOOMError();
4865 4866 4867
                goto endjob;
            }

4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882
            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;
                }
4883

4884 4885 4886 4887
                if (p == dirpath)
                    *(p+1) = '\0';
                else
                    *p = '\0';
4888

4889
                statfs_ret = statfs(dirpath, &st);
4890

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

4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909
            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;
            }
4910 4911 4912
            VIR_FREE(dirpath);
#endif

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

4915 4916 4917 4918 4919 4920
            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'"),
4921
                                 path);
4922 4923
                goto endjob;
            }
4924

4925 4926 4927
            /* 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 */
4928

4929 4930
            bypassSecurityDriver = 1;
        }
4931
    }
4932

4933

4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950
    if (!is_reg &&
        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;
        }
        rc = virCgroupAllowDevicePath(cgroup, path);
        if (rc != 0) {
            virReportSystemError(-rc,
                                 _("Unable to allow device %s for %s"),
                                 path, vm->def->name);
            goto endjob;
        }
    }

4951 4952
    if ((!bypassSecurityDriver) &&
        driver->securityDriver &&
4953
        driver->securityDriver->domainSetSavedStateLabel &&
4954
        driver->securityDriver->domainSetSavedStateLabel(vm, path) == -1)
4955 4956
        goto endjob;

4957 4958
    if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = { "cat", NULL };
M
Matthias Bolte 已提交
4959
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4960 4961 4962
        rc = qemuMonitorMigrateToFile(priv->mon,
                                      QEMU_MONITOR_MIGRATE_BACKGROUND,
                                      args, path, offset);
M
Matthias Bolte 已提交
4963
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4964
    } else {
4965
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
4966 4967 4968 4969 4970
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
M
Matthias Bolte 已提交
4971
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4972 4973 4974
        rc = qemuMonitorMigrateToFile(priv->mon,
                                      QEMU_MONITOR_MIGRATE_BACKGROUND,
                                      args, path, offset);
M
Matthias Bolte 已提交
4975
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4976 4977
    }

4978 4979 4980 4981 4982
    if (rc < 0)
        goto endjob;

    rc = qemuDomainWaitForMigrationComplete(driver, vm);

4983
    if (rc < 0)
4984
        goto endjob;
4985

4986 4987
    if ((!bypassSecurityDriver) &&
        driver->securityDriver &&
4988
        driver->securityDriver->domainRestoreSavedStateLabel &&
4989
        driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1)
4990
        VIR_WARN("failed to restore save state label on %s", path);
4991

4992 4993
    if (cgroup != NULL) {
        rc = virCgroupDenyDevicePath(cgroup, path);
4994 4995 4996
        if (rc != 0)
            VIR_WARN("Unable to deny device %s for %s %d",
                     path, vm->def->name, rc);
4997 4998
    }

4999 5000
    ret = 0;

5001
    /* Shut it down */
5002
    qemudShutdownVMDaemon(driver, vm);
5003 5004 5005
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
5006
    if (!vm->persistent) {
5007 5008 5009
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
5010 5011
        vm = NULL;
    }
5012

5013
endjob:
5014
    if (vm) {
5015 5016 5017 5018 5019 5020 5021 5022 5023 5024
        if (ret != 0) {
            if (header.was_running && priv->mon) {
                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;
            }
5025

5026 5027 5028 5029 5030
            if (cgroup != NULL) {
                rc = virCgroupDenyDevicePath(cgroup, path);
                if (rc != 0)
                    VIR_WARN("Unable to deny device %s for %s: %d",
                             path, vm->def->name, rc);
5031
            }
5032 5033 5034 5035 5036 5037

            if ((!bypassSecurityDriver) &&
                driver->securityDriver &&
                driver->securityDriver->domainRestoreSavedStateLabel &&
                driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1)
                VIR_WARN("failed to restore save state label on %s", path);
5038 5039
        }

5040
        if (qemuDomainObjEndJob(vm) == 0)
5041
            vm = NULL;
5042
    }
5043

5044 5045
cleanup:
    VIR_FREE(xml);
5046
    if (ret != 0 && is_reg)
5047
        unlink(path);
5048 5049
    if (vm)
        virDomainObjUnlock(vm);
5050 5051
    if (event)
        qemuDomainEventQueue(driver, event);
5052
    virCgroupFree(&cgroup);
5053
    qemuDriverUnlock(driver);
5054
    return ret;
D
Daniel P. Berrange 已提交
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
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;

5099
    virCheckFlags(0, -1);
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 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159

    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;

5160
    virCheckFlags(0, -1);
5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193

    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;

5194
    virCheckFlags(0, -1);
5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218

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

P
Paolo Bonzini 已提交
5220 5221 5222 5223 5224 5225
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;
5226
    int ret = -1, fd = -1;
5227
    virDomainEventPtr event = NULL;
5228 5229 5230 5231
    const char *args[] = {
        "cat",
        NULL,
    };
5232
    qemuDomainObjPrivatePtr priv;
P
Paolo Bonzini 已提交
5233 5234 5235 5236 5237 5238 5239

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

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5240 5241
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
5242 5243
        goto cleanup;
    }
5244
    priv = vm->privateData;
P
Paolo Bonzini 已提交
5245

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

D
Daniel P. Berrange 已提交
5249
    if (!virDomainObjIsActive(vm)) {
5250 5251
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
5252
        goto endjob;
P
Paolo Bonzini 已提交
5253 5254
    }

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

    if (close(fd) < 0) {
5263
        virReportSystemError(errno,
5264 5265 5266 5267 5268 5269 5270
                             _("unable to save file %s"),
                             path);
        goto endjob;
    }

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSavedStateLabel &&
5271
        driver->securityDriver->domainSetSavedStateLabel(vm, path) == -1)
5272 5273
        goto endjob;

P
Paolo Bonzini 已提交
5274 5275
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
P
Paolo Bonzini 已提交
5276 5277 5278
    resume = (vm->state == VIR_DOMAIN_RUNNING);

    /* Pause domain for non-live dump */
P
Paolo Bonzini 已提交
5279
    if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
5280
        vm->state = VIR_DOMAIN_PAUSED;
5281
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5282
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
5283
            qemuDomainObjExitMonitorWithDriver(driver, vm);
5284
            vm->state = VIR_DOMAIN_RUNNING;
5285
            goto endjob;
5286
        }
5287
        qemuDomainObjExitMonitorWithDriver(driver, vm);
P
Paolo Bonzini 已提交
5288 5289 5290
        paused = 1;
    }

5291
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
5292 5293 5294
    ret = qemuMonitorMigrateToFile(priv->mon,
                                   QEMU_MONITOR_MIGRATE_BACKGROUND,
                                   args, path, 0);
5295
    qemuDomainObjExitMonitorWithDriver(driver, vm);
5296 5297 5298 5299 5300 5301 5302 5303 5304
    if (ret < 0)
        goto endjob;

    ret = qemuDomainWaitForMigrationComplete(driver, vm);

    if (ret < 0)
        goto endjob;

    paused = 1;
5305 5306 5307

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSavedStateLabel &&
5308
        driver->securityDriver->domainRestoreSavedStateLabel(vm, path) == -1)
5309 5310 5311
        goto endjob;

endjob:
5312
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
5313
        qemudShutdownVMDaemon(driver, vm);
5314 5315 5316 5317 5318
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
5319 5320 5321
    /* 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.  */
5322
    else if (resume && paused) {
5323
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5324
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
5325
            if (virGetLastError() == NULL)
5326 5327
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
5328
        }
5329
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5330
        vm->state = VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
5331
    }
5332

5333 5334
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5335
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
5336 5337 5338 5339
        virDomainRemoveInactive(&driver->domains,
                                vm);
        vm = NULL;
    }
5340 5341

cleanup:
5342 5343
    if (ret != 0)
        unlink(path);
P
Paolo Bonzini 已提交
5344 5345
    if (vm)
        virDomainObjUnlock(vm);
5346 5347
    if (event)
        qemuDomainEventQueue(driver, event);
5348
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
5349 5350 5351 5352
    return ret;
}


5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364
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 */
5365
            qemuDomainObjEnterMonitor(vm);
5366
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
5367
            qemuDomainObjExitMonitor(vm);
5368 5369 5370 5371 5372 5373 5374 5375 5376 5377
            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 */
5378
            qemuDomainObjEnterMonitor(vm);
5379
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
5380
            qemuDomainObjExitMonitor(vm);
5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402
            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) {
5403 5404
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5405 5406
    const char * type;
    int max;
5407
    int ret = -1;
5408

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

5413 5414 5415
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

5416
    if (!vm) {
5417 5418
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5419 5420
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5421
        goto endjob;
5422 5423
    }

5424 5425 5426
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
5427
        goto endjob;
5428 5429
    }

5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454
    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;
5455

5456
cleanup:
5457 5458
    if (vm)
        virDomainObjUnlock(vm);
5459
    return ret;
5460 5461
}

5462 5463 5464 5465 5466 5467

static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
5468 5469
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5470
    int maxcpu, hostcpus;
5471
    virNodeInfo nodeinfo;
5472
    int ret = -1;
5473
    qemuDomainObjPrivatePtr priv;
5474

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

5479 5480 5481
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5482 5483
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5484 5485 5486
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
5487
    if (!virDomainObjIsActive(vm)) {
5488 5489
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",_("cannot pin vcpus on an inactive domain"));
5490
        goto cleanup;
5491 5492
    }

5493 5494 5495
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
5496 5497 5498
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("vcpu number out of range %d > %d"),
                        vcpu, priv->nvcpupids);
5499
        goto cleanup;
5500 5501
    }

5502
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
5503
        goto cleanup;
5504

5505
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
5506
    maxcpu = maplen * 8;
5507 5508
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
5509

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

5521
cleanup:
5522 5523
    if (vm)
        virDomainObjUnlock(vm);
5524
    return ret;
5525 5526 5527 5528 5529 5530 5531 5532
}

static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
5533 5534
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5535
    virNodeInfo nodeinfo;
5536
    int i, v, maxcpu, hostcpus;
5537
    int ret = -1;
5538
    qemuDomainObjPrivatePtr priv;
5539

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

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

D
Daniel P. Berrange 已提交
5552
    if (!virDomainObjIsActive(vm)) {
5553 5554 5555
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",
                        _("cannot list vcpu pinning for an inactive domain"));
5556
        goto cleanup;
5557 5558
    }

5559 5560
    priv = vm->privateData;

5561
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
5562
        goto cleanup;
5563

5564
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
5565
    maxcpu = maplen * 8;
5566 5567
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
5568 5569

    /* Clamp to actual number of vcpus */
5570 5571
    if (maxinfo > priv->nvcpupids)
        maxinfo = priv->nvcpupids;
5572

5573 5574 5575 5576 5577 5578
    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;
5579

5580
                if (priv->vcpupids != NULL &&
5581 5582 5583
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
                                        vm->pid,
5584
                                        priv->vcpupids[i]) < 0) {
5585
                    virReportSystemError(errno, "%s",
5586 5587 5588
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
5589
            }
5590 5591
        }

5592 5593
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
5594
            if (priv->vcpupids != NULL) {
5595 5596 5597
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);

5598
                    if (virProcessInfoGetAffinity(priv->vcpupids[v],
5599
                                                  cpumap, maplen, maxcpu) < 0)
5600
                        goto cleanup;
5601
                }
5602
            } else {
5603 5604
                qemuReportError(VIR_ERR_NO_SUPPORT,
                                "%s", _("cpu affinity is not available"));
5605
                goto cleanup;
5606 5607 5608
            }
        }
    }
5609
    ret = maxinfo;
5610

5611
cleanup:
5612 5613
    if (vm)
        virDomainObjUnlock(vm);
5614
    return ret;
5615 5616 5617
}


5618
static int qemudDomainGetMaxVcpus(virDomainPtr dom) {
5619 5620
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5621
    const char *type;
5622
    int ret = -1;
5623

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

5628
    if (!vm) {
5629 5630
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5631 5632
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5633
        goto cleanup;
5634 5635
    }

5636
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
5637 5638 5639
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
5640
        goto cleanup;
5641 5642
    }

5643
    ret = qemudGetMaxVCPUs(NULL, type);
5644

5645
cleanup:
5646 5647
    if (vm)
        virDomainObjUnlock(vm);
5648 5649 5650
    return ret;
}

5651 5652 5653 5654 5655 5656 5657 5658 5659
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);

5660 5661
    memset(seclabel, 0, sizeof(*seclabel));

5662 5663 5664
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5665 5666
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5667 5668 5669
        goto cleanup;
    }

5670
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
5671 5672 5673
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690
        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 已提交
5691
    if (virDomainObjIsActive(vm)) {
5692
        if (driver->securityDriver && driver->securityDriver->domainGetSecurityProcessLabel) {
5693
            if (driver->securityDriver->domainGetSecurityProcessLabel(vm, seclabel) == -1) {
5694 5695
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Failed to get security label"));
5696 5697 5698 5699 5700 5701 5702 5703 5704 5705
                goto cleanup;
            }
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
5706
    qemuDriverUnlock(driver);
5707 5708 5709
    return ret;
}

5710 5711
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
5712 5713 5714
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
5715
    int ret = 0;
5716

5717
    qemuDriverLock(driver);
5718
    if (!driver->securityPrimaryDriver) {
5719
        memset(secmodel, 0, sizeof (*secmodel));
5720 5721
        goto cleanup;
    }
5722

5723 5724
    p = driver->caps->host.secModel.model;
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
5725 5726 5727
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security model string exceeds max %d bytes"),
                        VIR_SECURITY_MODEL_BUFLEN-1);
5728 5729
        ret = -1;
        goto cleanup;
5730 5731 5732 5733 5734
    }
    strcpy(secmodel->model, p);

    p = driver->caps->host.secModel.doi;
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
5735 5736 5737
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security DOI string exceeds max %d bytes"),
                        VIR_SECURITY_DOI_BUFLEN-1);
5738 5739
        ret = -1;
        goto cleanup;
5740 5741
    }
    strcpy(secmodel->doi, p);
5742 5743 5744 5745

cleanup:
    qemuDriverUnlock(driver);
    return ret;
5746 5747
}

5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879
/* 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);
}

5880
/* TODO: check seclabel restore */
5881
static int qemudDomainRestore(virConnectPtr conn,
5882 5883 5884
                              const char *path) {
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
5885
    virDomainObjPtr vm = NULL;
5886
    int fd = -1;
5887
    pid_t read_pid = -1;
5888 5889
    int ret = -1;
    char *xml = NULL;
5890
    struct qemud_save_header header;
5891
    virDomainEventPtr event = NULL;
5892 5893 5894
    int intermediatefd = -1;
    pid_t intermediate_pid = -1;
    int childstat;
5895

5896
    qemuDriverLock(driver);
5897 5898
    /* Verify the header and read the XML */
    if ((fd = open(path, O_RDONLY)) < 0) {
5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912
        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;
        }
5913 5914 5915
    }

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
5916 5917
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read qemu header"));
5918
        goto cleanup;
5919 5920 5921
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
5922 5923
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("image magic is incorrect"));
5924
        goto cleanup;
5925 5926 5927
    }

    if (header.version > QEMUD_SAVE_VERSION) {
5928 5929 5930
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("image version is not supported (%d > %d)"),
                        header.version, QEMUD_SAVE_VERSION);
5931
        goto cleanup;
5932 5933
    }

5934 5935 5936
    if (header.xml_len <= 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("invalid XML length: %d"), header.xml_len);
5937
        goto cleanup;
5938 5939
    }

5940 5941 5942 5943 5944 5945
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
5946 5947
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read XML"));
5948
        goto cleanup;
5949 5950 5951
    }

    /* Create a domain from this XML */
5952
    if (!(def = virDomainDefParseString(driver->caps, xml,
5953
                                        VIR_DOMAIN_XML_INACTIVE))) {
5954 5955
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
5956
        goto cleanup;
5957 5958
    }

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

5962
    if (!(vm = virDomainAssignDef(driver->caps,
5963
                                  &driver->domains,
5964
                                  def, true))) {
5965 5966
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to assign new VM"));
5967
        goto cleanup;
5968
    }
5969
    def = NULL;
5970

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

5974 5975
    if (header.version == 2) {
        const char *intermediate_argv[3] = { NULL, "-dc", NULL };
5976 5977
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
        if (prog == NULL) {
5978 5979 5980
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("Invalid compressed save format %d"),
                            header.compressed);
5981
            goto endjob;
5982
        }
5983

5984
        if (header.compressed != QEMUD_SAVE_FORMAT_RAW) {
5985
            intermediate_argv[0] = prog;
5986 5987
            intermediatefd = fd;
            fd = -1;
5988
            if (virExec(intermediate_argv, NULL, NULL,
5989
                        &intermediate_pid, intermediatefd, &fd, NULL, 0) < 0) {
5990 5991 5992
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Failed to start decompression binary %s"),
                                intermediate_argv[0]);
5993
                goto endjob;
5994 5995 5996
            }
        }
    }
5997
    /* Set the migration source and start it up. */
5998
    ret = qemudStartVMDaemon(conn, driver, vm, "stdio", fd);
5999 6000 6001 6002 6003 6004 6005
    if (intermediate_pid != -1) {
        /* Wait for intermediate process to exit */
        while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
               errno == EINTR);
    }
    if (intermediatefd != -1)
        close(intermediatefd);
6006
    close(fd);
6007
    fd = -1;
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
    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;
            }
        }
    }
6037
    if (ret < 0) {
6038
        if (!vm->persistent) {
6039 6040 6041
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains,
                                        vm);
6042 6043
            vm = NULL;
        }
6044
        goto endjob;
6045 6046
    }

6047 6048 6049
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
6050

6051 6052
    /* If it was running before, resume it now. */
    if (header.was_running) {
6053
        qemuDomainObjPrivatePtr priv = vm->privateData;
6054
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
6055
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
6056
            if (virGetLastError() == NULL)
6057 6058
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("failed to resume domain"));
6059 6060
            qemuDomainObjExitMonitorWithDriver(driver,vm);
            goto endjob;
6061
        }
6062
        qemuDomainObjExitMonitorWithDriver(driver, vm);
6063
        vm->state = VIR_DOMAIN_RUNNING;
6064
        virDomainSaveStatus(driver->caps, driver->stateDir, vm);
6065
    }
6066
    ret = 0;
6067

6068
endjob:
6069 6070 6071
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
6072

6073 6074 6075 6076 6077
cleanup:
    virDomainDefFree(def);
    VIR_FREE(xml);
    if (fd != -1)
        close(fd);
6078 6079 6080 6081 6082 6083 6084
    if (read_pid != 0) {
        /* reap the process that read the file */
        while ((waitpid(read_pid, NULL, 0) == -1)
               && (errno == EINTR)) {
            /* empty */
        }
    }
6085 6086
    if (vm)
        virDomainObjUnlock(vm);
6087 6088
    if (event)
        qemuDomainEventQueue(driver, event);
6089
    qemuDriverUnlock(driver);
6090
    return ret;
D
Daniel P. Berrange 已提交
6091 6092 6093
}


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


6132
static char *qemudDomainDumpXML(virDomainPtr dom,
6133
                                int flags) {
6134 6135 6136
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
6137 6138
    unsigned long balloon;
    int err;
6139

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

D
Daniel P. Berrange 已提交
6143
    if (!vm) {
6144 6145
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6146 6147
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6148
        goto cleanup;
D
Daniel P. Berrange 已提交
6149 6150
    }

6151
    /* Refresh current memory based on balloon info */
D
Daniel P. Berrange 已提交
6152
    if (virDomainObjIsActive(vm)) {
6153
        qemuDomainObjPrivatePtr priv = vm->privateData;
6154 6155 6156
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
        if (!priv->jobActive) {
6157
            if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
6158 6159
                goto cleanup;

6160
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
6161
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
6162
            qemuDomainObjExitMonitorWithDriver(driver, vm);
6163 6164 6165 6166
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
                goto cleanup;
            }
6167 6168 6169 6170 6171 6172
            if (err < 0)
                goto cleanup;
            if (err > 0)
                vm->def->memory = balloon;
            /* err == 0 indicates no balloon support, so ignore it */
        }
6173
    }
6174

6175
    ret = qemudVMDumpXML(driver, vm, flags);
6176 6177

cleanup:
6178 6179
    if (vm)
        virDomainObjUnlock(vm);
6180
    qemuDriverUnlock(driver);
6181
    return ret;
D
Daniel P. Berrange 已提交
6182 6183 6184
}


6185 6186 6187 6188
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
                                     unsigned int flags ATTRIBUTE_UNUSED) {
6189
    struct qemud_driver *driver = conn->privateData;
6190 6191 6192 6193
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
6194 6195
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
6196 6197 6198
        goto cleanup;
    }

6199
    qemuDriverLock(driver);
6200
    def = qemuParseCommandLineString(driver->caps, config);
6201
    qemuDriverUnlock(driver);
6202 6203 6204
    if (!def)
        goto cleanup;

6205
    xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
6206 6207 6208 6209 6210 6211

cleanup:
    virDomainDefFree(def);
    return xml;
}

6212 6213 6214 6215 6216 6217
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;
6218
    virDomainChrDef monConfig;
6219
    const char *emulator;
6220
    unsigned long long qemuCmdFlags;
6221 6222 6223 6224 6225 6226 6227 6228
    struct stat sb;
    const char **retargv = NULL;
    const char **retenv = NULL;
    const char **tmp;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *ret = NULL;
    int i;

6229 6230
    qemuDriverLock(driver);

6231
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
6232 6233
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
6234 6235 6236
        goto cleanup;
    }

6237
    def = virDomainDefParseString(driver->caps, xmlData, 0);
6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281
    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) {
6282
        virReportSystemError(errno,
6283 6284 6285 6286 6287 6288 6289 6290
                             _("Cannot find QEMU binary %s"),
                             emulator);
        goto cleanup;
    }

    if (qemudExtractVersionInfo(emulator,
                                NULL,
                                &qemuCmdFlags) < 0) {
6291 6292 6293
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot determine QEMU argv syntax %s"),
                        emulator);
6294 6295 6296
        goto cleanup;
    }

6297
    if (qemuPrepareMonitorChr(driver, &monConfig, def->name) < 0)
6298
        goto cleanup;
6299 6300

    if (qemudBuildCommandLine(conn, driver, def,
D
Daniel P. Berrange 已提交
6301
                              &monConfig, 0, qemuCmdFlags,
6302 6303
                              &retargv, &retenv,
                              NULL, NULL, /* Don't want it to create TAP devices */
C
Chris Lalancette 已提交
6304
                              NULL, NULL) < 0) {
6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320
        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++;
    }

6321 6322
    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
6323
        virReportOOMError();
6324
        goto cleanup;
6325
    }
6326 6327 6328 6329

    ret = virBufferContentAndReset(&buf);

cleanup:
6330
    qemuDriverUnlock(driver);
6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343
    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;
}


6344
static int qemudListDefinedDomains(virConnectPtr conn,
6345
                            char **const names, int nnames) {
6346
    struct qemud_driver *driver = conn->privateData;
6347
    int n;
6348

6349
    qemuDriverLock(driver);
6350
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
6351
    qemuDriverUnlock(driver);
6352
    return n;
D
Daniel P. Berrange 已提交
6353 6354
}

6355
static int qemudNumDefinedDomains(virConnectPtr conn) {
6356
    struct qemud_driver *driver = conn->privateData;
6357
    int n;
6358

6359
    qemuDriverLock(driver);
6360
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
6361
    qemuDriverUnlock(driver);
6362

6363
    return n;
D
Daniel P. Berrange 已提交
6364 6365 6366
}


6367
static int qemudDomainStart(virDomainPtr dom) {
6368 6369 6370
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
6371
    virDomainEventPtr event = NULL;
6372
    char *managed_save = NULL;
6373

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

6377
    if (!vm) {
6378 6379
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6380 6381
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6382
        goto cleanup;
6383 6384
    }

6385 6386 6387 6388
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
6389 6390
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is already running"));
6391 6392 6393
        goto endjob;
    }

6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422
    /*
     * 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);
    }

6423
    ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL, -1);
6424
    if (ret != -1)
6425 6426 6427
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
6428

6429
endjob:
6430 6431
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
6432

6433
cleanup:
6434
    VIR_FREE(managed_save);
6435 6436
    if (vm)
        virDomainObjUnlock(vm);
6437
    if (event)
6438
        qemuDomainEventQueue(driver, event);
6439
    qemuDriverUnlock(driver);
6440
    return ret;
D
Daniel P. Berrange 已提交
6441 6442
}

6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457
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;

6458
        if (STRNEQ(def->os.machine, machine->name))
6459 6460 6461
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
6462
            virReportOOMError();
6463 6464 6465 6466 6467 6468 6469 6470 6471
            return -1;
        }

        break;
    }

    return 0;
}

6472 6473 6474 6475 6476 6477 6478
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
    int i, nmachines = 0;

    if (qemudProbeMachineTypes(def->emulator, &machines, &nmachines) < 0) {
6479
        virReportOOMError();
6480 6481 6482 6483 6484 6485 6486
        return -1;
    }

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

6487
        if (STRNEQ(def->os.machine, machines[i]->name))
6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

6500 6501
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
6502 6503 6504 6505 6506 6507
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
6508
        virCapsGuestDomainInfoPtr info;
6509 6510 6511
        int j;

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

6514 6515 6516 6517 6518 6519 6520 6521 6522
            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;
6523 6524
        }

6525 6526 6527 6528
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
6529 6530 6531 6532
                return -1;
            goto out;
        }
    }
6533 6534 6535 6536

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

6537 6538 6539 6540 6541 6542 6543
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
6544

6545
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
6546
    struct qemud_driver *driver = conn->privateData;
6547
    virDomainDefPtr def;
6548
    virDomainObjPtr vm = NULL;
6549
    virDomainPtr dom = NULL;
6550
    virDomainEventPtr event = NULL;
6551
    int dupVM;
6552

6553
    qemuDriverLock(driver);
6554
    if (!(def = virDomainDefParseString(driver->caps, xml,
6555
                                        VIR_DOMAIN_XML_INACTIVE)))
6556
        goto cleanup;
6557

6558
    if (virSecurityDriverVerify(def) < 0)
6559 6560
        goto cleanup;

6561 6562
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
6563

6564
    if (qemudCanonicalizeMachine(driver, def) < 0)
6565 6566
        goto cleanup;

6567 6568 6569
    if (qemuAssignPCIAddresses(def) < 0)
        goto cleanup;

6570
    if (!(vm = virDomainAssignDef(driver->caps,
6571
                                  &driver->domains,
6572
                                  def, false))) {
6573
        goto cleanup;
6574
    }
6575
    def = NULL;
6576
    vm->persistent = 1;
6577

6578
    if (virDomainSaveConfig(driver->configDir,
6579
                            vm->newDef ? vm->newDef : vm->def) < 0) {
6580 6581
        virDomainRemoveInactive(&driver->domains,
                                vm);
6582
        vm = NULL;
6583
        goto cleanup;
6584 6585
    }

6586 6587
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
6588
                                     !dupVM ?
6589 6590
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
6591

6592
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
6593
    if (dom) dom->id = vm->def->id;
6594 6595

cleanup:
6596
    virDomainDefFree(def);
6597 6598
    if (vm)
        virDomainObjUnlock(vm);
6599 6600
    if (event)
        qemuDomainEventQueue(driver, event);
6601
    qemuDriverUnlock(driver);
6602
    return dom;
D
Daniel P. Berrange 已提交
6603 6604
}

6605
static int qemudDomainUndefine(virDomainPtr dom) {
6606 6607
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6608
    virDomainEventPtr event = NULL;
6609
    int ret = -1;
D
Daniel P. Berrange 已提交
6610

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

D
Daniel P. Berrange 已提交
6614
    if (!vm) {
6615 6616
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6617 6618
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6619
        goto cleanup;
D
Daniel P. Berrange 已提交
6620 6621
    }

D
Daniel P. Berrange 已提交
6622
    if (virDomainObjIsActive(vm)) {
6623 6624
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot delete active domain"));
6625
        goto cleanup;
D
Daniel P. Berrange 已提交
6626 6627
    }

6628
    if (!vm->persistent) {
6629 6630
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot undefine transient domain"));
6631
        goto cleanup;
6632 6633
    }

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

6637 6638 6639
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
6640

6641 6642
    virDomainRemoveInactive(&driver->domains,
                            vm);
6643
    vm = NULL;
6644
    ret = 0;
D
Daniel P. Berrange 已提交
6645

6646
cleanup:
6647 6648
    if (vm)
        virDomainObjUnlock(vm);
6649 6650
    if (event)
        qemuDomainEventQueue(driver, event);
6651
    qemuDriverUnlock(driver);
6652
    return ret;
D
Daniel P. Berrange 已提交
6653 6654
}

6655

6656
static int qemudDomainChangeEjectableMedia(struct qemud_driver *driver,
6657
                                           virDomainObjPtr vm,
6658 6659
                                           virDomainDiskDefPtr disk,
                                           unsigned long long qemuCmdFlags)
6660
{
6661
    virDomainDiskDefPtr origdisk = NULL;
6662
    int i;
6663
    int ret;
6664
    char *driveAlias = NULL;
6665

6666
    origdisk = NULL;
6667
    for (i = 0 ; i < vm->def->ndisks ; i++) {
6668 6669
        if (vm->def->disks[i]->bus == disk->bus &&
            STREQ(vm->def->disks[i]->dst, disk->dst)) {
6670
            origdisk = vm->def->disks[i];
6671
            break;
6672
        }
6673 6674 6675
    }

    if (!origdisk) {
6676 6677 6678 6679
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No device with bus '%s' and target '%s'"),
                        virDomainDiskBusTypeToString(disk->bus),
                        disk->dst);
6680 6681 6682
        return -1;
    }

6683
    if (!origdisk->info.alias) {
6684 6685
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), origdisk->dst);
6686 6687
        return -1;
    }
6688

6689 6690
    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
6691 6692 6693
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Removable media not supported for %s device"),
                        virDomainDiskDeviceTypeToString(disk->device));
6694
        return -1;
6695
    }
6696

6697 6698
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
6699
        driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0)
6700 6701
        return -1;

6702 6703 6704
    if (!(driveAlias = qemuDeviceDriveHostAlias(origdisk, qemuCmdFlags)))
        goto error;

6705
    qemuDomainObjPrivatePtr priv = vm->privateData;
6706
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6707
    if (disk->src) {
6708
        const char *format = NULL;
6709 6710 6711
        if (disk->type != VIR_DOMAIN_DISK_TYPE_DIR) {
            if (disk->driverType)
                format = disk->driverType;
6712 6713 6714
            else if (origdisk->driverType)
                format = origdisk->driverType;
        }
6715
        ret = qemuMonitorChangeMedia(priv->mon,
6716
                                     driveAlias,
6717
                                     disk->src, format);
6718
    } else {
6719
        ret = qemuMonitorEjectMedia(priv->mon, driveAlias);
6720
    }
6721
    qemuDomainObjExitMonitorWithDriver(driver, vm);
6722

6723 6724 6725 6726 6727
    if (ret < 0)
        goto error;

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
6728
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, origdisk) < 0)
6729 6730 6731
        VIR_WARN("Unable to restore security label on ejected image %s", origdisk->src);

    VIR_FREE(origdisk->src);
6732 6733 6734 6735
    origdisk->src = disk->src;
    disk->src = NULL;
    origdisk->type = disk->type;

6736 6737
    VIR_FREE(driveAlias);

6738
    virDomainDiskDefFree(disk);
6739

6740
    return ret;
6741 6742

error:
6743
    VIR_FREE(driveAlias);
6744 6745
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
6746
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0)
6747
        VIR_WARN("Unable to restore security label on new media %s", disk->src);
6748
    return -1;
6749 6750
}

6751

6752
static int qemudDomainAttachPciDiskDevice(struct qemud_driver *driver,
6753
                                          virDomainObjPtr vm,
6754 6755
                                          virDomainDiskDefPtr disk,
                                          int qemuCmdFlags)
6756
{
6757
    int i, ret;
6758
    const char* type = virDomainDiskBusTypeToString(disk->bus);
6759
    qemuDomainObjPrivatePtr priv = vm->privateData;
6760 6761
    char *devstr = NULL;
    char *drivestr = NULL;
6762 6763

    for (i = 0 ; i < vm->def->ndisks ; i++) {
6764
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
6765 6766
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
6767 6768 6769 6770
            return -1;
        }
    }

6771 6772
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
6773
        driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0)
6774 6775
        return -1;

6776
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
6777 6778
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
            goto error;
6779 6780
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
6781

6782 6783 6784
        if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
            goto error;

6785
        if (!(devstr = qemuBuildDriveDevStr(disk)))
6786 6787 6788
            goto error;
    }

6789
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
6790
        virReportOOMError();
6791
        goto error;
6792 6793
    }

6794
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810
    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));
        }
    }
6811
    qemuDomainObjExitMonitorWithDriver(driver, vm);
6812

6813 6814
    if (ret < 0)
        goto error;
6815

6816
    virDomainDiskInsertPreAlloced(vm->def, disk);
6817

6818 6819 6820
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

6821 6822 6823
    return 0;

error:
6824 6825 6826
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

6827 6828 6829 6830 6831
    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);

6832 6833
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
6834
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0)
6835
        VIR_WARN("Unable to restore security label on %s", disk->src);
6836 6837

    return -1;
6838
}
6839

6840

6841
static int qemudDomainAttachPciControllerDevice(struct qemud_driver *driver,
6842
                                                virDomainObjPtr vm,
6843 6844
                                                virDomainControllerDefPtr controller,
                                                int qemuCmdFlags)
6845
{
6846 6847
    int i;
    int ret = -1;
6848
    const char* type = virDomainControllerTypeToString(controller->type);
6849
    char *devstr = NULL;
6850 6851 6852
    qemuDomainObjPrivatePtr priv = vm->privateData;

    for (i = 0 ; i < vm->def->ncontrollers ; i++) {
6853 6854
        if ((vm->def->controllers[i]->type == controller->type) &&
            (vm->def->controllers[i]->idx == controller->idx)) {
6855 6856 6857
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s:%d already exists"),
                            type, controller->idx);
6858 6859 6860 6861
            return -1;
        }
    }

6862 6863 6864 6865 6866 6867
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
            goto cleanup;
        if (qemuAssignDeviceControllerAlias(controller) < 0)
            goto cleanup;
    }
6868

6869
    if (!(devstr = qemuBuildControllerDevStr(controller))) {
6870
        virReportOOMError();
6871 6872 6873
        goto cleanup;
    }

6874
    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) {
6875
        virReportOOMError();
6876
        goto cleanup;
6877 6878 6879
    }

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6880 6881 6882 6883 6884 6885 6886
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    } else {
        ret = qemuMonitorAttachPCIDiskController(priv->mon,
                                                 type,
                                                 &controller->info.addr.pci);
    }
6887 6888 6889
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (ret == 0) {
6890 6891
        controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
        virDomainControllerInsertPreAlloced(vm->def, controller);
6892 6893
    }

6894
cleanup:
6895 6896 6897 6898 6899 6900
    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");

6901
    VIR_FREE(devstr);
6902 6903 6904
    return ret;
}

6905

6906
static virDomainControllerDefPtr
6907
qemuDomainFindOrCreateSCSIDiskController(struct qemud_driver *driver,
6908
                                         virDomainObjPtr vm,
6909 6910
                                         int controller,
                                         int qemuCmdFlags)
6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923
{
    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 已提交
6924
    /* No SCSI controller present, for backward compatibility we
6925 6926
     * now hotplug a controller */
    if (VIR_ALLOC(cont) < 0) {
6927
        virReportOOMError();
6928 6929 6930 6931 6932 6933
        return NULL;
    }
    cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
    cont->idx = 0;

    VIR_INFO0("No SCSI controller present, hotplugging one");
6934
    if (qemudDomainAttachPciControllerDevice(driver,
6935
                                             vm, cont, qemuCmdFlags) < 0) {
6936 6937 6938 6939 6940 6941
        VIR_FREE(cont);
        return NULL;
    }
    return cont;
}

6942

6943
static int qemudDomainAttachSCSIDisk(struct qemud_driver *driver,
6944
                                     virDomainObjPtr vm,
6945
                                     virDomainDiskDefPtr disk,
6946 6947 6948 6949
                                     int qemuCmdFlags)
{
    int i;
    qemuDomainObjPrivatePtr priv = vm->privateData;
6950
    virDomainControllerDefPtr cont = NULL;
6951
    char *drivestr = NULL;
6952
    char *devstr = NULL;
6953 6954 6955
    int ret = -1;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
6956
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
6957 6958
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
6959
            return -1;
6960 6961 6962
        }
    }

6963 6964 6965

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
6966
        driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0)
6967 6968
        return -1;

6969
    /* We should have an address already, so make sure */
6970
    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
6971 6972 6973
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected disk address type %s"),
                        virDomainDeviceAddressTypeToString(disk->info.type));
6974
        goto error;
6975 6976
    }

6977 6978 6979
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
6980
        if (!(devstr = qemuBuildDriveDevStr(disk)))
6981 6982 6983 6984 6985 6986
            goto error;
    }

    if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
        goto error;

6987
    for (i = 0 ; i <= disk->info.addr.drive.controller ; i++) {
6988
        cont = qemuDomainFindOrCreateSCSIDiskController(driver, vm, i, qemuCmdFlags);
6989
        if (!cont)
6990
            goto error;
6991 6992
    }

6993 6994 6995 6996 6997
    /* Tell clang that "cont" is non-NULL.
       This is because disk->info.addr.driver.controller is unsigned,
       and hence the above loop must iterate at least once.  */
    sa_assert (cont);

6998
    if (cont->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
6999 7000
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("SCSI controller %d was missing its PCI address"), cont->idx);
7001
        goto error;
7002 7003 7004
    }

    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
7005
        virReportOOMError();
7006
        goto error;
7007 7008 7009
    }

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029
    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));
        }
    }
7030 7031
    qemuDomainObjExitMonitorWithDriver(driver, vm);

7032 7033
    if (ret < 0)
        goto error;
7034

7035
    virDomainDiskInsertPreAlloced(vm->def, disk);
7036 7037

    VIR_FREE(devstr);
7038
    VIR_FREE(drivestr);
7039 7040 7041 7042

    return 0;

error:
7043
    VIR_FREE(devstr);
7044
    VIR_FREE(drivestr);
7045

7046 7047
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7048
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0)
7049
        VIR_WARN("Unable to restore security label on %s", disk->src);
7050 7051

    return -1;
7052 7053
}

7054

7055
static int qemudDomainAttachUsbMassstorageDevice(struct qemud_driver *driver,
7056
                                                 virDomainObjPtr vm,
7057 7058
                                                 virDomainDiskDefPtr disk,
                                                 int qemuCmdFlags)
7059
{
7060
    qemuDomainObjPrivatePtr priv = vm->privateData;
7061
    int i, ret;
7062 7063
    char *drivestr = NULL;
    char *devstr = NULL;
7064

7065
    for (i = 0 ; i < vm->def->ndisks ; i++) {
7066
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
7067 7068
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
7069 7070 7071 7072
            return -1;
        }
    }

7073 7074
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
7075
        driver->securityDriver->domainSetSecurityImageLabel(vm, disk) < 0)
7076 7077
        return -1;

7078
    if (!disk->src) {
7079 7080
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("disk source path is missing"));
7081
        goto error;
7082 7083
    }

7084
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7085 7086
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
7087 7088
        if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
            goto error;
7089
        if (!(devstr = qemuBuildDriveDevStr(disk)))
7090 7091 7092
            goto error;
    }

7093
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
7094
        virReportOOMError();
7095
        goto error;
7096 7097
    }

7098
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7099 7100 7101 7102 7103 7104 7105 7106 7107 7108
    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);
    }
7109
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7110

7111 7112 7113
    if (ret < 0)
        goto error;

7114
    virDomainDiskInsertPreAlloced(vm->def, disk);
7115

7116 7117 7118
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7119 7120 7121
    return 0;

error:
7122 7123 7124
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7125 7126
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7127
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, disk) < 0)
7128
        VIR_WARN("Unable to restore security label on %s", disk->src);
7129 7130

    return -1;
7131 7132
}

7133

7134
/* XXX conn required for network -> bridge resolution */
M
Mark McLoughlin 已提交
7135
static int qemudDomainAttachNetDevice(virConnectPtr conn,
7136
                                      struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7137
                                      virDomainObjPtr vm,
7138
                                      virDomainNetDefPtr net,
7139
                                      unsigned long long qemuCmdFlags)
M
Mark McLoughlin 已提交
7140
{
7141
    qemuDomainObjPrivatePtr priv = vm->privateData;
7142
    char *tapfd_name = NULL;
7143
    int tapfd = -1;
7144
    char *nicstr = NULL;
7145
    char *netstr = NULL;
7146
    int ret = -1;
7147
    virDomainDevicePCIAddress guestAddr;
7148
    int vlan;
M
Mark McLoughlin 已提交
7149 7150

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
7151 7152
        qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                        _("installed qemu version does not support host_net_add"));
M
Mark McLoughlin 已提交
7153 7154 7155 7156 7157
        return -1;
    }

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
7158
        if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
7159 7160 7161 7162
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("network device type '%s' cannot be attached: "
                              "qemu is not using a unix socket monitor"),
                            virDomainNetTypeToString(net->type));
7163 7164 7165 7166 7167
            return -1;
        }

        if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
            return -1;
7168 7169 7170 7171 7172 7173 7174 7175 7176
    } 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 已提交
7177
        if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
7178
                                           net->data.direct.linkdev,
7179 7180
                                           net->data.direct.mode,
                                           qemuCmdFlags)) < 0)
7181
            return -1;
M
Mark McLoughlin 已提交
7182 7183
    }

7184 7185
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
        goto no_memory;
M
Mark McLoughlin 已提交
7186

7187 7188 7189 7190 7191
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
            goto cleanup;
    }
M
Mark McLoughlin 已提交
7192

7193 7194 7195 7196
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
        goto cleanup;

7197
    vlan = qemuDomainNetVLAN(net);
M
Mark McLoughlin 已提交
7198

7199
    if (vlan < 0) {
7200 7201
        qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                        _("Unable to attach network devices without vlan"));
7202 7203 7204
        goto cleanup;
    }

7205
    if (tapfd != -1) {
7206
        if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0)
7207 7208
            goto no_memory;

7209
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7210
        if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0) {
7211
            qemuDomainObjExitMonitorWithDriver(driver, vm);
7212
            goto cleanup;
7213
        }
7214
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7215 7216
    }

7217
    /* FIXME - need to support vhost-net here (5th arg) */
7218 7219 7220 7221 7222 7223 7224 7225 7226 7227
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (!(netstr = qemuBuildHostNetStr(net, ',',
                                           -1, tapfd_name, 0)))
            goto try_tapfd_close;
    } else {
        if (!(netstr = qemuBuildHostNetStr(net, ' ',
                                           vlan, tapfd_name, 0)))
            goto try_tapfd_close;
    }
M
Mark McLoughlin 已提交
7228

7229
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7230
    if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
7231
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7232
        goto try_tapfd_close;
7233
    }
7234
    qemuDomainObjExitMonitorWithDriver(driver, vm);
M
Mark McLoughlin 已提交
7235

7236 7237 7238
    if (tapfd != -1)
        close(tapfd);
    tapfd = -1;
M
Mark McLoughlin 已提交
7239

7240 7241 7242 7243 7244 7245 7246
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (!(nicstr = qemuBuildNicDevStr(net, vlan)))
            goto try_remove;
    } else {
        if (!(nicstr = qemuBuildNicStr(net, NULL, vlan)))
            goto try_remove;
    }
M
Mark McLoughlin 已提交
7247

7248
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto try_remove;
        }
    } else {
        if (qemuMonitorAddPCINetwork(priv->mon, nicstr,
                                     &guestAddr) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto try_remove;
        }
        net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
        memcpy(&net->info.addr.pci, &guestAddr, sizeof(guestAddr));
7262
    }
7263
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7264

7265
    ret = 0;
M
Mark McLoughlin 已提交
7266 7267 7268

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

7269
cleanup:
7270 7271 7272 7273 7274 7275
    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");

7276 7277
    if (ret != 0)
        virNWFilterTearNWFilter(net);
S
Stefan Berger 已提交
7278

7279 7280 7281 7282 7283
    VIR_FREE(nicstr);
    VIR_FREE(netstr);
    VIR_FREE(tapfd_name);
    if (tapfd != -1)
        close(tapfd);
7284

7285
    return ret;
7286

7287
try_remove:
7288
    if (vlan < 0) {
7289
        VIR_WARN0(_("Unable to remove network backend"));
7290 7291 7292 7293
    } else {
        char *hostnet_name;
        if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
            goto no_memory;
7294
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7295
        if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
7296
            VIR_WARN(_("Failed to remove network backend for vlan %d, net %s"),
7297
                     vlan, hostnet_name);
7298
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7299
        VIR_FREE(hostnet_name);
7300
    }
7301
    goto cleanup;
7302

7303
try_tapfd_close:
7304
    if (tapfd_name) {
7305
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7306
        if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
7307
            VIR_WARN(_("Failed to close tapfd with '%s'"), tapfd_name);
7308
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7309
    }
7310

7311 7312
    goto cleanup;

7313
no_memory:
7314
    virReportOOMError();
7315
    goto cleanup;
M
Mark McLoughlin 已提交
7316 7317
}

7318

7319
static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
7320
                                          virDomainObjPtr vm,
7321 7322
                                          virDomainHostdevDefPtr hostdev,
                                          int qemuCmdFlags)
7323
{
7324
    qemuDomainObjPrivatePtr priv = vm->privateData;
7325
    pciDevice *pci;
7326
    int ret;
7327
    virDomainDevicePCIAddress guestAddr;
7328
    char *devstr = NULL;
7329 7330

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

7335
    pci = pciGetDevice(hostdev->source.subsys.u.pci.domain,
7336 7337 7338
                       hostdev->source.subsys.u.pci.bus,
                       hostdev->source.subsys.u.pci.slot,
                       hostdev->source.subsys.u.pci.function);
7339
    if (!pci)
7340
        return -1;
7341

7342 7343 7344 7345
    if (!pciDeviceIsAssignable(pci, !driver->relaxedACS) ||
        (hostdev->managed && pciDettachDevice(pci) < 0) ||
        pciResetDevice(pci, driver->activePciHostdevs) < 0) {
        pciFreeDevice(pci);
7346 7347 7348
        return -1;
    }

7349 7350
    if (pciDeviceListAdd(driver->activePciHostdevs, pci) < 0) {
        pciFreeDevice(pci);
7351
        return -1;
7352 7353
    }

7354
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7355 7356
        if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
            goto error;
7357 7358 7359 7360 7361 7362
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
            goto error;

        if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev)))
            goto error;
    }
7363

7364
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7365 7366 7367 7368 7369 7370
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    else
        ret = qemuMonitorAddPCIHostDevice(priv->mon,
                                          &hostdev->source.subsys.u.pci,
                                          &guestAddr);
7371
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7372
    if (ret < 0)
7373
        goto error;
7374
    hostdev->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
7375
    memcpy(&hostdev->info.addr.pci, &guestAddr, sizeof(guestAddr));
7376 7377 7378

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

7379 7380
    VIR_FREE(devstr);

7381
    return 0;
7382 7383

error:
7384 7385 7386 7387 7388
    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");

7389
    VIR_FREE(devstr);
7390
    pciDeviceListDel(driver->activePciHostdevs, pci);
7391 7392

    return -1;
7393 7394
}

7395

7396
static int qemudDomainAttachHostUsbDevice(struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7397
                                          virDomainObjPtr vm,
7398 7399
                                          virDomainHostdevDefPtr hostdev,
                                          int qemuCmdFlags)
7400 7401
{
    int ret;
7402
    qemuDomainObjPrivatePtr priv = vm->privateData;
7403 7404
    char *devstr = NULL;

7405 7406 7407 7408 7409 7410
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
            goto error;
        if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
            goto error;
    }
7411

7412
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
7413
        virReportOOMError();
7414
        goto error;
7415
    }
7416

7417
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7418 7419 7420
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    else
7421
        ret = qemuMonitorAddUSBDeviceExact(priv->mon,
7422 7423
                                           hostdev->source.subsys.u.usb.bus,
                                           hostdev->source.subsys.u.usb.device);
7424
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7425 7426 7427 7428
    if (ret < 0)
        goto error;

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

7430
    VIR_FREE(devstr);
7431

7432 7433 7434 7435 7436
    return 0;

error:
    VIR_FREE(devstr);
    return -1;
7437 7438
}

7439

7440
static int qemudDomainAttachHostDevice(struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7441
                                       virDomainObjPtr vm,
7442 7443
                                       virDomainHostdevDefPtr hostdev,
                                       int qemuCmdFlags)
M
Mark McLoughlin 已提交
7444 7445
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
7446 7447 7448
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev mode '%s' not supported"),
                        virDomainHostdevModeTypeToString(hostdev->mode));
M
Mark McLoughlin 已提交
7449 7450 7451
        return -1;
    }

7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468
    /* 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);
    }


7469
    if (driver->securityDriver &&
7470
        driver->securityDriver->domainSetSecurityHostdevLabel &&
7471
        driver->securityDriver->domainSetSecurityHostdevLabel(vm, hostdev) < 0)
7472
        return -1;
M
Mark McLoughlin 已提交
7473 7474

    switch (hostdev->source.subsys.type) {
7475
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
7476
        if (qemudDomainAttachHostPciDevice(driver, vm,
7477
                                           hostdev, qemuCmdFlags) < 0)
7478 7479 7480
            goto error;
        break;

M
Mark McLoughlin 已提交
7481
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
7482
        if (qemudDomainAttachHostUsbDevice(driver, vm,
7483
                                           hostdev, qemuCmdFlags) < 0)
7484 7485 7486
            goto error;
        break;

M
Mark McLoughlin 已提交
7487
    default:
7488 7489 7490
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev subsys type '%s' not supported"),
                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
7491
        goto error;
M
Mark McLoughlin 已提交
7492
    }
7493 7494 7495 7496 7497 7498

    return 0;

error:
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityHostdevLabel &&
7499
        driver->securityDriver->domainRestoreSecurityHostdevLabel(vm, hostdev) < 0)
7500 7501 7502
        VIR_WARN0("Unable to restore host device labelling on hotplug fail");

    return -1;
M
Mark McLoughlin 已提交
7503 7504
}

7505

7506
static int qemudDomainAttachDevice(virDomainPtr dom,
7507 7508
                                   const char *xml)
{
7509 7510 7511
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
7512
    unsigned long long qemuCmdFlags;
7513
    virCgroupPtr cgroup = NULL;
7514
    int ret = -1;
7515

7516
    qemuDriverLock(driver);
7517
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
7518
    if (!vm) {
7519 7520
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7521 7522
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7523
        goto cleanup;
7524 7525
    }

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

D
Daniel P. Berrange 已提交
7529
    if (!virDomainObjIsActive(vm)) {
7530 7531
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot attach device on inactive domain"));
7532
        goto endjob;
7533 7534
    }

7535
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
7536
                                  VIR_DOMAIN_XML_INACTIVE);
7537
    if (dev == NULL)
7538
        goto endjob;
7539

7540 7541 7542
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
7543
        goto endjob;
7544

7545
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
7546
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
7547
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
7548 7549 7550
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Unable to find cgroup for %s\n"),
                                vm->def->name);
7551
                goto endjob;
7552 7553 7554 7555 7556
            }
            if (dev->data.disk->src != NULL &&
                dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
                virCgroupAllowDevicePath(cgroup,
                                         dev->data.disk->src) < 0) {
7557 7558 7559
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unable to allow device %s"),
                                dev->data.disk->src);
7560
                goto endjob;
7561 7562 7563
            }
        }

7564
        switch (dev->data.disk->device) {
7565 7566
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
7567 7568 7569
            ret = qemudDomainChangeEjectableMedia(driver, vm,
                                                  dev->data.disk,
                                                  qemuCmdFlags);
7570 7571
            if (ret == 0)
                dev->data.disk = NULL;
7572
            break;
7573

7574 7575
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
7576
                ret = qemudDomainAttachUsbMassstorageDevice(driver, vm,
7577
                                                            dev->data.disk, qemuCmdFlags);
7578 7579
                if (ret == 0)
                    dev->data.disk = NULL;
7580
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
7581
                ret = qemudDomainAttachPciDiskDevice(driver, vm,
7582
                                                     dev->data.disk, qemuCmdFlags);
7583 7584
                if (ret == 0)
                    dev->data.disk = NULL;
7585
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
7586
                ret = qemudDomainAttachSCSIDisk(driver, vm,
7587
                                                dev->data.disk, qemuCmdFlags);
7588 7589
                if (ret == 0)
                    dev->data.disk = NULL;
7590
            } else {
7591 7592 7593
                qemuReportError(VIR_ERR_NO_SUPPORT,
                                _("disk bus '%s' cannot be hotplugged."),
                                virDomainDiskBusTypeToString(dev->data.disk->bus));
7594
                /* fallthrough */
7595 7596
            }
            break;
7597

7598
        default:
7599 7600 7601
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk device type '%s' cannot be hotplugged"),
                            virDomainDiskDeviceTypeToString(dev->data.disk->device));
7602 7603
            /* Fallthrough */
        }
7604
        if (ret != 0 && cgroup) {
7605 7606
            virCgroupDenyDevicePath(cgroup,
                                    dev->data.disk->src);
7607
        }
7608 7609
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
7610
            ret = qemudDomainAttachPciControllerDevice(driver, vm,
7611
                                                       dev->data.controller, qemuCmdFlags);
7612 7613
            if (ret == 0)
                dev->data.controller = NULL;
7614
        } else {
7615 7616 7617
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk controller bus '%s' cannot be hotplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
7618 7619
            /* fallthrough */
        }
M
Mark McLoughlin 已提交
7620
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
7621 7622
        ret = qemudDomainAttachNetDevice(dom->conn, driver, vm,
                                         dev->data.net, qemuCmdFlags);
7623 7624
        if (ret == 0)
            dev->data.net = NULL;
M
Mark McLoughlin 已提交
7625
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
7626
        ret = qemudDomainAttachHostDevice(driver, vm,
7627
                                          dev->data.hostdev, qemuCmdFlags);
7628 7629
        if (ret == 0)
            dev->data.hostdev = NULL;
7630
    } else {
7631 7632 7633
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("device type '%s' cannot be attached"),
                        virDomainDeviceTypeToString(dev->type));
7634
        goto endjob;
7635 7636
    }

7637
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
7638 7639
        ret = -1;

7640
endjob:
7641 7642
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
7643

7644
cleanup:
7645 7646 7647
    if (cgroup)
        virCgroupFree(&cgroup);

7648
    virDomainDeviceDefFree(dev);
7649 7650
    if (vm)
        virDomainObjUnlock(vm);
7651
    qemuDriverUnlock(driver);
7652 7653 7654
    return ret;
}

7655 7656 7657 7658
static int qemudDomainAttachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
7659 7660
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
7661 7662 7663 7664 7665 7666
        return -1;
    }

    return qemudDomainAttachDevice(dom, xml);
}

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 7710 7711 7712 7713 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 7740 7741 7742 7743 7744
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;
}


7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755
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;

7756 7757 7758 7759
    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_CURRENT |
                  VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817
    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:
7818 7819 7820
            ret = qemudDomainChangeEjectableMedia(driver, vm,
                                                  dev->data.disk,
                                                  qemuCmdFlags);
7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838
            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;

7839 7840 7841 7842
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;

7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868
    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;
}


E
Eric Blake 已提交
7869
static inline int qemudFindDisk(virDomainDefPtr def, const char *dst)
W
Wolfgang Mauerer 已提交
7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881
{
    int i;

    for (i = 0 ; i < def->ndisks ; i++) {
        if (STREQ(def->disks[i]->dst, dst)) {
            return i;
        }
    }

    return -1;
}

E
Eric Blake 已提交
7882
static inline void qemudShrinkDisks(virDomainDefPtr def, size_t i)
W
Wolfgang Mauerer 已提交
7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898
{
    if (def->ndisks > 1) {
        memmove(def->disks + i,
                def->disks + i + 1,
                sizeof(*def->disks) *
                (def->ndisks - (i + 1)));
        def->ndisks--;
        if (VIR_REALLOC_N(def->disks, def->ndisks) < 0) {
            /* ignore, harmless */
        }
    } else {
        VIR_FREE(def->disks);
        def->ndisks = 0;
    }
}

7899
static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
7900
                                          virDomainObjPtr vm,
7901 7902
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
7903 7904 7905
{
    int i, ret = -1;
    virDomainDiskDefPtr detach = NULL;
7906
    qemuDomainObjPrivatePtr priv = vm->privateData;
7907

W
Wolfgang Mauerer 已提交
7908
    i = qemudFindDisk(vm->def, dev->data.disk->dst);
7909

W
Wolfgang Mauerer 已提交
7910
    if (i < 0) {
7911 7912
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk %s not found"), dev->data.disk->dst);
7913
        goto cleanup;
7914 7915
    }

W
Wolfgang Mauerer 已提交
7916 7917
    detach = vm->def->disks[i];

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
        goto cleanup;
7923 7924
    }

7925
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936
    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;
        }
7937
    }
7938
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7939

W
Wolfgang Mauerer 已提交
7940 7941
    qemudShrinkDisks(vm->def, i);

7942
    virDomainDiskDefFree(detach);
7943

7944 7945
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7946
        driver->securityDriver->domainRestoreSecurityImageLabel(vm, dev->data.disk) < 0)
7947 7948
        VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);

7949
    ret = 0;
7950 7951

cleanup:
7952 7953 7954
    return ret;
}

7955
static int qemudDomainDetachPciControllerDevice(struct qemud_driver *driver,
7956
                                                virDomainObjPtr vm,
7957 7958
                                                virDomainDeviceDefPtr dev,
                                                unsigned long long qemuCmdFlags)
7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972
{
    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) {
7973 7974 7975 7976
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk controller %s:%d not found"),
                        virDomainControllerTypeToString(dev->data.controller->type),
                        dev->data.controller->idx);
7977 7978 7979 7980 7981
        goto cleanup;
    }

    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
7982 7983
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("device cannot be detached without a PCI address"));
7984 7985 7986
        goto cleanup;
    }

7987 7988 7989 7990 7991
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceControllerAlias(detach) < 0)
            goto cleanup;
    }

7992
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003
    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;
        }
8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019
    }
    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;
    }
8020 8021 8022 8023 8024

    if (qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0) {
        VIR_WARN0("Unable to release PCI address on controller");
    }

8025 8026 8027 8028 8029 8030 8031 8032
    virDomainControllerDefFree(detach);

    ret = 0;

cleanup:
    return ret;
}

8033
static int
8034
qemudDomainDetachNetDevice(struct qemud_driver *driver,
8035
                           virDomainObjPtr vm,
8036 8037
                           virDomainDeviceDefPtr dev,
                           unsigned long long qemuCmdFlags)
8038 8039 8040
{
    int i, ret = -1;
    virDomainNetDefPtr detach = NULL;
8041
    qemuDomainObjPrivatePtr priv = vm->privateData;
8042 8043
    int vlan;
    char *hostnet_name = NULL;
8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054

    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) {
8055 8056 8057 8058 8059
        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]);
8060 8061 8062
        goto cleanup;
    }

8063 8064
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
8065 8066
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a PCI address"));
8067 8068 8069
        goto cleanup;
    }

8070
    if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
8071 8072
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("unable to determine original VLAN"));
8073 8074 8075 8076
        goto cleanup;
    }

    if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) {
8077
        virReportOOMError();
8078 8079 8080
        goto cleanup;
    }

8081
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092
    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;
        }
8093
    }
8094

8095
    if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
8096
        qemuDomainObjExitMonitorWithDriver(driver, vm);
8097
        goto cleanup;
8098
    }
8099
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8100

8101 8102
    virNWFilterTearNWFilter(detach);

8103 8104
#if WITH_MACVTAP
    if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
S
Stefan Berger 已提交
8105 8106
        if (detach->ifname)
            delMacvtap(detach->ifname);
8107 8108 8109
    }
#endif

8110
    if ((driver->macFilter) && (detach->ifname != NULL)) {
8111
        if ((errno = networkDisallowMacOnPort(driver,
8112 8113
                                              detach->ifname,
                                              detach->mac))) {
8114
            virReportSystemError(errno,
8115 8116 8117 8118 8119
             _("failed to remove ebtables rule on  '%s'"),
                                 detach->ifname);
        }
    }

8120 8121 8122 8123 8124 8125 8126 8127 8128 8129
    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 {
8130
        VIR_FREE(vm->def->nets);
8131
        vm->def->nnets = 0;
8132
    }
8133
    virDomainNetDefFree(detach);
8134

8135 8136 8137
    ret = 0;

cleanup:
8138
    VIR_FREE(hostnet_name);
8139 8140 8141
    return ret;
}

8142
static int qemudDomainDetachHostPciDevice(struct qemud_driver *driver,
8143
                                          virDomainObjPtr vm,
8144 8145
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
8146
{
8147
    virDomainHostdevDefPtr detach = NULL;
8148
    qemuDomainObjPrivatePtr priv = vm->privateData;
8149
    int i, ret;
8150
    pciDevice *pci;
8151 8152

    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
8153 8154 8155 8156
        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;

8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171
        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) {
8172 8173 8174 8175 8176 8177
        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);
8178 8179 8180
        return -1;
    }

8181 8182
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
8183 8184
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a PCI address"));
8185 8186 8187
        return -1;
    }

8188
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199
    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;
        }
8200
    }
8201
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8202 8203 8204

    ret = 0;

8205
    pci = pciGetDevice(detach->source.subsys.u.pci.domain,
8206 8207 8208 8209 8210 8211
                       detach->source.subsys.u.pci.bus,
                       detach->source.subsys.u.pci.slot,
                       detach->source.subsys.u.pci.function);
    if (!pci)
        ret = -1;
    else {
8212
        pciDeviceSetManaged(pci, detach->managed);
8213 8214
        pciDeviceListDel(driver->activePciHostdevs, pci);
        if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
8215
            ret = -1;
8216
        qemudReattachManagedDevice(pci);
8217
        pciFreeDevice(pci);
8218 8219
    }

8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231
    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;
8232
    }
8233
    virDomainHostdevDefFree(detach);
8234 8235 8236 8237

    return ret;
}

8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253
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;
8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269
        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;
            }
8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319
        }
    }

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

8320
static int qemudDomainDetachHostDevice(struct qemud_driver *driver,
8321
                                       virDomainObjPtr vm,
8322 8323
                                       virDomainDeviceDefPtr dev,
                                       unsigned long long qemuCmdFlags)
8324 8325 8326 8327 8328
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
    int ret;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
8329 8330 8331
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev mode '%s' not supported"),
                        virDomainHostdevModeTypeToString(hostdev->mode));
8332 8333 8334 8335 8336
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
8337
        ret = qemudDomainDetachHostPciDevice(driver, vm, dev, qemuCmdFlags);
8338
        break;
8339 8340 8341
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        ret = qemudDomainDetachHostUsbDevice(driver, vm, dev, qemuCmdFlags);
        break;
8342
    default:
8343 8344 8345
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev subsys type '%s' not supported"),
                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
8346 8347 8348
        return -1;
    }

8349
    if (driver->securityDriver &&
8350
        driver->securityDriver->domainRestoreSecurityHostdevLabel &&
8351
        driver->securityDriver->domainRestoreSecurityHostdevLabel(vm, dev->data.hostdev) < 0)
8352
        VIR_WARN0("Failed to restore host device labelling");
8353

8354 8355 8356
    return ret;
}

8357 8358
static int qemudDomainDetachDevice(virDomainPtr dom,
                                   const char *xml) {
8359 8360
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8361
    unsigned long long qemuCmdFlags;
8362 8363
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;
8364

8365
    qemuDriverLock(driver);
8366
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8367
    if (!vm) {
8368 8369
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8370 8371
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8372
        goto cleanup;
8373 8374
    }

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

D
Daniel P. Berrange 已提交
8378
    if (!virDomainObjIsActive(vm)) {
8379 8380
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot detach device on inactive domain"));
8381
        goto endjob;
8382 8383
    }

8384
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
8385
                                  VIR_DOMAIN_XML_INACTIVE);
8386
    if (dev == NULL)
8387
        goto endjob;
8388

8389 8390 8391 8392
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
        goto endjob;
8393 8394 8395

    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
8396
        dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
8397
        ret = qemudDomainDetachPciDiskDevice(driver, vm, dev, qemuCmdFlags);
8398
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
8399
        ret = qemudDomainDetachNetDevice(driver, vm, dev, qemuCmdFlags);
8400 8401
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
8402 8403
            ret = qemudDomainDetachPciControllerDevice(driver, vm, dev,
                                                       qemuCmdFlags);
8404
        } else {
8405 8406 8407
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk controller bus '%s' cannot be hotunplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
8408 8409
            /* fallthrough */
        }
8410
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
8411
        ret = qemudDomainDetachHostDevice(driver, vm, dev, qemuCmdFlags);
8412
    } else {
8413 8414
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("This type of device cannot be hot unplugged"));
8415
    }
8416

8417
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
8418 8419
        ret = -1;

8420
endjob:
8421 8422
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
8423

8424 8425
cleanup:
    virDomainDeviceDefFree(dev);
8426 8427
    if (vm)
        virDomainObjUnlock(vm);
8428
    qemuDriverUnlock(driver);
8429 8430 8431
    return ret;
}

8432 8433 8434 8435
static int qemudDomainDetachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
8436 8437
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
8438 8439 8440 8441 8442 8443
        return -1;
    }

    return qemudDomainDetachDevice(dom, xml);
}

8444
static int qemudDomainGetAutostart(virDomainPtr dom,
8445
                                   int *autostart) {
8446 8447 8448
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
8449

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

8454
    if (!vm) {
8455 8456
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8457 8458
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8459
        goto cleanup;
8460 8461 8462
    }

    *autostart = vm->autostart;
8463
    ret = 0;
8464

8465
cleanup:
8466 8467
    if (vm)
        virDomainObjUnlock(vm);
8468
    return ret;
8469 8470
}

8471
static int qemudDomainSetAutostart(virDomainPtr dom,
8472
                                   int autostart) {
8473 8474
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8475 8476
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
8477

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

8481
    if (!vm) {
8482 8483
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8484 8485
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8486
        goto cleanup;
8487 8488
    }

8489
    if (!vm->persistent) {
8490 8491
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot set autostart for transient domain"));
8492
        goto cleanup;
8493 8494
    }

8495 8496
    autostart = (autostart != 0);

8497
    if (vm->autostart != autostart) {
8498
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
8499
            goto cleanup;
8500
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
8501
            goto cleanup;
8502

8503 8504
        if (autostart) {
            int err;
8505

8506
            if ((err = virFileMakePath(driver->autostartDir))) {
8507
                virReportSystemError(err,
8508 8509
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
8510 8511
                goto cleanup;
            }
8512

8513
            if (symlink(configFile, autostartLink) < 0) {
8514
                virReportSystemError(errno,
8515 8516
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
8517 8518 8519 8520
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
8521
                virReportSystemError(errno,
8522 8523
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
8524 8525
                goto cleanup;
            }
8526 8527
        }

8528
        vm->autostart = autostart;
8529
    }
8530
    ret = 0;
8531

8532 8533 8534
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
8535 8536
    if (vm)
        virDomainObjUnlock(vm);
8537
    qemuDriverUnlock(driver);
8538
    return ret;
8539 8540
}

8541 8542 8543 8544 8545

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

8548
    qemuDriverLock(driver);
8549
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8550 8551
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
8552
        goto cleanup;
8553 8554 8555 8556 8557 8558 8559
    }

    if (nparams)
        *nparams = 1;

    ret = strdup("posix");
    if (!ret)
8560
        virReportOOMError();
8561 8562 8563

cleanup:
    qemuDriverUnlock(driver);
8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576
    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;

8577
    qemuDriverLock(driver);
8578
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8579 8580
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
8581
        goto cleanup;
8582 8583 8584 8585 8586
    }

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

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

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
8593 8594
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
8595 8596 8597 8598 8599 8600 8601 8602 8603
        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) {
8604 8605
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for cpu_shares tunable, expected a 'ullong'"));
8606 8607 8608 8609 8610
                goto cleanup;
            }

            rc = virCgroupSetCpuShares(group, params[i].value.ul);
            if (rc != 0) {
8611
                virReportSystemError(-rc, "%s",
8612 8613 8614 8615
                                     _("unable to set cpu shares tunable"));
                goto cleanup;
            }
        } else {
8616 8617
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Invalid parameter `%s'"), param->field);
8618 8619 8620 8621 8622 8623 8624 8625 8626
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
8627
    qemuDriverUnlock(driver);
8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641
    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;

8642
    qemuDriverLock(driver);
8643
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8644 8645
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
8646
        goto cleanup;
8647 8648 8649
    }

    if ((*nparams) != 1) {
8650 8651
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
8652
        goto cleanup;
8653 8654 8655 8656 8657
    }

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

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

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

    rc = virCgroupGetCpuShares(group, &val);
    if (rc != 0) {
8671
        virReportSystemError(-rc, "%s",
8672 8673 8674 8675 8676
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
    params[0].value.ul = val;
    params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
C
Chris Lalancette 已提交
8677
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
8678 8679
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Field cpu_shares too long for destination"));
C
Chris Lalancette 已提交
8680 8681
        goto cleanup;
    }
8682 8683 8684 8685 8686 8687 8688

    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
8689
    qemuDriverUnlock(driver);
8690 8691 8692 8693
    return ret;
}


8694 8695 8696 8697 8698 8699 8700 8701 8702
/* 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)
{
8703
    struct qemud_driver *driver = dom->conn->privateData;
8704
    int i, ret = -1;
8705
    virDomainObjPtr vm;
8706
    virDomainDiskDefPtr disk = NULL;
8707

8708
    qemuDriverLock(driver);
8709
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8710
    qemuDriverUnlock(driver);
8711
    if (!vm) {
8712 8713
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8714 8715
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8716
        goto cleanup;
8717
    }
8718 8719 8720 8721

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

D
Daniel P. Berrange 已提交
8722
    if (!virDomainObjIsActive (vm)) {
8723 8724
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8725
        goto endjob;
8726 8727
    }

8728 8729 8730 8731 8732 8733 8734 8735
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
8736 8737
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path: %s"), path);
8738
        goto endjob;
8739 8740
    }

8741
    if (!disk->info.alias) {
8742 8743
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), disk->dst);
8744
        goto endjob;
8745
    }
8746

8747
    qemuDomainObjPrivatePtr priv = vm->privateData;
8748 8749
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
8750
                                       disk->info.alias,
8751 8752 8753 8754 8755 8756
                                       &stats->rd_req,
                                       &stats->rd_bytes,
                                       &stats->wr_req,
                                       &stats->wr_bytes,
                                       &stats->errs);
    qemuDomainObjExitMonitor(vm);
8757

8758
endjob:
8759 8760
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
8761

8762
cleanup:
8763 8764
    if (vm)
        virDomainObjUnlock(vm);
8765
    return ret;
8766 8767
}

8768
#ifdef __linux__
8769 8770 8771 8772 8773
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
8774 8775
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8776
    int i;
8777
    int ret = -1;
8778

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

8783
    if (!vm) {
8784 8785
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8786 8787
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8788
        goto cleanup;
8789 8790
    }

D
Daniel P. Berrange 已提交
8791
    if (!virDomainObjIsActive(vm)) {
8792 8793
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8794
        goto cleanup;
8795 8796 8797
    }

    /* Check the path is one of the domain's network interfaces. */
8798 8799
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
8800 8801 8802 8803
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
8804 8805
    }

8806
    if (ret == 0)
8807
        ret = linuxDomainInterfaceStats(path, stats);
8808
    else
8809 8810
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path, '%s' is not a known interface"), path);
8811

8812
cleanup:
8813 8814
    if (vm)
        virDomainObjUnlock(vm);
8815 8816
    return ret;
}
8817
#else
8818 8819 8820 8821
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
8822 8823
    qemuReportError(VIR_ERR_NO_SUPPORT,
                    "%s", __FUNCTION__);
8824 8825
    return -1;
}
8826
#endif
8827

8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843
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);
8844 8845
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8846 8847 8848
        goto cleanup;
    }

8849 8850 8851
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

8852 8853 8854
    if (virDomainObjIsActive(vm)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        qemuDomainObjEnterMonitor(vm);
8855
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
8856 8857
        qemuDomainObjExitMonitor(vm);
    } else {
8858 8859
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8860 8861
    }

8862 8863 8864
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

8865 8866 8867 8868 8869 8870
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

8871 8872 8873 8874 8875 8876 8877
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
8878 8879 8880
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
8881

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

8886
    if (!vm) {
8887 8888
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8889 8890
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8891
        goto cleanup;
8892 8893 8894
    }

    if (!path || path[0] == '\0') {
8895 8896
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("NULL or empty path"));
8897
        goto cleanup;
8898 8899 8900
    }

    /* Check the path belongs to this domain. */
8901 8902
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
8903 8904 8905 8906
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
8907 8908
    }

8909 8910 8911 8912 8913
    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) {
8914 8915
            virReportSystemError(errno,
                                 _("%s: failed to open"), path);
8916 8917
            goto cleanup;
        }
8918

8919 8920 8921 8922 8923 8924
        /* 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) {
8925 8926
            virReportSystemError(errno,
                                 _("%s: failed to seek or read"), path);
8927 8928 8929 8930 8931
            goto cleanup;
        }

        ret = 0;
    } else {
8932 8933
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("invalid path"));
8934 8935
    }

8936 8937 8938
cleanup:
    if (fd >= 0)
        close (fd);
8939 8940
    if (vm)
        virDomainObjUnlock(vm);
8941 8942 8943
    return ret;
}

R
Richard W.M. Jones 已提交
8944 8945 8946 8947 8948 8949
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
8950 8951
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8952
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
8953 8954
    int fd = -1, ret = -1;

8955
    qemuDriverLock(driver);
8956
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8957
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
8958 8959

    if (!vm) {
8960 8961
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8962 8963
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8964 8965 8966
        goto cleanup;
    }

8967
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
8968 8969
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
8970
        goto cleanup;
R
Richard W.M. Jones 已提交
8971 8972
    }

8973 8974 8975
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
8976
    if (!virDomainObjIsActive(vm)) {
8977 8978
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
8979
        goto endjob;
R
Richard W.M. Jones 已提交
8980 8981
    }

8982
    if (virAsprintf(&tmp, driver->cacheDir,  "/qemu.mem.XXXXXX") < 0) {
8983
        virReportOOMError();
8984
        goto endjob;
8985 8986
    }

R
Richard W.M. Jones 已提交
8987 8988
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
8989 8990
        virReportSystemError(errno,
                             _("mkstemp(\"%s\") failed"), tmp);
8991
        goto endjob;
R
Richard W.M. Jones 已提交
8992 8993
    }

8994
    qemuDomainObjPrivatePtr priv = vm->privateData;
8995
    qemuDomainObjEnterMonitor(vm);
8996
    if (flags == VIR_MEMORY_VIRTUAL) {
8997 8998
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
8999
            goto endjob;
9000
        }
9001
    } else {
9002 9003
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
9004
            goto endjob;
9005
        }
R
Richard W.M. Jones 已提交
9006
    }
9007
    qemuDomainObjExitMonitor(vm);
R
Richard W.M. Jones 已提交
9008 9009 9010

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
9011 9012 9013
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
9014
        goto endjob;
R
Richard W.M. Jones 已提交
9015 9016 9017
    }

    ret = 0;
9018

9019
endjob:
9020 9021
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9022

9023
cleanup:
9024
    VIR_FREE(tmp);
R
Richard W.M. Jones 已提交
9025 9026
    if (fd >= 0) close (fd);
    unlink (tmp);
9027 9028
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
9029 9030 9031
    return ret;
}

9032

9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 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 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102
static int qemuDomainGetBlockInfo(virDomainPtr dom,
                                  const char *path,
                                  virDomainBlockInfoPtr info,
                                  unsigned int flags) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
    virStorageFileMetadata meta;
    struct stat sb;
    int i;

    virCheckFlags(0, -1);

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

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

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

    if (ret != 0) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path %s not assigned to domain"), path);
        goto cleanup;
    }

    ret = -1;

    /* The path is correct, now try to open it and get its size. */
    fd = open (path, O_RDONLY);
    if (fd == -1) {
        virReportSystemError(errno,
                             _("failed to open path '%s'"), path);
        goto cleanup;
    }

    /* Probe for magic formats */
    memset(&meta, 0, sizeof(meta));
    if (virStorageFileGetMetadataFromFD(path, fd, &meta) < 0)
        goto cleanup;

    /* Get info for normal formats */
    if (fstat(fd, &sb) < 0) {
        virReportSystemError(errno,
                             _("cannot stat file '%s'"), path);
        goto cleanup;
    }

    if (S_ISREG(sb.st_mode)) {
9103
#ifndef WIN32
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 9146
        info->physical = (unsigned long long)sb.st_blocks *
            (unsigned long long)DEV_BSIZE;
#else
        info->physical = sb.st_size;
#endif
        /* Regular files may be sparse, so logical size (capacity) is not same
         * as actual physical above
         */
        info->capacity = sb.st_size;
    } else {
        /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
         * be 64 bits on all platforms.
         */
        end = lseek (fd, 0, SEEK_END);
        if (end == (off_t)-1) {
            virReportSystemError(errno,
                                 _("failed to seek to end of %s"), path);
            goto cleanup;
        }
        info->physical = end;
        info->capacity = end;
    }

    /* If the file we probed has a capacity set, then override
     * what we calculated from file/block extents */
    if (meta.capacity)
        info->capacity = meta.capacity;

    /* XXX allocation will need to be pulled from QEMU for
     * the qcow inside LVM case */
    info->allocation = info->physical;

    ret = 0;

cleanup:
    if (fd != -1)
        close(fd);
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


9147
static int
9148 9149 9150 9151
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
9152
{
9153 9154 9155
    struct qemud_driver *driver = conn->privateData;
    int ret;

9156
    qemuDriverLock(driver);
9157 9158
    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
                                        callback, opaque, freecb);
9159
    qemuDriverUnlock(driver);
9160

9161
    return ret;
9162 9163
}

9164

9165
static int
9166 9167
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
9168
{
9169 9170 9171
    struct qemud_driver *driver = conn->privateData;
    int ret;

9172
    qemuDriverLock(driver);
9173 9174 9175 9176 9177 9178
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
                                               callback);
9179
    qemuDriverUnlock(driver);
9180

9181
    return ret;
9182 9183
}

9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 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

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


9227 9228
static void qemuDomainEventDispatchFunc(virConnectPtr conn,
                                        virDomainEventPtr event,
9229
                                        virConnectDomainEventGenericCallback cb,
9230 9231
                                        void *cbopaque,
                                        void *opaque)
9232
{
9233
    struct qemud_driver *driver = opaque;
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 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278
    /* 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);
9279 9280
}

D
Daniel Veillard 已提交
9281 9282
/* Migration support. */

C
Chris Lalancette 已提交
9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301
/* 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) {
9302 9303
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9304 9305 9306 9307 9308
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch == 0) {
9309 9310
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream does not have a callback registered"));
C
Chris Lalancette 已提交
9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338
        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) {
9339 9340
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9341 9342 9343 9344 9345
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch == 0) {
9346 9347
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream does not have a callback registered"));
C
Chris Lalancette 已提交
9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404
        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) {
9405 9406
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9407 9408 9409 9410 9411
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch != 0) {
9412 9413
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream already has a callback registered"));
C
Chris Lalancette 已提交
9414 9415 9416 9417 9418 9419 9420 9421
        goto cleanup;
    }

    if ((qemust->watch = virEventAddHandle(qemust->fd,
                                           events,
                                           qemuStreamMigEvent,
                                           st,
                                           NULL)) < 0) {
9422 9423
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot register file watch on stream"));
C
Chris Lalancette 已提交
9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455
        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;

9456
    if (VIR_ALLOC(qemust) < 0) {
9457
        virReportOOMError();
C
Chris Lalancette 已提交
9458
        return NULL;
9459
    }
C
Chris Lalancette 已提交
9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520

    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) {
9521 9522
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536
        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;
9537
            virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575
                                 _("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;
9576
    unsigned long long qemuCmdFlags;
C
Chris Lalancette 已提交
9577 9578 9579 9580
    struct qemuStreamMigFile *qemust = NULL;

    qemuDriverLock(driver);
    if (!dom_xml) {
9581 9582
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
9583 9584 9585
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9586
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
9587 9588 9589 9590
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
9591 9592
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
9593 9594 9595 9596
        goto cleanup;
    }

    /* Parse the domain XML. */
9597
    if (!(def = virDomainDefParseString(driver->caps, dom_xml,
C
Chris Lalancette 已提交
9598
                                        VIR_DOMAIN_XML_INACTIVE))) {
9599 9600
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
C
Chris Lalancette 已提交
9601 9602 9603 9604
        goto cleanup;
    }

    /* Target domain name, maybe renamed. */
9605 9606 9607 9608 9609 9610
    if (dname) {
        VIR_FREE(def->name);
        def->name = strdup(dname);
        if (def->name == NULL)
            goto cleanup;
    }
C
Chris Lalancette 已提交
9611

9612 9613
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
C
Chris Lalancette 已提交
9614

9615
    if (!(vm = virDomainAssignDef(driver->caps,
C
Chris Lalancette 已提交
9616
                                  &driver->domains,
9617
                                  def, true))) {
9618 9619
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to assign new VM"));
C
Chris Lalancette 已提交
9620 9621 9622 9623
        goto cleanup;
    }
    def = NULL;

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

C
Chris Lalancette 已提交
9627 9628 9629 9630 9631
    /* 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) {
9632
        virReportOOMError();
9633
        goto endjob;
C
Chris Lalancette 已提交
9634 9635 9636 9637 9638
    }
    unlink(unixfile);

    /* check that this qemu version supports the interactive exec */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
9639 9640 9641
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot determine QEMU argv syntax %s"),
                        vm->def->emulator);
9642
        goto endjob;
C
Chris Lalancette 已提交
9643 9644 9645 9646 9647 9648
    }
    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 {
9649 9650
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("Destination qemu is too old to support tunnelled migration"));
9651
        goto endjob;
C
Chris Lalancette 已提交
9652 9653
    }
    if (internalret < 0) {
9654
        virReportOOMError();
9655
        goto endjob;
C
Chris Lalancette 已提交
9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669
    }
    /* 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;
        }
9670
        goto endjob;
C
Chris Lalancette 已提交
9671 9672 9673 9674
    }

    qemust = qemuStreamMigOpen(st, unixfile);
    if (qemust == NULL) {
9675
        qemudShutdownVMDaemon(driver, vm);
9676
        if (!vm->persistent) {
9677 9678
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
9679 9680
            vm = NULL;
        }
9681
        virReportSystemError(errno,
C
Chris Lalancette 已提交
9682 9683
                             _("cannot open unix socket '%s' for tunnelled migration"),
                             unixfile);
9684
        goto endjob;
C
Chris Lalancette 已提交
9685 9686 9687 9688 9689 9690 9691 9692 9693 9694
    }

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

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

9695
endjob:
9696 9697 9698
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9699

C
Chris Lalancette 已提交
9700 9701
cleanup:
    virDomainDefFree(def);
9702 9703
    if (unixfile)
        unlink(unixfile);
C
Chris Lalancette 已提交
9704 9705 9706 9707 9708 9709 9710 9711 9712
    VIR_FREE(unixfile);
    if (vm)
        virDomainObjUnlock(vm);
    if (event)
        qemuDomainEventQueue(driver, event);
    qemuDriverUnlock(driver);
    return ret;
}

D
Daniel Veillard 已提交
9713 9714 9715 9716
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
9717
static int ATTRIBUTE_NONNULL (5)
D
Daniel Veillard 已提交
9718 9719 9720 9721 9722
qemudDomainMigratePrepare2 (virConnectPtr dconn,
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
9723
                            unsigned long flags,
D
Daniel Veillard 已提交
9724 9725 9726 9727 9728
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
    static int port = 0;
9729 9730
    struct qemud_driver *driver = dconn->privateData;
    virDomainDefPtr def = NULL;
D
Daniel Veillard 已提交
9731 9732
    virDomainObjPtr vm = NULL;
    int this_port;
9733
    char *hostname;
D
Daniel Veillard 已提交
9734 9735
    char migrateFrom [64];
    const char *p;
9736
    virDomainEventPtr event = NULL;
9737
    int ret = -1;
9738
    int internalret;
9739 9740

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

9742
    qemuDriverLock(driver);
C
Chris Lalancette 已提交
9743 9744 9745 9746
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9747 9748
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
9749 9750 9751
        goto cleanup;
    }

D
Daniel Veillard 已提交
9752
    if (!dom_xml) {
9753 9754
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
9755
        goto cleanup;
D
Daniel Veillard 已提交
9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772
    }

    /* 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 */
9773
        if ((hostname = virGetHostnameLocalhost(0)) == NULL)
9774
            goto cleanup;
D
Daniel Veillard 已提交
9775

9776 9777 9778 9779 9780
        /* 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 已提交
9781
        /* Caller frees */
9782 9783 9784
        internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
        VIR_FREE(hostname);
        if (internalret < 0) {
9785
            virReportOOMError();
9786
            goto cleanup;
D
Daniel Veillard 已提交
9787 9788 9789 9790 9791 9792
        }
    } 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.
         */
9793
        if (!STRPREFIX (uri_in, "tcp:")) {
9794 9795
            qemuReportError (VIR_ERR_INVALID_ARG,
                             "%s", _("only tcp URIs are supported for KVM/QEMU migrations"));
9796
            goto cleanup;
D
Daniel Veillard 已提交
9797 9798 9799 9800
        }

        /* Get the port number. */
        p = strrchr (uri_in, ':');
9801 9802 9803 9804 9805 9806 9807 9808
        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) {
9809
                virReportOOMError();
9810 9811 9812 9813 9814 9815 9816
                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)) {
9817 9818
                qemuReportError(VIR_ERR_INVALID_ARG,
                                "%s", _("URI ended with incorrect ':port'"));
9819 9820
                goto cleanup;
            }
D
Daniel Veillard 已提交
9821 9822 9823
        }
    }

9824
    if (*uri_out)
9825 9826
        VIR_DEBUG("Generated uri_out=%s", *uri_out);

D
Daniel Veillard 已提交
9827
    /* Parse the domain XML. */
9828
    if (!(def = virDomainDefParseString(driver->caps, dom_xml,
9829
                                        VIR_DOMAIN_XML_INACTIVE))) {
9830 9831
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
9832
        goto cleanup;
D
Daniel Veillard 已提交
9833 9834 9835
    }

    /* Target domain name, maybe renamed. */
9836 9837 9838 9839 9840 9841
    if (dname) {
        VIR_FREE(def->name);
        def->name = strdup(dname);
        if (def->name == NULL)
            goto cleanup;
    }
D
Daniel Veillard 已提交
9842

9843 9844
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
9845

9846
    if (!(vm = virDomainAssignDef(driver->caps,
D
Daniel Veillard 已提交
9847
                                  &driver->domains,
9848
                                  def, true))) {
9849 9850
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to assign new VM"));
9851
        goto cleanup;
D
Daniel Veillard 已提交
9852
    }
9853
    def = NULL;
D
Daniel Veillard 已提交
9854

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

D
Daniel Veillard 已提交
9858 9859 9860 9861 9862 9863 9864
    /* 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);
9865
    if (qemudStartVMDaemon (dconn, driver, vm, migrateFrom, -1) < 0) {
9866 9867 9868
        /* Note that we don't set an error here because qemudStartVMDaemon
         * should have already done that.
         */
9869
        if (!vm->persistent) {
9870 9871
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
9872 9873
            vm = NULL;
        }
9874
        goto endjob;
D
Daniel Veillard 已提交
9875
    }
9876 9877 9878 9879

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

9882
endjob:
9883 9884 9885
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9886

9887 9888 9889 9890 9891
cleanup:
    virDomainDefFree(def);
    if (ret != 0) {
        VIR_FREE(*uri_out);
    }
9892 9893
    if (vm)
        virDomainObjUnlock(vm);
9894 9895
    if (event)
        qemuDomainEventQueue(driver, event);
9896
    qemuDriverUnlock(driver);
9897
    return ret;
C
Chris Lalancette 已提交
9898 9899 9900

}

9901 9902 9903 9904

/* Perform migration using QEMU's native TCP migrate support,
 * not encrypted obviously
 */
9905
static int doNativeMigrate(struct qemud_driver *driver,
9906 9907
                           virDomainObjPtr vm,
                           const char *uri,
9908
                           unsigned int flags,
9909 9910 9911 9912
                           const char *dname ATTRIBUTE_UNUSED,
                           unsigned long resource)
{
    int ret = -1;
9913
    xmlURIPtr uribits = NULL;
9914
    qemuDomainObjPrivatePtr priv = vm->privateData;
9915 9916 9917 9918
    unsigned int background_flags = 0;

    virCheckFlags(VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
                  -1);
9919 9920 9921 9922 9923 9924

    /* 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) {
9925
            virReportOOMError();
9926 9927 9928 9929 9930 9931 9932 9933
            goto cleanup;
        }
        uribits = xmlParseURI(tmpuri);
        VIR_FREE(tmpuri);
    } else {
        uribits = xmlParseURI(uri);
    }
    if (!uribits) {
9934 9935
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot parse URI %s"), uri);
9936 9937 9938
        goto cleanup;
    }

9939
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9940
    if (resource > 0 &&
9941
        qemuMonitorSetMigrationSpeed(priv->mon, resource) < 0) {
9942
        qemuDomainObjExitMonitorWithDriver(driver, vm);
9943
        goto cleanup;
9944
    }
9945

9946 9947 9948 9949 9950 9951 9952 9953
    if (flags & VIR_MIGRATE_NON_SHARED_DISK)
        background_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_DISK;

    if (flags & VIR_MIGRATE_NON_SHARED_INC)
        background_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_INC;

    if (qemuMonitorMigrateToHost(priv->mon, background_flags, uribits->server,
                                 uribits->port) < 0) {
9954
        qemuDomainObjExitMonitorWithDriver(driver, vm);
9955 9956
        goto cleanup;
    }
9957
    qemuDomainObjExitMonitorWithDriver(driver, vm);
9958

9959
    if (qemuDomainWaitForMigrationComplete(driver, vm) < 0)
9960 9961 9962 9963 9964 9965 9966 9967 9968 9969
        goto cleanup;

    ret = 0;

cleanup:
    xmlFreeURI(uribits);
    return ret;
}


9970 9971
#define TUNNEL_SEND_BUF_SIZE 65536

9972
static int doTunnelSendAll(virStreamPtr st,
9973 9974
                           int sock)
{
9975 9976 9977 9978 9979 9980 9981 9982
    char *buffer;
    int nbytes = TUNNEL_SEND_BUF_SIZE;

    if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0) {
        virReportOOMError();
        virStreamAbort(st);
        return -1;
    }
9983 9984 9985 9986 9987

    /* XXX should honour the 'resource' parameter here */
    for (;;) {
        nbytes = saferead(sock, buffer, nbytes);
        if (nbytes < 0) {
9988
            virReportSystemError(errno, "%s",
9989
                                 _("tunnelled migration failed to read from qemu"));
9990 9991
            virStreamAbort(st);
            VIR_FREE(buffer);
9992 9993 9994 9995 9996 9997 9998
            return -1;
        }
        else if (nbytes == 0)
            /* EOF; get out of here */
            break;

        if (virStreamSend(st, buffer, nbytes) < 0) {
9999 10000
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("Failed to write migration data to remote libvirtd"));
10001
            VIR_FREE(buffer);
10002 10003 10004 10005
            return -1;
        }
    }

10006 10007
    VIR_FREE(buffer);

10008 10009 10010 10011 10012 10013 10014
    if (virStreamFinish(st) < 0)
        /* virStreamFinish set the error for us */
        return -1;

    return 0;
}

C
Chris Lalancette 已提交
10015
static int doTunnelMigrate(virDomainPtr dom,
10016
                           struct qemud_driver *driver,
10017
                           virConnectPtr dconn,
C
Chris Lalancette 已提交
10018
                           virDomainObjPtr vm,
10019
                           const char *dom_xml,
C
Chris Lalancette 已提交
10020 10021 10022 10023 10024
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
10025
    qemuDomainObjPrivatePtr priv = vm->privateData;
10026 10027
    int client_sock = -1;
    int qemu_sock = -1;
C
Chris Lalancette 已提交
10028 10029
    struct sockaddr_un sa_qemu, sa_client;
    socklen_t addrlen;
10030
    virDomainPtr ddomain = NULL;
C
Chris Lalancette 已提交
10031
    int retval = -1;
10032
    virStreamPtr st = NULL;
C
Chris Lalancette 已提交
10033 10034
    char *unixfile = NULL;
    int internalret;
10035
    unsigned long long qemuCmdFlags;
C
Chris Lalancette 已提交
10036 10037
    int status;
    unsigned long long transferred, remaining, total;
10038
    unsigned int background_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
C
Chris Lalancette 已提交
10039

10040 10041 10042 10043 10044 10045 10046 10047
    /*
     * 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 已提交
10048 10049
     */

10050

10051
    /* Stage 1. setup local support infrastructure */
C
Chris Lalancette 已提交
10052 10053 10054

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
                    driver->stateDir, vm->def->name) < 0) {
10055
        virReportOOMError();
10056
        goto cleanup;
C
Chris Lalancette 已提交
10057 10058 10059 10060
    }

    qemu_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (qemu_sock < 0) {
10061
        virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
10062
                             _("cannot open tunnelled migration socket"));
10063
        goto cleanup;
C
Chris Lalancette 已提交
10064 10065 10066 10067 10068
    }
    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) {
10069 10070 10071
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Unix socket '%s' too big for destination"),
                        unixfile);
10072
        goto cleanup;
C
Chris Lalancette 已提交
10073 10074 10075
    }
    unlink(unixfile);
    if (bind(qemu_sock, (struct sockaddr *)&sa_qemu, sizeof(sa_qemu)) < 0) {
10076
        virReportSystemError(errno,
C
Chris Lalancette 已提交
10077 10078
                             _("Cannot bind to unix socket '%s' for tunnelled migration"),
                             unixfile);
10079
        goto cleanup;
C
Chris Lalancette 已提交
10080 10081
    }
    if (listen(qemu_sock, 1) < 0) {
10082
        virReportSystemError(errno,
C
Chris Lalancette 已提交
10083 10084
                             _("Cannot listen on unix socket '%s' for tunnelled migration"),
                             unixfile);
10085
        goto cleanup;
C
Chris Lalancette 已提交
10086 10087 10088 10089
    }

    /* check that this qemu version supports the unix migration */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
10090 10091 10092
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot extract Qemu version from '%s'"),
                        vm->def->emulator);
10093 10094 10095 10096 10097
        goto cleanup;
    }

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX) &&
        !(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
10098 10099
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("Source qemu is too old to support tunnelled migration"));
10100
        goto cleanup;
C
Chris Lalancette 已提交
10101
    }
10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122


    /* 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 */
10123
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
10124 10125 10126 10127 10128 10129 10130 10131
    if (flags & VIR_MIGRATE_NON_SHARED_DISK)
        background_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_DISK;
    if (flags & VIR_MIGRATE_NON_SHARED_INC)
        background_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_INC;
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX){
        internalret = qemuMonitorMigrateToUnix(priv->mon, background_flags,
                                               unixfile);
    }
C
Chris Lalancette 已提交
10132 10133
    else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
        const char *args[] = { "nc", "-U", unixfile, NULL };
10134
        internalret = qemuMonitorMigrateToCommand(priv->mon, QEMU_MONITOR_MIGRATE_BACKGROUND, args);
10135 10136
    } else {
        internalret = -1;
C
Chris Lalancette 已提交
10137
    }
10138
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
10139
    if (internalret < 0) {
10140 10141
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("tunnelled migration monitor command failed"));
10142
        goto finish;
C
Chris Lalancette 已提交
10143 10144
    }

10145 10146 10147
    /* From this point onwards we *must* call cancel to abort the
     * migration on source if anything goes wrong */

C
Chris Lalancette 已提交
10148 10149 10150
    /* it is also possible that the migrate didn't fail initially, but
     * rather failed later on.  Check the output of "info migrate"
     */
10151
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
10152 10153
    if (qemuMonitorGetMigrationStatus(priv->mon,
                                      &status,
C
Chris Lalancette 已提交
10154 10155 10156
                                      &transferred,
                                      &remaining,
                                      &total) < 0) {
10157
        qemuDomainObjExitMonitorWithDriver(driver, vm);
10158
        goto cancel;
C
Chris Lalancette 已提交
10159
    }
10160
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
10161 10162

    if (status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
10163 10164
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s",_("migrate failed"));
10165
        goto cancel;
C
Chris Lalancette 已提交
10166 10167 10168 10169 10170 10171
    }

    addrlen = sizeof(sa_client);
    while ((client_sock = accept(qemu_sock, (struct sockaddr *)&sa_client, &addrlen)) < 0) {
        if (errno == EAGAIN || errno == EINTR)
            continue;
10172
        virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
10173
                             _("tunnelled migration failed to accept from qemu"));
10174
        goto cancel;
C
Chris Lalancette 已提交
10175 10176
    }

10177
    retval = doTunnelSendAll(st, client_sock);
10178

10179
cancel:
10180
    if (retval != 0) {
10181
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
10182
        qemuMonitorMigrateCancel(priv->mon);
10183
        qemuDomainObjExitMonitorWithDriver(driver, vm);
10184
    }
C
Chris Lalancette 已提交
10185

10186
finish:
C
Chris Lalancette 已提交
10187 10188 10189
    dname = dname ? dname : dom->name;
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri, flags, retval);
10190 10191 10192 10193 10194 10195 10196

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

C
Chris Lalancette 已提交
10197 10198 10199
    if (ddomain)
        virUnrefDomain(ddomain);

10200 10201 10202 10203
    if (unixfile) {
        unlink(unixfile);
        VIR_FREE(unixfile);
    }
C
Chris Lalancette 已提交
10204

10205 10206 10207
    if (st)
        /* don't call virStreamFree(), because that resets any pending errors */
        virUnrefStream(st);
10208 10209 10210 10211
    return retval;
}


10212 10213 10214 10215
/* 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,
10216
                              struct qemud_driver *driver,
10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241
                              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) {
10242 10243
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("domainMigratePrepare2 did not set uri"));
10244
        goto cleanup;
10245 10246
    }

10247
    if (doNativeMigrate(driver, vm, uri_out, flags, dname, resource) < 0)
10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264
        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;
}


10265
static int doPeer2PeerMigrate(virDomainPtr dom,
10266
                              struct qemud_driver *driver,
10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282
                              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) {
10283 10284
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("Failed to connect to remote libvirt URI %s"), uri);
10285 10286 10287
        return -1;
    }
    if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
10288
                                  VIR_DRV_FEATURE_MIGRATION_P2P)) {
10289 10290
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("Destination libvirt does not support peer-to-peer migration protocol"));
10291 10292 10293
        goto cleanup;
    }

10294 10295 10296
    dom_xml = qemudVMDumpXML(driver, vm,
                             VIR_DOMAIN_XML_SECURE |
                             VIR_DOMAIN_XML_UPDATE_CPU);
10297
    if (!dom_xml) {
10298 10299
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
10300 10301 10302
        goto cleanup;
    }

10303
    if (flags & VIR_MIGRATE_TUNNELLED)
10304
        ret = doTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
10305
    else
10306
        ret = doNonTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
10307 10308 10309

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

10313
    return ret;
D
Daniel Veillard 已提交
10314 10315
}

10316

D
Daniel Veillard 已提交
10317 10318 10319 10320 10321 10322
/* 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,
10323
                           unsigned long flags,
10324
                           const char *dname,
D
Daniel Veillard 已提交
10325 10326
                           unsigned long resource)
{
10327 10328
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
10329
    virDomainEventPtr event = NULL;
10330
    int ret = -1;
10331
    int resume = 0;
10332
    qemuDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
10333

10334
    qemuDriverLock(driver);
10335
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
10336
    if (!vm) {
10337 10338
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10339 10340
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
10341
        goto cleanup;
D
Daniel Veillard 已提交
10342
    }
10343
    priv = vm->privateData;
D
Daniel Veillard 已提交
10344

10345 10346
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
10347
    priv->jobActive = QEMU_JOB_MIGRATION;
10348

D
Daniel P. Berrange 已提交
10349
    if (!virDomainObjIsActive(vm)) {
10350 10351
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
10352
        goto endjob;
D
Daniel Veillard 已提交
10353 10354
    }

10355 10356 10357
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

10358
    resume = vm->state == VIR_DOMAIN_RUNNING;
10359
    if (!(flags & VIR_MIGRATE_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
10360
        if (qemuDomainMigrateOffline(driver, vm) < 0)
10361
            goto endjob;
10362 10363
    }

10364
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
10365
        if (doPeer2PeerMigrate(dom, driver, vm, uri, flags, dname, resource) < 0)
10366
            /* doPeer2PeerMigrate already set the error, so just get out */
10367
            goto endjob;
10368
    } else {
10369
        if (doNativeMigrate(driver, vm, uri, flags, dname, resource) < 0)
10370
            goto endjob;
10371 10372
    }

D
Daniel Veillard 已提交
10373
    /* Clean up the source domain. */
10374
    qemudShutdownVMDaemon(driver, vm);
10375
    resume = 0;
10376 10377 10378 10379

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
C
Chris Lalancette 已提交
10380
    if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
10381
        virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm);
10382 10383
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains, vm);
10384 10385
        vm = NULL;
    }
10386
    ret = 0;
D
Daniel Veillard 已提交
10387

10388
endjob:
10389
    if (resume && vm->state == VIR_DOMAIN_PAUSED) {
10390
        /* we got here through some sort of failure; start the domain again */
10391
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
10392
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
10393 10394 10395 10396
            /* 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
             */
10397
            VIR_ERROR(_("Failed to resume guest %s after failure"),
10398
                      vm->def->name);
10399
        }
10400
        qemuDomainObjExitMonitorWithDriver(driver, vm);
10401

10402
        vm->state = VIR_DOMAIN_RUNNING;
10403 10404 10405 10406
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }
10407 10408 10409
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
10410

10411
cleanup:
10412 10413
    if (vm)
        virDomainObjUnlock(vm);
10414 10415
    if (event)
        qemuDomainEventQueue(driver, event);
10416
    qemuDriverUnlock(driver);
10417
    return ret;
D
Daniel Veillard 已提交
10418 10419 10420 10421 10422 10423 10424 10425 10426
}

/* 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 已提交
10427
                           unsigned long flags,
D
Daniel Veillard 已提交
10428 10429
                           int retcode)
{
10430 10431 10432
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
10433
    virDomainEventPtr event = NULL;
10434
    virErrorPtr orig_err;
C
Chris Lalancette 已提交
10435
    int newVM = 1;
D
Daniel Veillard 已提交
10436

10437 10438 10439
    /* Migration failed. Save the current error so nothing squashes it */
    orig_err = virSaveLastError();

10440
    qemuDriverLock(driver);
10441
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
10442
    if (!vm) {
10443 10444
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
10445
        goto cleanup;
D
Daniel Veillard 已提交
10446 10447
    }

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

D
Daniel Veillard 已提交
10451 10452 10453 10454
    /* 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 已提交
10455 10456 10457 10458 10459
        if (flags & VIR_MIGRATE_PERSIST_DEST) {
            if (vm->persistent)
                newVM = 0;
            vm->persistent = 1;

10460
            if (virDomainSaveConfig(driver->configDir, vm->def) < 0) {
C
Chris Lalancette 已提交
10461 10462 10463 10464 10465 10466 10467 10468 10469 10470
                /* 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;
10471
                goto endjob;
C
Chris Lalancette 已提交
10472 10473 10474 10475 10476 10477 10478 10479 10480
            }

            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_DEFINED,
                                             newVM ?
                                             VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                             VIR_DOMAIN_EVENT_DEFINED_UPDATED);
            if (event)
                qemuDomainEventQueue(driver, event);
10481
            event = NULL;
C
Chris Lalancette 已提交
10482 10483

        }
10484
        qemuDomainObjPrivatePtr priv = vm->privateData;
D
Daniel Veillard 已提交
10485
        dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
10486

10487 10488 10489 10490 10491 10492 10493 10494
        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)
10495 10496
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("resume operation failed"));
10497 10498 10499
                qemuDomainObjExitMonitorWithDriver(driver, vm);
                goto endjob;
            }
10500
            qemuDomainObjExitMonitorWithDriver(driver, vm);
10501 10502

            vm->state = VIR_DOMAIN_RUNNING;
10503 10504
        }

10505 10506 10507
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
10508 10509 10510 10511 10512 10513
        if (vm->state == VIR_DOMAIN_PAUSED) {
            qemuDomainEventQueue(driver, event);
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
        }
10514
        virDomainSaveStatus(driver->caps, driver->stateDir, vm);
D
Daniel Veillard 已提交
10515
    } else {
10516
        qemudShutdownVMDaemon(driver, vm);
10517 10518 10519
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
10520
        if (!vm->persistent) {
10521 10522
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
10523 10524
            vm = NULL;
        }
D
Daniel Veillard 已提交
10525
    }
10526

10527
endjob:
10528 10529 10530
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
10531

10532
cleanup:
10533 10534 10535 10536
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
10537 10538
    if (vm)
        virDomainObjUnlock(vm);
10539 10540
    if (event)
        qemuDomainEventQueue(driver, event);
10541
    qemuDriverUnlock(driver);
10542
    return dom;
D
Daniel Veillard 已提交
10543 10544
}

10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560
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;

10561
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE);
10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578
    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) {
10579 10580
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("device %s is not a PCI device"), dev->name);
10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600
        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;

10601
    pci = pciGetDevice(domain, bus, slot, function);
10602 10603 10604
    if (!pci)
        return -1;

10605
    if (pciDettachDevice(pci) < 0)
10606 10607 10608 10609
        goto out;

    ret = 0;
out:
10610
    pciFreeDevice(pci);
10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623
    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;

10624
    pci = pciGetDevice(domain, bus, slot, function);
10625 10626 10627
    if (!pci)
        return -1;

10628
    if (pciReAttachDevice(pci) < 0)
10629 10630 10631 10632
        goto out;

    ret = 0;
out:
10633
    pciFreeDevice(pci);
10634 10635 10636 10637 10638 10639
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
10640
    struct qemud_driver *driver = dev->conn->privateData;
10641 10642 10643 10644 10645 10646 10647
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

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

10648
    pci = pciGetDevice(domain, bus, slot, function);
10649 10650 10651
    if (!pci)
        return -1;

10652 10653
    qemuDriverLock(driver);

10654
    if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
10655 10656 10657 10658
        goto out;

    ret = 0;
out:
10659
    qemuDriverUnlock(driver);
10660
    pciFreeDevice(pci);
10661 10662 10663
    return ret;
}

10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674
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) {
10675 10676
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cannot get host CPU capabilities"));
10677 10678
    }
    else
10679
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
10680 10681 10682 10683 10684 10685

    qemuDriverUnlock(driver);

    return ret;
}

10686

10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699
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;
}

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

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


10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764
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);
10765
            priv->jobSignals |= QEMU_JOB_SIGNAL_CANCEL;
10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785
        } 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;
}


10786 10787 10788 10789 10790 10791 10792 10793 10794 10795
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;

10796
    virCheckFlags(0, -1);
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

    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 已提交
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
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,
10944 10945
                            _("Disk '%s' does not support snapshotting"),
                            vm->def->disks[i]->src);
C
Chris Lalancette 已提交
10946 10947 10948 10949 10950 10951 10952 10953 10954
            return 0;
        }
    }

    return 1;
}

static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
                                                        const char *xmlDesc,
10955
                                                        unsigned int flags)
C
Chris Lalancette 已提交
10956 10957 10958 10959 10960 10961 10962 10963 10964 10965
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainSnapshotDefPtr def;
    const char *qemuimgarg[] = { NULL, "snapshot", "-c", NULL, NULL, NULL };
    int i;

10966 10967
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
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
    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 {
11029 11030 11031 11032 11033
        qemuDomainObjPrivatePtr priv;
        int ret;

        if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
            goto cleanup;
C
Chris Lalancette 已提交
11034 11035
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
11036
        ret = qemuMonitorCreateSnapshot(priv->mon, def->name);
C
Chris Lalancette 已提交
11037
        qemuDomainObjExitMonitorWithDriver(driver, vm);
11038
        if (qemuDomainObjEndJob(vm) == 0) {
11039
            vm = NULL;
11040 11041
            goto cleanup;
        }
11042 11043
        if (ret < 0)
            goto cleanup;
C
Chris Lalancette 已提交
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
    }

    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,
11080
                                       unsigned int flags)
C
Chris Lalancette 已提交
11081 11082 11083 11084 11085
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

11086 11087
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107
    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,
11108
                                 unsigned int flags)
C
Chris Lalancette 已提交
11109 11110 11111 11112 11113
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

11114 11115
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136
    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,
11137
                                                           unsigned int flags)
C
Chris Lalancette 已提交
11138 11139 11140 11141 11142 11143
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

11144 11145
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
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
    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,
11173
                                        unsigned int flags)
C
Chris Lalancette 已提交
11174 11175 11176 11177 11178
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

11179 11180
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200
    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,
11201
                                                      unsigned int flags)
C
Chris Lalancette 已提交
11202 11203 11204 11205 11206
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

11207 11208
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
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
    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,
11235
                                       unsigned int flags)
C
Chris Lalancette 已提交
11236 11237 11238 11239 11240 11241 11242
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

11243 11244
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271
    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,
11272
                                      unsigned int flags)
C
Chris Lalancette 已提交
11273 11274 11275 11276 11277 11278 11279 11280 11281 11282
{
    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;

11283 11284
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315
    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)
11316
                goto endjob;
C
Chris Lalancette 已提交
11317 11318 11319
        }
        else {
            if (qemuDomainSnapshotSetActive(vm, driver->snapshotDir) < 0)
11320
                goto endjob;
C
Chris Lalancette 已提交
11321 11322 11323 11324

            rc = qemudStartVMDaemon(snapshot->domain->conn, driver, vm, NULL,
                                    -1);
            if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
11325
                goto endjob;
C
Chris Lalancette 已提交
11326
            if (rc < 0)
11327
                goto endjob;
C
Chris Lalancette 已提交
11328 11329 11330 11331 11332 11333
        }

        if (snap->def->state == VIR_DOMAIN_PAUSED) {
            /* qemu unconditionally starts the domain running again after
             * loadvm, so let's pause it to keep consistency
             */
11334
            int state = vm->state;
C
Chris Lalancette 已提交
11335
            priv = vm->privateData;
11336
            vm->state = VIR_DOMAIN_PAUSED;
C
Chris Lalancette 已提交
11337 11338 11339
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorStopCPUs(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
11340 11341
            if (rc < 0) {
                vm->state = state;
11342
                goto endjob;
11343
            }
C
Chris Lalancette 已提交
11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365
        }

        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);
11366 11367 11368 11369
            if (!vm->persistent) {
                if (qemuDomainObjEndJob(vm) > 0)
                    virDomainRemoveInactive(&driver->domains, vm);
                vm = NULL;
11370
                goto cleanup;
11371
            }
C
Chris Lalancette 已提交
11372 11373 11374
        }

        if (qemuDomainSnapshotSetActive(vm, driver->snapshotDir) < 0)
11375
            goto endjob;
C
Chris Lalancette 已提交
11376 11377 11378 11379 11380 11381
    }

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

    ret = 0;

11382
endjob:
C
Chris Lalancette 已提交
11383 11384 11385
    if (vm && qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

11386
cleanup:
C
Chris Lalancette 已提交
11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 11520
    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;

11521 11522
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);

C
Chris Lalancette 已提交
11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539
    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;
    }

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

C
Chris Lalancette 已提交
11543 11544 11545 11546 11547 11548 11549 11550
    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)
11551
            goto endjob;
C
Chris Lalancette 已提交
11552 11553 11554 11555
    }

    ret = qemuDomainSnapshotDiscard(driver, vm, snap);

11556 11557 11558 11559
endjob:
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

C
Chris Lalancette 已提交
11560 11561 11562 11563 11564 11565
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
11566

11567 11568 11569 11570 11571
static virDriver qemuDriver = {
    VIR_DRV_QEMU,
    "QEMU",
    qemudOpen, /* open */
    qemudClose, /* close */
D
Daniel Veillard 已提交
11572
    qemudSupportsFeature, /* supports_feature */
11573 11574
    qemudGetType, /* type */
    qemudGetVersion, /* version */
11575
    NULL, /* libvirtVersion (impl. in libvirt.c) */
11576
    virGetHostname, /* getHostname */
11577
    qemudGetMaxVCPUs, /* getMaxVcpus */
11578
    nodeGetInfo, /* nodeGetInfo */
11579 11580 11581
    qemudGetCapabilities, /* getCapabilities */
    qemudListDomains, /* listDomains */
    qemudNumDomains, /* numOfDomains */
11582
    qemudDomainCreate, /* domainCreateXML */
11583 11584 11585 11586 11587
    qemudDomainLookupByID, /* domainLookupByID */
    qemudDomainLookupByUUID, /* domainLookupByUUID */
    qemudDomainLookupByName, /* domainLookupByName */
    qemudDomainSuspend, /* domainSuspend */
    qemudDomainResume, /* domainResume */
11588
    qemudDomainShutdown, /* domainShutdown */
11589 11590 11591
    NULL, /* domainReboot */
    qemudDomainDestroy, /* domainDestroy */
    qemudDomainGetOSType, /* domainGetOSType */
11592
    qemudDomainGetMaxMemory, /* domainGetMaxMemory */
11593
    NULL, /* domainSetMaxMemory */
11594
    qemudDomainSetMemory, /* domainSetMemory */
11595 11596 11597
    qemudDomainGetInfo, /* domainGetInfo */
    qemudDomainSave, /* domainSave */
    qemudDomainRestore, /* domainRestore */
P
Paolo Bonzini 已提交
11598
    qemudDomainCoreDump, /* domainCoreDump */
11599
    qemudDomainSetVcpus, /* domainSetVcpus */
11600 11601
    qemudDomainPinVcpu, /* domainPinVcpu */
    qemudDomainGetVcpus, /* domainGetVcpus */
11602
    qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
11603 11604
    qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
    qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
11605
    qemudDomainDumpXML, /* domainDumpXML */
11606
    qemuDomainXMLFromNative, /* domainXmlFromNative */
11607
    qemuDomainXMLToNative, /* domainXMLToNative */
11608 11609
    qemudListDefinedDomains, /* listDefinedDomains */
    qemudNumDefinedDomains, /* numOfDefinedDomains */
11610 11611 11612
    qemudDomainStart, /* domainCreate */
    qemudDomainDefine, /* domainDefineXML */
    qemudDomainUndefine, /* domainUndefine */
11613
    qemudDomainAttachDevice, /* domainAttachDevice */
11614
    qemudDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
11615
    qemudDomainDetachDevice, /* domainDetachDevice */
11616
    qemudDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
11617
    qemuDomainUpdateDeviceFlags, /* domainUpdateDeviceFlags */
11618 11619
    qemudDomainGetAutostart, /* domainGetAutostart */
    qemudDomainSetAutostart, /* domainSetAutostart */
11620 11621 11622
    qemuGetSchedulerType, /* domainGetSchedulerType */
    qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
    qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
11623 11624
    NULL, /* domainMigratePrepare (v1) */
    qemudDomainMigratePerform, /* domainMigratePerform */
11625
    NULL, /* domainMigrateFinish */
11626
    qemudDomainBlockStats, /* domainBlockStats */
11627
    qemudDomainInterfaceStats, /* domainInterfaceStats */
11628
    qemudDomainMemoryStats, /* domainMemoryStats */
11629
    qemudDomainBlockPeek, /* domainBlockPeek */
R
Richard W.M. Jones 已提交
11630
    qemudDomainMemoryPeek, /* domainMemoryPeek */
11631
    qemuDomainGetBlockInfo, /* domainGetBlockInfo */
11632 11633
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
11634 11635
    qemuDomainEventRegister, /* domainEventRegister */
    qemuDomainEventDeregister, /* domainEventDeregister */
D
Daniel Veillard 已提交
11636 11637
    qemudDomainMigratePrepare2, /* domainMigratePrepare2 */
    qemudDomainMigrateFinish2, /* domainMigrateFinish2 */
11638 11639 11640
    qemudNodeDeviceDettach, /* nodeDeviceDettach */
    qemudNodeDeviceReAttach, /* nodeDeviceReAttach */
    qemudNodeDeviceReset, /* nodeDeviceReset */
C
Chris Lalancette 已提交
11641
    qemudDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
11642 11643 11644 11645
    qemuIsEncrypted, /* isEncrypted */
    qemuIsSecure, /* isSecure */
    qemuDomainIsActive, /* domainIsActive */
    qemuDomainIsPersistent, /* domainIsPersistent */
11646
    qemuCPUCompare, /* cpuCompare */
11647
    qemuCPUBaseline, /* cpuBaseline */
11648
    qemuDomainGetJobInfo, /* domainGetJobInfo */
11649
    qemuDomainAbortJob, /* domainAbortJob */
11650
    qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
11651 11652
    qemuDomainEventRegisterAny, /* domainEventRegisterAny */
    qemuDomainEventDeregisterAny, /* domainEventDeregisterAny */
11653 11654 11655
    qemuDomainManagedSave, /* domainManagedSave */
    qemuDomainHasManagedSaveImage, /* domainHasManagedSaveImage */
    qemuDomainManagedSaveRemove, /* domainManagedSaveRemove */
C
Chris Lalancette 已提交
11656 11657 11658 11659 11660 11661 11662 11663 11664
    qemuDomainSnapshotCreateXML, /* domainSnapshotCreateXML */
    qemuDomainSnapshotDumpXML, /* domainSnapshotDumpXML */
    qemuDomainSnapshotNum, /* domainSnapshotNum */
    qemuDomainSnapshotListNames, /* domainSnapshotListNames */
    qemuDomainSnapshotLookupByName, /* domainSnapshotLookupByName */
    qemuDomainHasCurrentSnapshot, /* domainHasCurrentSnapshot */
    qemuDomainSnapshotCurrent, /* domainSnapshotCurrent */
    qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */
    qemuDomainSnapshotDelete, /* domainSnapshotDelete */
11665 11666 11667
};


11668
static virStateDriver qemuStateDriver = {
11669
    .name = "QEMU",
11670 11671 11672 11673
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
11674
};
11675

S
Stefan Berger 已提交
11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690
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,
};

11691
int qemuRegister(void) {
11692 11693
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
S
Stefan Berger 已提交
11694
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
11695 11696
    return 0;
}