qemu_driver.c 383.2 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
#include "virterror_internal.h"
50
#include "logging.h"
51
#include "datatypes.h"
52 53
#include "qemu_driver.h"
#include "qemu_conf.h"
54
#include "qemu_monitor.h"
55
#include "qemu_bridge_filter.h"
J
Jim Meyering 已提交
56
#include "c-ctype.h"
57
#include "event.h"
58
#include "buf.h"
59
#include "util.h"
60
#include "nodeinfo.h"
61
#include "stats_linux.h"
62
#include "capabilities.h"
63
#include "memory.h"
64
#include "uuid.h"
65
#include "domain_conf.h"
66 67
#include "node_device_conf.h"
#include "pci.h"
68
#include "hostusb.h"
69
#include "processinfo.h"
70 71
#include "qemu_security_stacked.h"
#include "qemu_security_dac.h"
72
#include "cgroup.h"
C
Chris Lalancette 已提交
73
#include "libvirt_internal.h"
74
#include "xml.h"
75
#include "cpu/cpu.h"
76
#include "macvtap.h"
77
#include "domain_nwfilter.h"
78
#include "hooks.h"
79
#include "storage_file.h"
80

81

82 83
#define VIR_FROM_THIS VIR_FROM_QEMU

84 85 86
#define QEMU_VNC_PORT_MIN  5900
#define QEMU_VNC_PORT_MAX  65535

87 88 89 90 91 92
/* 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,
93 94
    QEMU_JOB_MIGRATION_OUT,
    QEMU_JOB_MIGRATION_IN,
95 96 97 98 99
};

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 */
100 101 102 103 104
    QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME = 1 << 2, /* Request migration downtime change */
};

struct qemuDomainJobSignalsData {
    unsigned long long migrateDowntime; /* Data for QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME */
105 106
};

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

117
    qemuMonitorPtr mon;
118
    virDomainChrDefPtr monConfig;
D
Daniel P. Berrange 已提交
119
    int monJSON;
120 121 122

    int nvcpupids;
    int *vcpupids;
123 124

    qemuDomainPCIAddressSetPtr pciaddrs;
125
    int persistentAddrs;
126 127
};

128 129
static int qemudShutdown(void);

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

139 140 141
static void qemuDomainEventFlush(int timer, void *opaque);
static void qemuDomainEventQueue(struct qemud_driver *driver,
                                 virDomainEventPtr event);
142

J
Jiri Denemark 已提交
143 144
static int qemudDomainObjStart(virConnectPtr conn,
                               struct qemud_driver *driver,
145 146
                               virDomainObjPtr vm,
                               bool start_paused);
J
Jiri Denemark 已提交
147

148 149
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
150
                              virDomainObjPtr vm,
151
                              const char *migrateFrom,
152
                              bool start_paused,
153 154
                              int stdin_fd,
                              const char *stdin_path);
155

156
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
157 158
                                  virDomainObjPtr vm,
                                  int migrated);
159

160
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
161

162
static int qemuDetectVcpuPIDs(struct qemud_driver *driver,
163
                              virDomainObjPtr vm);
164

165 166 167
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                                       virDomainDefPtr def);

J
Jim Meyering 已提交
168
static struct qemud_driver *qemu_driver = NULL;
169

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184

static void *qemuDomainObjPrivateAlloc(void)
{
    qemuDomainObjPrivatePtr priv;

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

    return priv;
}

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

185
    qemuDomainPCIAddressSetFree(priv->pciaddrs);
186 187 188
    virDomainChrDefFree(priv->monConfig);
    VIR_FREE(priv->vcpupids);

189 190
    /* This should never be non-NULL if we get here, but just in case... */
    if (priv->mon) {
191
        VIR_ERROR0(_("Unexpected QEMU monitor still active during domain deletion"));
192 193 194 195 196 197
        qemuMonitorClose(priv->mon);
    }
    VIR_FREE(priv);
}


198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
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 已提交
216 217
        if (priv->monJSON)
            virBufferAddLit(buf, " json='1'");
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
        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) {
244
        virReportOOMError();
245 246 247
        goto error;
    }

248
    if (!(priv->monConfig->info.alias = strdup("monitor"))) {
249
        virReportOOMError();
250 251 252
        goto error;
    }

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

260
    tmp = virXPathString("string(./monitor[1]/@type)", ctxt);
261 262 263 264 265 266
    if (tmp)
        priv->monConfig->type = virDomainChrTypeFromString(tmp);
    else
        priv->monConfig->type = VIR_DOMAIN_CHR_TYPE_PTY;
    VIR_FREE(tmp);

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

273 274 275 276 277 278 279 280 281
    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);
282 283 284
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unsupported monitor type '%s'"),
                        virDomainChrTypeToString(priv->monConfig->type));
285 286 287
        goto error;
    }

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



323 324 325 326 327 328 329 330 331
/*
 * 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
 */
332 333 334 335

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

336 337 338 339
static int qemuDomainObjBeginJob(virDomainObjPtr obj) ATTRIBUTE_RETURN_CHECK;
static int qemuDomainObjBeginJob(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;
340 341 342 343
    struct timeval now;
    unsigned long long then;

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

    virDomainObjRef(obj);

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

    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;
386 387 388 389
    struct timeval now;
    unsigned long long then;

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

    virDomainObjRef(obj);
    qemuDriverUnlock(driver);

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

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

439 440
    priv->jobActive = QEMU_JOB_NONE;
    priv->jobSignals = 0;
441
    memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData));
442 443
    priv->jobStart = 0;
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
444 445
    virCondSignal(&priv->jobCond);

446
    return virDomainObjUnref(obj);
447 448 449 450 451 452 453 454 455 456 457
}


/*
 * 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
 */
458 459 460 461 462
static void qemuDomainObjEnterMonitor(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    qemuMonitorLock(priv->mon);
463
    qemuMonitorRef(priv->mon);
464
    virDomainObjUnlock(obj);
465 466 467
}


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

    refs = qemuMonitorUnref(priv->mon);

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

482
    virDomainObjLock(obj);
483 484 485 486 487

    if (refs == 0) {
        virDomainObjUnref(obj);
        priv->mon = NULL;
    }
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
}


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

    refs = qemuMonitorUnref(priv->mon);

    if (refs > 0)
        qemuMonitorUnlock(priv->mon);
524 525 526

    qemuDriverLock(driver);
    virDomainObjLock(obj);
527 528 529 530 531

    if (refs == 0) {
        virDomainObjUnref(obj);
        priv->mon = NULL;
    }
532 533
}

534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
static void qemuDomainObjEnterRemoteWithDriver(struct qemud_driver *driver,
                                               virDomainObjPtr obj)
{
    virDomainObjRef(obj);
    virDomainObjUnlock(obj);
    qemuDriverUnlock(driver);
}

static void qemuDomainObjExitRemoteWithDriver(struct qemud_driver *driver,
                                              virDomainObjPtr obj)
{
    qemuDriverLock(driver);
    virDomainObjLock(obj);
    virDomainObjUnref(obj);
}
549

550 551 552 553 554 555 556 557 558
static int qemuCgroupControllerActive(struct qemud_driver *driver,
                                      int controller)
{
    if (driver->cgroup == NULL)
        return 0;
    if (driver->cgroupControllers & (1 << controller))
        return 1;
    return 0;
}
559

560
static int
561
qemudLogFD(struct qemud_driver *driver, const char* name)
562 563 564
{
    char logfile[PATH_MAX];
    mode_t logmode;
G
Guido Günther 已提交
565
    int ret, fd = -1;
566

567 568
    if ((ret = snprintf(logfile, sizeof(logfile), "%s/%s.log",
                        driver->logDir, name))
G
Guido Günther 已提交
569
        < 0 || ret >= sizeof(logfile)) {
570
        virReportOOMError();
571 572 573 574
        return -1;
    }

    logmode = O_CREAT | O_WRONLY;
575 576
    /* Only logrotate files in /var/log, so only append if running privileged */
    if (driver->privileged)
577
        logmode |= O_APPEND;
578 579 580
    else
        logmode |= O_TRUNC;

581
    if ((fd = open(logfile, logmode, S_IRUSR | S_IWUSR)) < 0) {
582
        virReportSystemError(errno,
583 584
                             _("failed to create logfile %s"),
                             logfile);
585 586
        return -1;
    }
587
    if (virSetCloseExec(fd) < 0) {
588
        virReportSystemError(errno, "%s",
589
                             _("Unable to set VM logfile close-on-exec flag"));
590 591 592 593 594 595 596
        close(fd);
        return -1;
    }
    return fd;
}


597
static int
598
qemudLogReadFD(const char* logDir, const char* name, off_t pos)
599 600 601 602 603 604 605
{
    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)) {
606 607 608
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("failed to build logfile name %s/%s.log"),
                        logDir, name);
609 610 611 612 613
        return -1;
    }


    if ((fd = open(logfile, logmode)) < 0) {
614
        virReportSystemError(errno,
615 616
                             _("failed to create logfile %s"),
                             logfile);
617 618
        return -1;
    }
619
    if (virSetCloseExec(fd) < 0) {
620
        virReportSystemError(errno, "%s",
621
                             _("Unable to set VM logfile close-on-exec flag"));
622 623 624
        close(fd);
        return -1;
    }
625
    if (pos < 0 || lseek(fd, pos, SEEK_SET) < 0) {
626
      virReportSystemError(pos < 0 ? 0 : errno,
627 628
                             _("Unable to seek to %lld in %s"),
                             (long long) pos, logfile);
629 630 631 632 633 634
        close(fd);
    }
    return fd;
}


635 636 637 638 639 640 641 642 643
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;
644
    virErrorPtr err;
645 646

    virDomainObjLock(vm);
647 648 649 650 651 652 653 654 655
    virResetLastError();
    if (qemuDomainObjBeginJobWithDriver(data->driver, vm) < 0) {
        err = virGetLastError();
        VIR_ERROR(_("Failed to start job on VM '%s': %s"),
                  vm->def->name,
                  err ? err->message : _("unknown error"));
    } else {
        if (vm->autostart &&
            !virDomainObjIsActive(vm) &&
656
            qemudDomainObjStart(data->conn, data->driver, vm, false) < 0) {
657
            err = virGetLastError();
658
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
659
                      vm->def->name,
660
                      err ? err->message : _("unknown error"));
661
        }
662 663 664

        if (qemuDomainObjEndJob(vm) == 0)
            vm = NULL;
665
    }
666 667 668

    if (vm)
        virDomainObjUnlock(vm);
669 670
}

671 672
static void
qemudAutostartConfigs(struct qemud_driver *driver) {
673 674 675 676 677
    /* 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
     */
678 679 680
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
681
    /* Ignoring NULL conn which is mostly harmless here */
682
    struct qemuAutostartData data = { driver, conn };
683

684
    qemuDriverLock(driver);
685
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
686
    qemuDriverUnlock(driver);
687

688 689
    if (conn)
        virConnectClose(conn);
690 691
}

692 693 694 695 696 697 698 699 700

/**
 * qemudRemoveDomainStatus
 *
 * remove all state files of a domain from statedir
 *
 * Returns 0 on success
 */
static int
701
qemudRemoveDomainStatus(struct qemud_driver *driver,
702 703
                        virDomainObjPtr vm)
{
704
    char ebuf[1024];
705 706 707
    char *file = NULL;

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

712
    if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR)
713
        VIR_WARN("Failed to remove domain XML for %s: %s",
D
Daniel Veillard 已提交
714 715 716
                 vm->def->name, virStrerror(errno, ebuf, sizeof(ebuf)));
    VIR_FREE(file);

717
    if (virFileDeletePid(driver->stateDir, vm->def->name) != 0)
718
        VIR_WARN("Failed to remove PID file for %s: %s",
719
                 vm->def->name, virStrerror(errno, ebuf, sizeof(ebuf)));
720

D
Daniel Veillard 已提交
721

722
    return 0;
723 724
}

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

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

739
    VIR_DEBUG("Received EOF on %p '%s'", vm, vm->def->name);
740 741 742 743 744 745 746 747
    virDomainObjLock(vm);

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

748
    qemudShutdownVMDaemon(driver, vm, 0);
749 750 751 752 753 754 755 756 757 758 759 760 761
    if (!vm->persistent)
        virDomainRemoveInactive(&driver->domains, vm);
    else
        virDomainObjUnlock(vm);

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


762 763 764
static virDomainDiskDefPtr
findDomainDiskByPath(virDomainObjPtr vm,
                     const char *path)
765 766 767 768 769 770 771
{
    int i;

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

        disk = vm->def->disks[i];
772 773
        if (disk->src != NULL && STREQ(disk->src, path))
            return disk;
774
    }
775 776 777 778

    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                    _("no disk found with path %s"),
                    path);
779 780 781
    return NULL;
}

782 783 784 785 786 787
static virDomainDiskDefPtr
findDomainDiskByAlias(virDomainObjPtr vm,
                      const char *alias)
{
    int i;

788 789 790
    if (STRPREFIX(alias, QEMU_DRIVE_HOST_PREFIX))
        alias += strlen(QEMU_DRIVE_HOST_PREFIX);

791 792 793 794 795 796 797 798 799 800 801 802 803 804
    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;
}

805
static int
806 807 808 809
getVolumeQcowPassphrase(virConnectPtr conn,
                        virDomainDiskDefPtr disk,
                        char **secretRet,
                        size_t *secretLen)
810 811 812 813 814
{
    virSecretPtr secret;
    char *passphrase;
    unsigned char *data;
    size_t size;
815
    int ret = -1;
816
    virStorageEncryptionPtr enc;
817

818 819 820 821 822 823 824
    if (!disk->encryption) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("disk %s does not have any encryption information"),
                        disk->src);
        return -1;
    }
    enc = disk->encryption;
825 826

    if (!conn) {
827 828
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cannot find secrets without a connection"));
829
        goto cleanup;
830 831 832 833 834
    }

    if (conn->secretDriver == NULL ||
        conn->secretDriver->lookupByUUID == NULL ||
        conn->secretDriver->getValue == NULL) {
835 836
        qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                        _("secret storage not supported"));
837
        goto cleanup;
838 839 840 841 842 843
    }

    if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW ||
        enc->nsecrets != 1 ||
        enc->secrets[0]->type !=
        VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) {
844
        qemuReportError(VIR_ERR_INVALID_DOMAIN,
845
                        _("invalid <encryption> for volume %s"), disk->src);
846
        goto cleanup;
847 848 849 850 851
    }

    secret = conn->secretDriver->lookupByUUID(conn,
                                              enc->secrets[0]->uuid);
    if (secret == NULL)
852
        goto cleanup;
853 854 855 856
    data = conn->secretDriver->getValue(secret, &size,
                                        VIR_SECRET_GET_VALUE_INTERNAL_CALL);
    virUnrefSecret(secret);
    if (data == NULL)
857
        goto cleanup;
858 859 860 861

    if (memchr(data, '\0', size) != NULL) {
        memset(data, 0, size);
        VIR_FREE(data);
862 863
        qemuReportError(VIR_ERR_INVALID_SECRET,
                        _("format='qcow' passphrase for %s must not contain a "
864
                          "'\\0'"), disk->src);
865
        goto cleanup;
866 867 868 869 870
    }

    if (VIR_ALLOC_N(passphrase, size + 1) < 0) {
        memset(data, 0, size);
        VIR_FREE(data);
871
        virReportOOMError();
872
        goto cleanup;
873 874 875 876 877 878 879 880 881 882
    }
    memcpy(passphrase, data, size);
    passphrase[size] = '\0';

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

    *secretRet = passphrase;
    *secretLen = size;

883 884 885
    ret = 0;

cleanup:
886 887
    return ret;
}
888

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
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);
910
    return ret;
911 912
}

913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934

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


935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
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;
}


967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
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;
}


996 997 998 999 1000 1001
static int
qemuHandleDomainWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                         virDomainObjPtr vm,
                         int action)
{
    struct qemud_driver *driver = qemu_driver;
1002 1003
    virDomainEventPtr watchdogEvent = NULL;
    virDomainEventPtr lifecycleEvent = NULL;
1004 1005

    virDomainObjLock(vm);
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
    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);
    }
1020 1021
    virDomainObjUnlock(vm);

1022
    if (watchdogEvent || lifecycleEvent) {
1023
        qemuDriverLock(driver);
1024 1025 1026 1027
        if (watchdogEvent)
            qemuDomainEventQueue(driver, watchdogEvent);
        if (lifecycleEvent)
            qemuDomainEventQueue(driver, lifecycleEvent);
1028 1029 1030 1031 1032 1033 1034
        qemuDriverUnlock(driver);
    }

    return 0;
}


1035 1036 1037 1038
static int
qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                        virDomainObjPtr vm,
                        const char *diskAlias,
1039 1040
                        int action,
                        const char *reason)
1041 1042
{
    struct qemud_driver *driver = qemu_driver;
1043
    virDomainEventPtr ioErrorEvent = NULL;
1044
    virDomainEventPtr ioErrorEvent2 = NULL;
1045
    virDomainEventPtr lifecycleEvent = NULL;
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
    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 = "";
    }

1061
    ioErrorEvent = virDomainEventIOErrorNewFromObj(vm, srcPath, devAlias, action);
1062
    ioErrorEvent2 = virDomainEventIOErrorReasonNewFromObj(vm, srcPath, devAlias, action, reason);
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075

    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);
    }
1076 1077
    virDomainObjUnlock(vm);

1078
    if (ioErrorEvent || ioErrorEvent2 || lifecycleEvent) {
1079
        qemuDriverLock(driver);
1080 1081
        if (ioErrorEvent)
            qemuDomainEventQueue(driver, ioErrorEvent);
1082 1083
        if (ioErrorEvent2)
            qemuDomainEventQueue(driver, ioErrorEvent2);
1084 1085
        if (lifecycleEvent)
            qemuDomainEventQueue(driver, lifecycleEvent);
1086 1087 1088 1089 1090 1091 1092
        qemuDriverUnlock(driver);
    }

    return 0;
}


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 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
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;
}


1185 1186 1187 1188 1189 1190 1191 1192 1193
static void qemuHandleMonitorDestroy(qemuMonitorPtr mon,
                                     virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    if (priv->mon == mon)
        priv->mon = NULL;
    virDomainObjUnref(vm);
}

1194
static qemuMonitorCallbacks monitorCallbacks = {
1195
    .destroy = qemuHandleMonitorDestroy,
1196 1197
    .eofNotify = qemuHandleMonitorEOF,
    .diskSecretLookup = findVolumeQcowPassphrase,
1198
    .domainStop = qemuHandleDomainStop,
1199
    .domainReset = qemuHandleDomainReset,
1200
    .domainRTCChange = qemuHandleDomainRTCChange,
1201
    .domainWatchdog = qemuHandleDomainWatchdog,
1202
    .domainIOError = qemuHandleDomainIOError,
1203
    .domainGraphics = qemuHandleDomainGraphics,
1204 1205
};

1206
static int
1207
qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
1208
{
1209
    qemuDomainObjPrivatePtr priv = vm->privateData;
1210
    int ret = -1;
1211

1212 1213 1214 1215 1216 1217
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecuritySocketLabel &&
        driver->securityDriver->domainSetSecuritySocketLabel
          (driver->securityDriver,vm) < 0) {
        VIR_ERROR(_("Failed to set security context for monitor for %s"),
                  vm->def->name);
1218 1219 1220
        goto error;
    }

1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
    /* Hold an extra reference because we can't allow 'vm' to be
     * deleted while the monitor is active */
    virDomainObjRef(vm);

    priv->mon = qemuMonitorOpen(vm,
                                priv->monConfig,
                                priv->monJSON,
                                &monitorCallbacks);

    if (priv->mon == NULL)
        virDomainObjUnref(vm);
1232

1233 1234 1235 1236 1237 1238
    if (driver->securityDriver &&
        driver->securityDriver->domainClearSecuritySocketLabel &&
        driver->securityDriver->domainClearSecuritySocketLabel
          (driver->securityDriver,vm) < 0) {
        VIR_ERROR(_("Failed to clear security context for monitor for %s"),
                  vm->def->name);
1239
        goto error;
1240
    }
1241

1242 1243 1244 1245 1246 1247
    if (priv->mon == NULL) {
        VIR_INFO("Failed to connect monitor for %s", vm->def->name);
        goto error;
    }


1248 1249 1250 1251
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorSetCapabilities(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

1252 1253
    ret = 0;
error:
1254
    if (ret < 0)
1255 1256 1257
        qemuMonitorClose(priv->mon);

    return ret;
1258
}
1259 1260 1261 1262

/*
 * Open an existing VM's monitor, re-detect VCPU threads
 * and re-reserve the security labels in use
1263
 */
1264 1265
static void
qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
1266
{
1267 1268
    virDomainObjPtr obj = payload;
    struct qemud_driver *driver = opaque;
1269
    qemuDomainObjPrivatePtr priv;
1270
    unsigned long long qemuCmdFlags;
1271 1272

    virDomainObjLock(obj);
1273

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

1276 1277
    priv = obj->privateData;

1278
    /* XXX check PID liveliness & EXE path */
1279
    if (qemuConnectMonitor(driver, obj) < 0)
1280
        goto error;
1281

1282 1283 1284 1285
    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
        goto error;
    }

1286 1287 1288 1289 1290 1291 1292 1293 1294
    /* 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;

1295 1296 1297
    if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(obj->def)))
        goto error;

1298
    if (driver->securityDriver &&
1299
        driver->securityDriver->domainReserveSecurityLabel &&
1300 1301
        driver->securityDriver->domainReserveSecurityLabel(driver->securityDriver,
                                                           obj) < 0)
1302
        goto error;
1303

1304 1305
    if (obj->def->id >= driver->nextvmid)
        driver->nextvmid = obj->def->id + 1;
1306

1307 1308
    virDomainObjUnlock(obj);
    return;
1309

1310
error:
1311 1312 1313
    /* 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 */
1314
    qemudShutdownVMDaemon(driver, obj, 0);
1315 1316 1317 1318
    if (!obj->persistent)
        virDomainRemoveInactive(&driver->domains, obj);
    else
        virDomainObjUnlock(obj);
1319
}
1320

1321
/**
1322
 * qemudReconnectDomains
1323 1324 1325 1326 1327 1328 1329
 *
 * Try to re-open the resources for live VMs that we care
 * about.
 */
static void
qemuReconnectDomains(struct qemud_driver *driver)
{
1330
    virHashForEach(driver->domains.objs, qemuReconnectDomain, driver);
1331 1332
}

1333

1334 1335 1336 1337 1338 1339
static int
qemudSecurityInit(struct qemud_driver *qemud_drv)
{
    int ret;
    virSecurityDriverPtr security_drv;

1340 1341 1342
    qemuSecurityStackedSetDriver(qemud_drv);
    qemuSecurityDACSetDriver(qemud_drv);

1343
    ret = virSecurityDriverStartup(&security_drv,
1344 1345
                                   qemud_drv->securityDriverName,
                                   qemud_drv->allowDiskFormatProbing);
1346 1347 1348 1349
    if (ret == -1) {
        VIR_ERROR0(_("Failed to start security driver"));
        return -1;
    }
1350 1351 1352

    /* No primary security driver wanted to be enabled: just setup
     * the DAC driver on its own */
1353
    if (ret == -2) {
1354
        qemud_drv->securityDriver = &qemuDACSecurityDriver;
1355
        VIR_INFO0(_("No security driver available"));
1356 1357 1358 1359 1360
    } else {
        qemud_drv->securityPrimaryDriver = security_drv;
        qemud_drv->securitySecondaryDriver = &qemuDACSecurityDriver;
        qemud_drv->securityDriver = &qemuStackedSecurityDriver;
        VIR_INFO("Initialized security driver %s", security_drv->name);
1361 1362
    }

1363
    return 0;
1364
}
1365 1366


1367 1368
static virCapsPtr
qemuCreateCapabilities(virCapsPtr oldcaps,
1369
                       struct qemud_driver *driver)
1370 1371 1372 1373 1374
{
    virCapsPtr caps;

    /* Basic host arch / guest machine capabilities */
    if (!(caps = qemudCapsInit(oldcaps))) {
1375
        virReportOOMError();
1376 1377 1378
        return NULL;
    }

1379 1380 1381 1382 1383 1384 1385 1386
    if (driver->allowDiskFormatProbing) {
        caps->defaultDiskDriverName = NULL;
        caps->defaultDiskDriverType = NULL;
    } else {
        caps->defaultDiskDriverName = "qemu";
        caps->defaultDiskDriverType = "raw";
    }

1387 1388 1389 1390 1391 1392
    /* Domain XML parser hooks */
    caps->privateDataAllocFunc = qemuDomainObjPrivateAlloc;
    caps->privateDataFreeFunc = qemuDomainObjPrivateFree;
    caps->privateDataXMLFormat = qemuDomainObjPrivateXMLFormat;
    caps->privateDataXMLParse = qemuDomainObjPrivateXMLParse;

1393 1394 1395 1396 1397
    if (virGetHostUUID(caps->host.host_uuid)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot get the host uuid"));
        goto err_exit;
    }
1398 1399

    /* Security driver data */
1400
    if (driver->securityPrimaryDriver) {
1401 1402
        const char *doi, *model;

1403 1404
        doi = virSecurityDriverGetDOI(driver->securityPrimaryDriver);
        model = virSecurityDriverGetModel(driver->securityPrimaryDriver);
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417

        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:
1418
    virReportOOMError();
1419
err_exit:
1420 1421 1422
    virCapabilitiesFree(caps);
    return NULL;
}
1423

C
Chris Lalancette 已提交
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
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) {
1441
        VIR_ERROR(_("Failed to allocate memory for snapshot directory for domain %s"),
C
Chris Lalancette 已提交
1442 1443 1444 1445 1446 1447 1448 1449 1450
                   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)
1451
            VIR_ERROR(_("Failed to open snapshot directory %s for domain %s: %s"),
C
Chris Lalancette 已提交
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
                      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) {
1466
            VIR_ERROR0(_("Failed to allocate memory for path"));
C
Chris Lalancette 已提交
1467 1468 1469 1470 1471 1472
            continue;
        }

        ret = virFileReadAll(fullpath, 1024*1024*1, &xmlStr);
        if (ret < 0) {
            /* Nothing we can do here, skip this one */
1473
            VIR_ERROR(_("Failed to read snapshot file %s: %s"), fullpath,
C
Chris Lalancette 已提交
1474
                      virStrerror(errno, ebuf, sizeof(ebuf)));
1475
            VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1476 1477 1478 1479 1480 1481
            continue;
        }

        def = virDomainSnapshotDefParseString(xmlStr, 0);
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
1482
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"), fullpath);
1483
            VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1484 1485 1486 1487
            VIR_FREE(xmlStr);
            continue;
        }

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

1490
        VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
        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);
}

1512 1513 1514 1515 1516 1517
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
1518
qemudStartup(int privileged) {
1519
    char *base = NULL;
D
Daniel P. Berrange 已提交
1520
    char driverConf[PATH_MAX];
1521
    int rc;
1522

1523
    if (VIR_ALLOC(qemu_driver) < 0)
1524 1525
        return -1;

1526
    if (virMutexInit(&qemu_driver->lock) < 0) {
1527
        VIR_ERROR0(_("cannot initialize mutex"));
1528 1529 1530
        VIR_FREE(qemu_driver);
        return -1;
    }
1531
    qemuDriverLock(qemu_driver);
1532
    qemu_driver->privileged = privileged;
1533

1534 1535 1536
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;

1537 1538 1539
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;

1540
    /* Init callback list */
1541
    if (VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
1542
        goto out_of_memory;
1543 1544 1545 1546 1547 1548
    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
        goto out_of_memory;

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

1550 1551 1552 1553 1554
    /* Allocate bitmap for vnc port reservation */
    if ((qemu_driver->reservedVNCPorts =
         virBitmapAlloc(QEMU_VNC_PORT_MAX - QEMU_VNC_PORT_MIN)) == NULL)
        goto out_of_memory;

1555
    if (privileged) {
1556 1557
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1)
1558
            goto out_of_memory;
1559

D
Daniel P. Berrange 已提交
1560
        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
1561
            goto out_of_memory;
1562 1563

        if (virAsprintf(&qemu_driver->stateDir,
1564
                      "%s/run/libvirt/qemu", LOCAL_STATE_DIR) == -1)
1565
            goto out_of_memory;
1566 1567 1568 1569 1570 1571 1572 1573

        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;
1574 1575 1576
        if (virAsprintf(&qemu_driver->saveDir,
                      "%s/lib/libvirt/qemu/save/", LOCAL_STATE_DIR) == -1)
            goto out_of_memory;
C
Chris Lalancette 已提交
1577 1578 1579
        if (virAsprintf(&qemu_driver->snapshotDir,
                        "%s/lib/libvirt/qemu/snapshot", LOCAL_STATE_DIR) == -1)
            goto out_of_memory;
1580
    } else {
1581
        uid_t uid = geteuid();
1582
        char *userdir = virGetUserDirectory(uid);
1583
        if (!userdir)
1584
            goto error;
1585

1586
        if (virAsprintf(&qemu_driver->logDir,
1587 1588
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
1589
            goto out_of_memory;
1590
        }
1591

1592 1593
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
1594
            goto out_of_memory;
1595 1596
        }
        VIR_FREE(userdir);
1597 1598 1599

        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
            goto out_of_memory;
1600 1601 1602 1603
        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;
1604 1605
        if (virAsprintf(&qemu_driver->saveDir, "%s/qemu/save", base) == -1)
            goto out_of_memory;
C
Chris Lalancette 已提交
1606 1607
        if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
            goto out_of_memory;
1608 1609
    }

L
Laine Stump 已提交
1610
    if (virFileMakePath(qemu_driver->stateDir) != 0) {
1611
        char ebuf[1024];
1612
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
1613
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
1614
        goto error;
1615
    }
L
Laine Stump 已提交
1616
    if (virFileMakePath(qemu_driver->libDir) != 0) {
1617
        char ebuf[1024];
1618
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
1619 1620 1621
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
L
Laine Stump 已提交
1622
    if (virFileMakePath(qemu_driver->cacheDir) != 0) {
1623
        char ebuf[1024];
1624
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
1625 1626 1627
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
1628 1629 1630 1631 1632 1633
    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 已提交
1634 1635 1636 1637 1638 1639
    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;
    }
1640 1641 1642 1643

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

1648
    if (virAsprintf(&qemu_driver->configDir, "%s/qemu", base) == -1)
1649 1650
        goto out_of_memory;

1651
    if (virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1)
1652 1653
        goto out_of_memory;

1654
    VIR_FREE(base);
1655

1656 1657 1658 1659 1660 1661 1662
    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)));
    }

1663 1664 1665 1666
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
        goto error;
    }

1667 1668
    if (qemudSecurityInit(qemu_driver) < 0)
        goto error;
D
Daniel P. Berrange 已提交
1669

1670
    if ((qemu_driver->caps = qemuCreateCapabilities(NULL,
1671
                                                    qemu_driver)) == NULL)
1672
        goto error;
1673

1674
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
1675 1676
        goto error;

1677 1678
    if (privileged) {
        if (chown(qemu_driver->libDir, qemu_driver->user, qemu_driver->group) < 0) {
1679
            virReportSystemError(errno,
1680 1681 1682 1683 1684
                                 _("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) {
1685
            virReportSystemError(errno,
1686 1687 1688 1689
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
1690 1691 1692 1693 1694 1695
        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 已提交
1696 1697 1698 1699 1700 1701
        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;
        }
1702 1703
    }

1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717
    /* 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) {
1718
            virReportSystemError(rc,
1719 1720 1721 1722 1723 1724
                                 _("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) {
1725
            virReportSystemError(errno,
1726 1727 1728 1729 1730 1731 1732 1733 1734
                                 _("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;
    }

1735
    /* Get all the running persistent or transient configs first */
1736
    if (virDomainLoadAllConfigs(qemu_driver->caps,
1737 1738 1739 1740 1741 1742 1743 1744 1745
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
                                1, NULL, NULL) < 0)
        goto error;

    qemuReconnectDomains(qemu_driver);

    /* Then inactive persistent configs */
1746
    if (virDomainLoadAllConfigs(qemu_driver->caps,
1747 1748
                                &qemu_driver->domains,
                                qemu_driver->configDir,
1749
                                qemu_driver->autostartDir,
1750
                                0, NULL, NULL) < 0)
1751
        goto error;
C
Chris Lalancette 已提交
1752 1753 1754 1755 1756


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

1757 1758
    qemuDriverUnlock(qemu_driver);

1759 1760
    qemudAutostartConfigs(qemu_driver);

1761

1762 1763
    return 0;

1764
out_of_memory:
1765
    virReportOOMError();
1766 1767 1768
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
1769
    VIR_FREE(base);
1770
    qemudShutdown();
1771 1772 1773
    return -1;
}

1774 1775 1776 1777
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;

1778 1779 1780 1781 1782 1783 1784 1785
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }
1786 1787
}

1788 1789 1790 1791 1792 1793 1794 1795
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
1796 1797 1798
    if (!qemu_driver)
        return 0;

1799
    qemuDriverLock(qemu_driver);
1800
    virDomainLoadAllConfigs(qemu_driver->caps,
1801 1802
                            &qemu_driver->domains,
                            qemu_driver->configDir,
1803
                            qemu_driver->autostartDir,
1804
                            0, qemudNotifyLoadDomain, qemu_driver);
1805
    qemuDriverUnlock(qemu_driver);
1806

1807
    qemudAutostartConfigs(qemu_driver);
1808 1809

    return 0;
1810 1811
}

1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
/**
 * 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) {
1822
    int active = 0;
1823

1824 1825 1826
    if (!qemu_driver)
        return 0;

1827
    /* XXX having to iterate here is not great because it requires many locks */
1828
    qemuDriverLock(qemu_driver);
1829
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
1830 1831
    qemuDriverUnlock(qemu_driver);
    return active;
1832 1833
}

1834 1835 1836 1837 1838 1839 1840
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
1841
    int i;
1842

1843
    if (!qemu_driver)
1844
        return -1;
1845

1846
    qemuDriverLock(qemu_driver);
1847
    pciDeviceListFree(qemu_driver->activePciHostdevs);
1848 1849
    virCapabilitiesFree(qemu_driver->caps);

1850
    virDomainObjListDeinit(&qemu_driver->domains);
1851
    virBitmapFree(qemu_driver->reservedVNCPorts);
1852

1853
    VIR_FREE(qemu_driver->securityDriverName);
1854
    VIR_FREE(qemu_driver->logDir);
1855 1856
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
1857
    VIR_FREE(qemu_driver->stateDir);
1858 1859
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
1860
    VIR_FREE(qemu_driver->saveDir);
C
Chris Lalancette 已提交
1861
    VIR_FREE(qemu_driver->snapshotDir);
1862
    VIR_FREE(qemu_driver->vncTLSx509certdir);
J
Jim Meyering 已提交
1863
    VIR_FREE(qemu_driver->vncListen);
1864
    VIR_FREE(qemu_driver->vncPassword);
1865
    VIR_FREE(qemu_driver->vncSASLdir);
1866
    VIR_FREE(qemu_driver->saveImageFormat);
1867 1868
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
D
Daniel P. Berrange 已提交
1869

1870 1871 1872 1873 1874 1875
    if (qemu_driver->cgroupDeviceACL) {
        for (i = 0 ; qemu_driver->cgroupDeviceACL[i] != NULL ; i++)
            VIR_FREE(qemu_driver->cgroupDeviceACL[i]);
        VIR_FREE(qemu_driver->cgroupDeviceACL);
    }

1876 1877
    /* Free domain callback list */
    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
1878 1879 1880 1881
    virDomainEventQueueFree(qemu_driver->domainEventQueue);

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

1883 1884 1885
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);

1886 1887
    virCgroupFree(&qemu_driver->cgroup);

1888
    qemuDriverUnlock(qemu_driver);
1889
    virMutexDestroy(&qemu_driver->lock);
1890
    VIR_FREE(qemu_driver);
1891 1892

    return 0;
1893 1894
}

1895
typedef int qemuLogHandleOutput(virDomainObjPtr vm,
1896 1897
                                const char *output,
                                int fd);
1898 1899 1900 1901 1902

/*
 * Returns -1 for error, 0 on success
 */
static int
1903
qemudReadLogOutput(virDomainObjPtr vm,
1904 1905
                   int fd,
                   char *buf,
G
Guido Günther 已提交
1906
                   size_t buflen,
1907
                   qemuLogHandleOutput func,
1908 1909 1910
                   const char *what,
                   int timeout)
{
1911
    int retries = (timeout*10);
1912
    int got = 0;
1913 1914 1915
    buf[0] = '\0';

    while (retries) {
1916
        ssize_t func_ret, ret;
1917
        int isdead = 0;
G
Guido Günther 已提交
1918

1919
        func_ret = func(vm, buf, fd);
1920

1921 1922
        if (kill(vm->pid, 0) == -1 && errno == ESRCH)
            isdead = 1;
1923

1924 1925
        /* Any failures should be detected before we read the log, so we
         * always have something useful to report on failure. */
1926 1927
        ret = saferead(fd, buf+got, buflen-got-1);
        if (ret < 0) {
1928
            virReportSystemError(errno,
1929 1930 1931 1932 1933
                                 _("Failure while reading %s log output"),
                                 what);
            return -1;
        }

1934 1935 1936
        got += ret;
        buf[got] = '\0';
        if (got == buflen-1) {
1937
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
1938 1939
                            _("Out of space while reading %s log output: %s"),
                            what, buf);
1940 1941 1942 1943
            return -1;
        }

        if (isdead) {
1944
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
1945 1946
                            _("Process exited while reading %s log output: %s"),
                            what, buf);
1947 1948 1949
            return -1;
        }

1950 1951
        if (func_ret <= 0)
            return func_ret;
1952 1953 1954 1955

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

1957
    qemuReportError(VIR_ERR_INTERNAL_ERROR,
1958 1959
                    _("Timed out while reading %s log output: %s"),
                    what, buf);
1960 1961 1962
    return -1;
}

1963

1964 1965 1966 1967 1968 1969 1970 1971
/*
 * 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
 */
1972
static int
1973
qemudExtractTTYPath(const char *haystack,
1974 1975
                    size_t *offset,
                    char **path)
1976
{
1977
    static const char needle[] = "char device redirected to";
1978
    char *tmp, *dev;
1979

1980
    VIR_FREE(*path);
1981
    /* First look for our magic string */
1982 1983 1984 1985 1986
    if (!(tmp = strstr(haystack + *offset, needle))) {
        return 1;
    }
    tmp += sizeof(needle);
    dev = tmp;
1987

1988 1989 1990 1991 1992
    /*
     * And look for first whitespace character and nul terminate
     * to mark end of the pty path
     */
    while (*tmp) {
1993
        if (c_isspace(*tmp)) {
1994 1995
            *path = strndup(dev, tmp-dev);
            if (*path == NULL) {
1996
                virReportOOMError();
1997 1998
                return -1;
            }
1999

2000
            /* ... now further update offset till we get EOL */
2001
            *offset = tmp - haystack;
2002 2003
            return 0;
        }
2004
        tmp++;
2005 2006 2007 2008 2009
    }

    /*
     * We found a path, but didn't find any whitespace,
     * so it must be still incomplete - we should at
2010 2011
     * least see a \n - indicate that we want to carry
     * on trying again
2012
     */
2013
    return 1;
2014 2015
}

2016
static int
2017
qemudFindCharDevicePTYsMonitor(virDomainObjPtr vm,
2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
                               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) {                                           \
2033 2034 2035
                if (chr->data.file.path == NULL) {                        \
                    /* neither the log output nor 'info chardev' had a */ \
                    /* pty path for this chardev, report an error */      \
2036 2037 2038
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,               \
                                    _("no assigned pty for device %s"), id); \
                    return -1;                                            \
2039 2040 2041 2042 2043
                } else {                                                  \
                    /* 'info chardev' had no pty path for this chardev, */\
                    /* but the log output had, so we're fine */           \
                    continue;                                             \
                }                                                         \
2044 2045
            }                                                             \
                                                                          \
2046
            VIR_FREE(chr->data.file.path);                                \
2047
            chr->data.file.path = strdup(path);                           \
2048 2049
                                                                          \
            if (chr->data.file.path == NULL) {                            \
2050
                virReportOOMError();                                      \
2051 2052
                return -1;                                                \
            }                                                             \
2053 2054 2055 2056 2057 2058
        }                                                                 \
    }

    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");
2059
#undef LOOKUP_PTYS
2060 2061 2062 2063

    return 0;
}

2064
static int
2065
qemudFindCharDevicePTYs(virDomainObjPtr vm,
2066 2067
                        const char *output,
                        int fd ATTRIBUTE_UNUSED)
2068
{
2069
    size_t offset = 0;
2070
    int ret, i;
2071 2072

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

2076
    /* first comes the serial devices */
2077 2078
    for (i = 0 ; i < vm->def->nserials ; i++) {
        virDomainChrDefPtr chr = vm->def->serials[i];
2079
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
2080
            if ((ret = qemudExtractTTYPath(output, &offset,
2081
                                           &chr->data.file.path)) != 0)
2082
                return ret;
2083 2084 2085
        }
    }

2086
    /* then the parallel devices */
2087 2088
    for (i = 0 ; i < vm->def->nparallels ; i++) {
        virDomainChrDefPtr chr = vm->def->parallels[i];
2089
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
2090
            if ((ret = qemudExtractTTYPath(output, &offset,
2091
                                           &chr->data.file.path)) != 0)
2092
                return ret;
2093 2094 2095
        }
    }

2096 2097 2098 2099
    /* 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) {
2100
            if ((ret = qemudExtractTTYPath(output, &offset,
2101 2102 2103 2104 2105
                                           &chr->data.file.path)) != 0)
                return ret;
        }
    }

2106
    return 0;
2107 2108
}

2109 2110 2111 2112 2113
static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED)
{
    VIR_FREE(payload);
}

2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127
static void
qemuReadLogFD(int logfd, char *buf, int maxlen, int off)
{
    int ret;
    char *tmpbuf = buf + off;

    ret = saferead(logfd, tmpbuf, maxlen - off - 1);
    if (ret < 0) {
        ret = 0;
    }

    tmpbuf[ret] = '\0';
}

2128
static int
2129
qemudWaitForMonitor(struct qemud_driver* driver,
2130
                    virDomainObjPtr vm, off_t pos)
2131
{
2132
    char buf[4096] = ""; /* Plenty of space to get startup greeting */
2133
    int logfd;
2134
    int ret = -1;
2135
    virHashTablePtr paths = NULL;
2136

2137
    if ((logfd = qemudLogReadFD(driver->logDir, vm->def->name, pos)) < 0)
2138
        return -1;
2139

2140 2141 2142 2143
    if (qemudReadLogOutput(vm, logfd, buf, sizeof(buf),
                           qemudFindCharDevicePTYs,
                           "console", 30) < 0)
        goto closelog;
2144

2145
    VIR_DEBUG("Connect monitor to %p '%s'", vm, vm->def->name);
2146 2147 2148
    if (qemuConnectMonitor(driver, vm) < 0) {
        goto cleanup;
    }
2149

2150 2151 2152 2153
    /* 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. */
2154
    paths = virHashCreate(0);
2155
    if (paths == NULL) {
2156
        virReportOOMError();
2157 2158 2159
        goto cleanup;
    }

2160
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2161 2162
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ret = qemuMonitorGetPtyPaths(priv->mon, paths);
2163
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2164 2165 2166

    VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret);
    if (ret == 0) {
2167
        ret = qemudFindCharDevicePTYsMonitor(vm, paths);
2168 2169 2170 2171 2172 2173 2174
    }

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

2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187
    if (kill(vm->pid, 0) == -1 && errno == ESRCH) {
        /* VM is dead, any other error raised in the interim is probably
         * not as important as the qemu cmdline output */
        qemuReadLogFD(logfd, buf, sizeof(buf), strlen(buf));
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("process exited while connecting to monitor: %s"),
                        buf);
        ret = -1;
    }

closelog:
    if (close(logfd) < 0) {
        char ebuf[4096];
2188
        VIR_WARN("Unable to close logfile: %s",
2189 2190 2191
                 virStrerror(errno, ebuf, sizeof ebuf));
    }

2192
    return ret;
2193 2194
}

2195
static int
2196
qemuDetectVcpuPIDs(struct qemud_driver *driver,
2197 2198 2199
                   virDomainObjPtr vm) {
    pid_t *cpupids = NULL;
    int ncpupids;
2200
    qemuDomainObjPrivatePtr priv = vm->privateData;
2201

2202
    if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
2203 2204
        priv->nvcpupids = 1;
        if (VIR_ALLOC_N(priv->vcpupids, priv->nvcpupids) < 0) {
2205
            virReportOOMError();
2206 2207
            return -1;
        }
2208
        priv->vcpupids[0] = vm->pid;
2209 2210 2211
        return 0;
    }

2212
    /* What follows is now all KVM specific */
2213

2214
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2215
    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) < 0) {
2216
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2217
        return -1;
2218
    }
2219
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2220

2221 2222 2223
    /* Treat failure to get VCPU<->PID mapping as non-fatal */
    if (ncpupids == 0)
        return 0;
2224

2225
    if (ncpupids != vm->def->vcpus) {
2226 2227 2228
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"),
                        ncpupids, (int)vm->def->vcpus);
2229 2230 2231
        VIR_FREE(cpupids);
        return -1;
    }
2232

2233 2234
    priv->nvcpupids = ncpupids;
    priv->vcpupids = cpupids;
2235 2236 2237
    return 0;
}

2238 2239 2240
/*
 * To be run between fork/exec of QEMU only
 */
2241
static int
2242 2243
qemudInitCpuAffinity(virDomainObjPtr vm)
{
2244
    int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN;
2245
    virNodeInfo nodeinfo;
2246 2247
    unsigned char *cpumap;
    int cpumaplen;
2248 2249

    DEBUG0("Setting CPU affinity");
2250

2251
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
2252 2253 2254 2255
        return -1;

    /* setaffinity fails if you set bits for CPUs which
     * aren't present, so we have to limit ourselves */
2256 2257 2258
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
2259

2260 2261
    cpumaplen = VIR_CPU_MAPLEN(maxcpu);
    if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) {
2262
        virReportOOMError();
2263 2264 2265
        return -1;
    }

D
Daniel P. Berrange 已提交
2266
    if (vm->def->cpumask) {
2267 2268 2269
        /* 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 已提交
2270
            if (vm->def->cpumask[i])
2271
                VIR_USE_CPU(cpumap, i);
D
Daniel P. Berrange 已提交
2272
    } else {
2273 2274 2275 2276
        /* 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 已提交
2277
        for (i = 0 ; i < maxcpu ; i++)
2278
            VIR_USE_CPU(cpumap, i);
D
Daniel P. Berrange 已提交
2279
    }
2280

2281 2282 2283 2284 2285 2286 2287 2288
    /* 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;
2289
    }
2290
    VIR_FREE(cpumap);
2291 2292 2293 2294 2295

    return 0;
}


2296
static int
2297 2298 2299 2300
qemuInitPasswords(virConnectPtr conn,
                  struct qemud_driver *driver,
                  virDomainObjPtr vm,
                  unsigned long long qemuCmdFlags) {
2301
    int ret = 0;
2302
    qemuDomainObjPrivatePtr priv = vm->privateData;
2303

2304 2305 2306
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) {
2307

2308
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
2309
        ret = qemuMonitorSetVNCPassword(priv->mon,
2310 2311 2312
                                        vm->def->graphics[0]->data.vnc.passwd ?
                                        vm->def->graphics[0]->data.vnc.passwd :
                                        driver->vncPassword);
2313
        qemuDomainObjExitMonitorWithDriver(driver, vm);
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
    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);
2339
            VIR_FREE(secret);
2340 2341 2342 2343 2344 2345 2346
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (ret < 0)
                goto cleanup;
        }
    }

cleanup:
2347
    return ret;
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 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579
#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
2580
qemuDetectPCIAddresses(virDomainObjPtr vm,
2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597
                       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) {
2598 2599 2600
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for VirtIO disk %s"),
                            vm->def->disks[i]->dst);
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611
            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) {
2612 2613 2614
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for %s NIC"),
                            vm->def->nets[i]->model);
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625
            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) {
2626 2627 2628
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for controller %s"),
                            virDomainControllerTypeToString(vm->def->controllers[i]->type));
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639
            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) {
2640 2641 2642
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for video adapter %s"),
                            virDomainVideoTypeToString(vm->def->videos[i]->type));
2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653
            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) {
2654 2655 2656
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for sound adapter %s"),
                            virDomainSoundModelTypeToString(vm->def->sounds[i]->model));
2657 2658 2659 2660 2661 2662 2663 2664 2665 2666
            return -1;
        }
    }


    if (vm->def->watchdog &&
        qemuGetPCIWatchdogVendorProduct(vm->def->watchdog, &vendor, &product) == 0) {
        if (qemuAssignNextPCIAddress(&(vm->def->watchdog->info),
                                     vendor, product,
                                     addrs,  naddrs) < 0) {
2667 2668 2669
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for watchdog %s"),
                            virDomainWatchdogModelTypeToString(vm->def->watchdog->model));
2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
            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);

2702
    ret = qemuDetectPCIAddresses(vm, addrs, naddrs);
2703 2704 2705 2706 2707 2708

    VIR_FREE(addrs);

    return ret;
}

2709
static int qemudNextFreeVNCPort(struct qemud_driver *driver) {
2710 2711
    int i;

2712
    for (i = QEMU_VNC_PORT_MIN; i < QEMU_VNC_PORT_MAX; i++) {
2713 2714 2715
        int fd;
        int reuse = 1;
        struct sockaddr_in addr;
2716 2717 2718 2719 2720 2721 2722 2723 2724
        bool used = false;

        if (virBitmapGetBit(driver->reservedVNCPorts,
                            i - QEMU_VNC_PORT_MIN, &used) < 0)
            VIR_DEBUG("virBitmapGetBit failed on bit %d", i - QEMU_VNC_PORT_MIN);

        if (used)
            continue;

2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
        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);
2740 2741 2742 2743 2744 2745
            /* Add port to bitmap of reserved ports */
            if (virBitmapSetBit(driver->reservedVNCPorts,
                                i - QEMU_VNC_PORT_MIN) < 0) {
                VIR_DEBUG("virBitmapSetBit failed on bit %d",
                          i - QEMU_VNC_PORT_MIN);
            }
2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759
            return i;
        }
        close(fd);

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

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

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


2798
static pciDeviceList *
2799
qemuGetPciHostDeviceList(virDomainDefPtr def)
2800 2801
{
    pciDeviceList *list;
2802 2803
    int i;

2804
    if (!(list = pciDeviceListNew()))
2805
        return NULL;
2806 2807 2808 2809 2810 2811 2812 2813 2814 2815

    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;

2816
        dev = pciGetDevice(hostdev->source.subsys.u.pci.domain,
2817 2818 2819
                           hostdev->source.subsys.u.pci.bus,
                           hostdev->source.subsys.u.pci.slot,
                           hostdev->source.subsys.u.pci.function);
2820
        if (!dev) {
2821
            pciDeviceListFree(list);
2822 2823
            return NULL;
        }
2824

2825 2826 2827
        if (pciDeviceListAdd(list, dev) < 0) {
            pciFreeDevice(dev);
            pciDeviceListFree(list);
2828
            return NULL;
2829 2830
        }

2831
        pciDeviceSetManaged(dev, hostdev->managed);
2832 2833
    }

2834 2835 2836 2837
    return list;
}

static int
2838 2839 2840 2841
qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                            virDomainDefPtr def)
{
    pciDeviceList *pcidevs;
2842
    int i;
2843
    int ret = -1;
2844 2845 2846 2847

    if (!def->nhostdevs)
        return 0;

2848
    if (!(pcidevs = qemuGetPciHostDeviceList(def)))
2849 2850
        return -1;

2851 2852
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2853 2854 2855
        pciDeviceListSteal(pcidevs, dev);
        if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            pciFreeDevice(dev);
2856
            goto cleanup;
2857 2858 2859
        }
    }

2860 2861 2862
    ret = 0;

cleanup:
2863
    pciDeviceListFree(pcidevs);
2864 2865 2866
    return ret;
}

2867

2868
static int
2869 2870
qemuPrepareHostPCIDevices(struct qemud_driver *driver,
                          virDomainDefPtr def)
2871 2872 2873
{
    pciDeviceList *pcidevs;
    int i;
2874
    int ret = -1;
2875

2876
    if (!(pcidevs = qemuGetPciHostDeviceList(def)))
2877 2878
        return -1;

2879
    /* We have to use 3 loops here. *All* devices must
2880 2881
     * be detached before we reset any of them, because
     * in some cases you have to reset the whole PCI,
2882 2883
     * which impacts all devices on it. Also, all devices
     * must be reset before being marked as active.
2884 2885 2886 2887 2888 2889 2890
     */

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

2891 2892
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2893
        if (!pciDeviceIsAssignable(dev, !driver->relaxedACS))
2894 2895
            goto cleanup;

2896
        if (pciDeviceGetManaged(dev) &&
2897
            pciDettachDevice(dev, driver->activePciHostdevs) < 0)
2898 2899
            goto cleanup;
    }
2900 2901 2902

    /* Now that all the PCI hostdevs have be dettached, we can safely
     * reset them */
2903 2904
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2905
        if (pciResetDevice(dev, driver->activePciHostdevs) < 0)
2906 2907
            goto cleanup;
    }
2908

2909
    /* Now mark all the devices as active */
2910 2911
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
2912 2913 2914
        pciDeviceListSteal(pcidevs, dev);
        if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            pciFreeDevice(dev);
2915 2916
            goto cleanup;
        }
2917 2918
    }

2919
    ret = 0;
2920

2921
cleanup:
2922
    pciDeviceListFree(pcidevs);
2923
    return ret;
2924 2925
}

2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936

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;
2937
        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975
            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;
}


2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997
static int
qemuPrepareChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
                         virDomainChrDefPtr dev,
                         void *opaque ATTRIBUTE_UNUSED)
{
    int fd;
    if (dev->type != VIR_DOMAIN_CHR_TYPE_FILE)
        return 0;

    if ((fd = open(dev->data.file.path, O_CREAT | O_APPEND, S_IRUSR|S_IWUSR)) < 0) {
        virReportSystemError(errno,
                             _("Unable to pre-create chardev file '%s'"),
                             dev->data.file.path);
        return -1;
    }

    close(fd);

    return 0;
}


2998
static void
2999
qemudReattachManagedDevice(pciDevice *dev, struct qemud_driver *driver)
3000 3001 3002 3003 3004 3005 3006 3007 3008
{
    int retries = 100;

    if (pciDeviceGetManaged(dev)) {
        while (pciWaitForDeviceCleanup(dev, "kvm_assigned_device")
               && retries) {
            usleep(100*1000);
            retries--;
        }
3009
        if (pciReAttachDevice(dev, driver->activePciHostdevs) < 0) {
3010 3011
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to re-attach PCI device: %s"),
3012
                      err ? err->message : _("unknown error"));
3013 3014 3015 3016 3017
            virResetError(err);
        }
    }
}

3018
static void
3019
qemuDomainReAttachHostDevices(struct qemud_driver *driver,
3020
                              virDomainDefPtr def)
3021
{
3022
    pciDeviceList *pcidevs;
3023 3024
    int i;

3025 3026
    if (!def->nhostdevs)
        return;
3027

3028
    if (!(pcidevs = qemuGetPciHostDeviceList(def))) {
3029
        virErrorPtr err = virGetLastError();
3030
        VIR_ERROR(_("Failed to allocate pciDeviceList: %s"),
3031
                  err ? err->message : _("unknown error"));
3032 3033
        virResetError(err);
        return;
3034 3035
    }

3036 3037
    /* Again 3 loops; mark all devices as inactive before reset
     * them and reset all the devices before re-attach */
3038

3039 3040
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3041
        pciDeviceListDel(driver->activePciHostdevs, dev);
3042
    }
3043

3044 3045
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3046
        if (pciResetDevice(dev, driver->activePciHostdevs) < 0) {
3047
            virErrorPtr err = virGetLastError();
3048
            VIR_ERROR(_("Failed to reset PCI device: %s"),
3049
                      err ? err->message : _("unknown error"));
3050 3051
            virResetError(err);
        }
3052
    }
3053

3054 3055
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3056
        qemudReattachManagedDevice(dev, driver);
3057
    }
3058

3059
    pciDeviceListFree(pcidevs);
3060 3061
}

3062 3063 3064 3065 3066 3067 3068 3069 3070 3071
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

3072

3073 3074 3075 3076 3077 3078 3079
static int qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
                                  const char *path,
                                  size_t depth ATTRIBUTE_UNUSED,
                                  void *opaque)
{
    virCgroupPtr cgroup = opaque;
    int rc;
3080

3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094
    VIR_DEBUG("Process path %s for disk", path);
    /* XXX RO vs RW */
    rc = virCgroupAllowDevicePath(cgroup, path);
    if (rc != 0) {
        /* Get this for non-block devices */
        if (rc == -EINVAL) {
            VIR_DEBUG("Ignoring EINVAL for %s", path);
        } else if (rc == -EACCES) { /* Get this for root squash NFS */
            VIR_DEBUG("Ignoring EACCES for %s", path);
        } else {
            virReportSystemError(-rc,
                                 _("Unable to allow access for disk path %s"),
                                 path);
            return -1;
3095
        }
3096
    }
3097 3098
    return 0;
}
3099 3100


3101 3102
static int qemuSetupDiskCgroup(struct qemud_driver *driver,
                               virCgroupPtr cgroup,
3103 3104 3105
                               virDomainDiskDefPtr disk)
{
    return virDomainDiskDefForeachPath(disk,
3106
                                       driver->allowDiskFormatProbing,
3107 3108 3109
                                       true,
                                       qemuSetupDiskPathAllow,
                                       cgroup);
3110 3111 3112
}


3113 3114 3115 3116
static int qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
                                    const char *path,
                                    size_t depth ATTRIBUTE_UNUSED,
                                    void *opaque)
3117
{
3118 3119
    virCgroupPtr cgroup = opaque;
    int rc;
3120

3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134
    VIR_DEBUG("Process path %s for disk", path);
    /* XXX RO vs RW */
    rc = virCgroupDenyDevicePath(cgroup, path);
    if (rc != 0) {
        /* Get this for non-block devices */
        if (rc == -EINVAL) {
            VIR_DEBUG("Ignoring EINVAL for %s", path);
        } else if (rc == -EACCES) { /* Get this for root squash NFS */
            VIR_DEBUG("Ignoring EACCES for %s", path);
        } else {
            virReportSystemError(-rc,
                                 _("Unable to allow access for disk path %s"),
                                 path);
            return -1;
3135
        }
3136
    }
3137 3138
    return 0;
}
3139 3140


3141 3142
static int qemuTeardownDiskCgroup(struct qemud_driver *driver,
                                  virCgroupPtr cgroup,
3143 3144 3145
                                  virDomainDiskDefPtr disk)
{
    return virDomainDiskDefForeachPath(disk,
3146
                                       driver->allowDiskFormatProbing,
3147 3148 3149
                                       true,
                                       qemuTeardownDiskPathDeny,
                                       cgroup);
3150 3151 3152
}


3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176
static int qemuSetupChardevCgroup(virDomainDefPtr def,
                                  virDomainChrDefPtr dev,
                                  void *opaque)
{
    virCgroupPtr cgroup = opaque;
    int rc;

    if (dev->type != VIR_DOMAIN_CHR_TYPE_DEV)
        return 0;


    VIR_DEBUG("Process path '%s' for disk", dev->data.file.path);
    rc = virCgroupAllowDevicePath(cgroup, dev->data.file.path);
    if (rc != 0) {
        virReportSystemError(-rc,
                             _("Unable to allow device %s for %s"),
                             dev->data.file.path, def->name);
        return -1;
    }

    return 0;
}


3177
static int qemuSetupCgroup(struct qemud_driver *driver,
3178 3179 3180 3181
                           virDomainObjPtr vm)
{
    virCgroupPtr cgroup = NULL;
    int rc;
3182
    unsigned int i;
3183 3184 3185 3186
    const char *const *deviceACL =
        driver->cgroupDeviceACL ?
        (const char *const *)driver->cgroupDeviceACL :
        defaultDeviceACL;
3187 3188 3189 3190 3191 3192

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

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

3199 3200
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        rc = virCgroupDenyAllDevices(cgroup);
3201
        if (rc != 0) {
3202 3203 3204 3205 3206
            if (rc == -EPERM) {
                VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
                goto done;
            }

3207
            virReportSystemError(-rc,
3208
                                 _("Unable to deny all devices for %s"), vm->def->name);
3209 3210 3211
            goto cleanup;
        }

3212
        for (i = 0; i < vm->def->ndisks ; i++) {
3213
            if (qemuSetupDiskCgroup(driver, cgroup, vm->def->disks[i]) < 0)
3214 3215
                goto cleanup;
        }
3216

3217
        rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
3218
        if (rc != 0) {
3219
            virReportSystemError(-rc, "%s",
3220
                                 _("unable to allow /dev/pts/ devices"));
3221 3222 3223
            goto cleanup;
        }

3224 3225 3226
        if (vm->def->nsounds) {
            rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR);
            if (rc != 0) {
3227
                virReportSystemError(-rc, "%s",
3228 3229 3230 3231 3232 3233 3234 3235 3236 3237
                                     _("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) {
3238
                virReportSystemError(-rc,
3239 3240 3241 3242
                                     _("unable to allow device %s"),
                                     deviceACL[i]);
                goto cleanup;
            }
3243
        }
3244 3245 3246 3247 3248 3249

        if (virDomainChrDefForeach(vm->def,
                                   true,
                                   qemuSetupChardevCgroup,
                                   cgroup) < 0)
            goto cleanup;
3250 3251 3252
    }

done:
3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264
    virCgroupFree(&cgroup);
    return 0;

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


3265
static int qemuRemoveCgroup(struct qemud_driver *driver,
3266 3267
                            virDomainObjPtr vm,
                            int quiet)
3268 3269 3270 3271 3272 3273 3274 3275 3276
{
    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) {
3277
        if (!quiet)
3278 3279 3280
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Unable to find cgroup for %s\n"),
                            vm->def->name);
3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300
        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) {
3301
        virReportSystemError(-rc,
3302 3303 3304 3305 3306 3307 3308
                             _("unable to find cgroup for domain %s"),
                             def->name);
        goto cleanup;
    }

    rc = virCgroupAddTask(cgroup, getpid());
    if (rc != 0) {
3309
        virReportSystemError(-rc,
3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326
                             _("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;
3327 3328 3329
};

static int qemudSecurityHook(void *data) {
3330 3331
    struct qemudHookData *h = data;

3332 3333 3334
    /* This must take place before exec(), so that all QEMU
     * memory allocation is on the correct NUMA node
     */
3335
    if (qemuAddToCgroup(h->driver, h->vm->def) < 0)
3336 3337
        return -1;

3338 3339 3340
    /* This must be done after cgroup placement to avoid resetting CPU
     * affinity */
    if (qemudInitCpuAffinity(h->vm) < 0)
3341
        return -1;
3342

3343 3344
    if (h->driver->securityDriver &&
        h->driver->securityDriver->domainSetSecurityProcessLabel &&
3345
        h->driver->securityDriver->domainSetSecurityProcessLabel(h->driver->securityDriver, h->vm) < 0)
3346 3347 3348
        return -1;

    return 0;
3349 3350
}

3351
static int
3352
qemuPrepareMonitorChr(struct qemud_driver *driver,
3353
                      virDomainChrDefPtr monConfig,
3354 3355
                      const char *vm)
{
3356
    monConfig->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_MONITOR;
3357

3358 3359
    monConfig->type = VIR_DOMAIN_CHR_TYPE_UNIX;
    monConfig->data.nix.listen = 1;
3360

D
Daniel P. Berrange 已提交
3361
    if (!(monConfig->info.alias = strdup("monitor"))) {
3362
        virReportOOMError();
D
Daniel P. Berrange 已提交
3363 3364 3365
        return -1;
    }

3366
    if (virAsprintf(&monConfig->data.nix.path, "%s/%s.monitor",
3367
                    driver->libDir, vm) < 0) {
3368
        virReportOOMError();
3369 3370 3371 3372 3373 3374
        return -1;
    }

    return 0;
}

C
Chris Lalancette 已提交
3375 3376 3377 3378 3379
static int qemuDomainSnapshotSetActive(virDomainObjPtr vm,
                                       char *snapshotDir);
static int qemuDomainSnapshotSetInactive(virDomainObjPtr vm,
                                         char *snapshotDir);

3380 3381
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
3382
                              virDomainObjPtr vm,
3383
                              const char *migrateFrom,
3384
                              bool start_paused,
3385 3386
                              int stdin_fd,
                              const char *stdin_path) {
3387
    const char **argv = NULL, **tmp;
3388
    const char **progenv = NULL;
3389
    int i, ret, runflags;
3390
    struct stat sb;
3391 3392
    int *vmfds = NULL;
    int nvmfds = 0;
3393
    unsigned long long qemuCmdFlags;
3394
    fd_set keepfd;
3395
    const char *emulator;
G
Guido Günther 已提交
3396
    pid_t child;
3397
    int pos = -1;
3398
    char ebuf[1024];
3399
    char *pidfile = NULL;
3400
    int logfile = -1;
3401
    qemuDomainObjPrivatePtr priv = vm->privateData;
3402

3403
    struct qemudHookData hookData;
3404 3405 3406 3407
    hookData.conn = conn;
    hookData.vm = vm;
    hookData.driver = driver;

3408
    FD_ZERO(&keepfd);
3409

3410 3411
    DEBUG0("Beginning VM startup process");

D
Daniel P. Berrange 已提交
3412
    if (virDomainObjIsActive(vm)) {
3413 3414
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("VM is already active"));
3415 3416 3417
        return -1;
    }

3418 3419 3420 3421 3422
    /* Must be run before security labelling */
    DEBUG0("Preparing host devices");
    if (qemuPrepareHostDevices(driver, vm->def) < 0)
        goto cleanup;

3423 3424 3425 3426 3427 3428 3429
    DEBUG0("Preparing chr devices");
    if (virDomainChrDefForeach(vm->def,
                               true,
                               qemuPrepareChardevDevice,
                               NULL) < 0)
        goto cleanup;

3430 3431
    /* If you are using a SecurityDriver with dynamic labelling,
       then generate a security label for isolation */
3432
    DEBUG0("Generating domain security label (if required)");
3433
    if (driver->securityDriver &&
3434
        driver->securityDriver->domainGenSecurityLabel &&
3435 3436
        driver->securityDriver->domainGenSecurityLabel(driver->securityDriver,
                                                       vm) < 0)
3437
        goto cleanup;
3438

3439
    DEBUG0("Generating setting domain security labels (if required)");
3440 3441
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityAllLabel &&
3442 3443
        driver->securityDriver->domainSetSecurityAllLabel(driver->securityDriver,
                                                          vm, stdin_path) < 0) {
3444
        if (stdin_path && virStorageFileIsSharedFS(stdin_path) != 1)
3445 3446
            goto cleanup;
    }
3447

3448 3449 3450
    /* Ensure no historical cgroup for this VM is lying around bogus
     * settings */
    DEBUG0("Ensuring no historical cgroup is lying around");
3451
    qemuRemoveCgroup(driver, vm, 1);
3452

3453 3454 3455
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        vm->def->graphics[0]->data.vnc.autoport) {
3456
        DEBUG0("Determining VNC port");
3457
        int port = qemudNextFreeVNCPort(driver);
3458
        if (port < 0) {
3459 3460
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Unable to find an unused VNC port"));
3461
            goto cleanup;
3462
        }
3463
        vm->def->graphics[0]->data.vnc.port = port;
3464
    }
3465

L
Laine Stump 已提交
3466
    if (virFileMakePath(driver->logDir) != 0) {
3467
        virReportSystemError(errno,
3468 3469
                             _("cannot create log directory %s"),
                             driver->logDir);
3470
        goto cleanup;
3471 3472
    }

3473
    DEBUG0("Creating domain log file");
3474
    if ((logfile = qemudLogFD(driver, vm->def->name)) < 0)
3475
        goto cleanup;
3476

3477 3478
    emulator = vm->def->emulator;

3479 3480 3481 3482
    /* 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
     */
3483
    if (stat(emulator, &sb) < 0) {
3484
        virReportSystemError(errno,
3485 3486
                             _("Cannot find QEMU binary %s"),
                             emulator);
3487
        goto cleanup;
3488 3489
    }

3490
    DEBUG0("Determing emulator version");
3491
    if (qemudExtractVersionInfo(emulator,
3492
                                NULL,
3493
                                &qemuCmdFlags) < 0)
3494
        goto cleanup;
3495

3496
    DEBUG0("Setting up domain cgroup (if required)");
3497
    if (qemuSetupCgroup(driver, vm) < 0)
3498 3499
        goto cleanup;

3500
    if (VIR_ALLOC(priv->monConfig) < 0) {
3501
        virReportOOMError();
3502 3503 3504
        goto cleanup;
    }

3505
    DEBUG0("Preparing monitor state");
3506
    if (qemuPrepareMonitorChr(driver, priv->monConfig, vm->def->name) < 0)
3507
        goto cleanup;
3508

D
Daniel P. Berrange 已提交
3509 3510 3511
#if HAVE_YAJL
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON)
        priv->monJSON = 1;
3512
    else
D
Daniel P. Berrange 已提交
3513
#endif
3514
        priv->monJSON = 0;
D
Daniel P. Berrange 已提交
3515

D
Daniel P. Berrange 已提交
3516
    if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
3517
        virReportSystemError(ret,
D
Daniel P. Berrange 已提交
3518 3519 3520 3521 3522
                             _("Cannot remove stale PID file for %s"),
                             vm->def->name);
        goto cleanup;
    }

3523
    if (!(pidfile = virFilePid(driver->stateDir, vm->def->name))) {
3524
        virReportSystemError(errno,
3525 3526 3527
                             "%s", _("Failed to build pidfile path."));
        goto cleanup;
    }
D
Daniel P. Berrange 已提交
3528

3529
    /*
M
Matthew Booth 已提交
3530
     * Normally PCI addresses are assigned in the virDomainCreate
3531 3532 3533 3534 3535
     * 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
     */
3536
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
3537
        DEBUG0("Assigning domain PCI addresses");
3538
        /* Populate cache with current addresses */
3539 3540 3541 3542 3543 3544 3545
        if (priv->pciaddrs) {
            qemuDomainPCIAddressSetFree(priv->pciaddrs);
            priv->pciaddrs = NULL;
        }
        if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(vm->def)))
            goto cleanup;

3546 3547

        /* Assign any remaining addresses */
3548 3549
        if (qemuAssignDevicePCISlots(vm->def, priv->pciaddrs) < 0)
            goto cleanup;
3550 3551 3552 3553

        priv->persistentAddrs = 1;
    } else {
        priv->persistentAddrs = 0;
3554 3555
    }

3556
    DEBUG0("Building emulator command line");
3557
    vm->def->id = driver->nextvmid++;
3558
    if (qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
D
Daniel P. Berrange 已提交
3559
                              priv->monJSON, qemuCmdFlags, &argv, &progenv,
3560
                              &vmfds, &nvmfds, migrateFrom,
C
Chris Lalancette 已提交
3561 3562 3563 3564
                              vm->current_snapshot) < 0)
        goto cleanup;

    if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
3565
        goto cleanup;
3566

3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582
    /* 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;
    }

3583 3584
    tmp = progenv;
    while (*tmp) {
3585
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
3586
            VIR_WARN("Unable to write envv to logfile: %s",
3587
                     virStrerror(errno, ebuf, sizeof ebuf));
3588
        if (safewrite(logfile, " ", 1) < 0)
3589
            VIR_WARN("Unable to write envv to logfile: %s",
3590
                     virStrerror(errno, ebuf, sizeof ebuf));
3591 3592
        tmp++;
    }
3593 3594
    tmp = argv;
    while (*tmp) {
3595
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
3596
            VIR_WARN("Unable to write argv to logfile: %s",
3597
                     virStrerror(errno, ebuf, sizeof ebuf));
3598
        if (safewrite(logfile, " ", 1) < 0)
3599
            VIR_WARN("Unable to write argv to logfile: %s",
3600
                     virStrerror(errno, ebuf, sizeof ebuf));
3601 3602
        tmp++;
    }
3603
    if (safewrite(logfile, "\n", 1) < 0)
3604
        VIR_WARN("Unable to write argv to logfile: %s",
3605
                 virStrerror(errno, ebuf, sizeof ebuf));
3606

3607
    if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
3608
        VIR_WARN("Unable to seek to end of logfile: %s",
3609
                 virStrerror(errno, ebuf, sizeof ebuf));
3610

3611 3612
    for (i = 0 ; i < nvmfds ; i++)
        FD_SET(vmfds[i], &keepfd);
3613

3614 3615 3616 3617 3618 3619 3620
    VIR_DEBUG("Clear emulator capabilities: %d",
              driver->clearEmulatorCapabilities);
    runflags = VIR_EXEC_NONBLOCK;
    if (driver->clearEmulatorCapabilities) {
        runflags |= VIR_EXEC_CLEAR_CAPS;
    }

3621
    ret = virExecDaemonize(argv, progenv, &keepfd, &child,
3622
                           stdin_fd, &logfile, &logfile,
3623
                           runflags,
3624 3625 3626
                           qemudSecurityHook, &hookData,
                           pidfile);
    VIR_FREE(pidfile);
G
Guido Günther 已提交
3627 3628 3629

    /* wait for qemu process to to show up */
    if (ret == 0) {
3630
        if (virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) {
3631 3632
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Domain %s didn't show up\n"), vm->def->name);
3633
            ret = -1;
G
Guido Günther 已提交
3634
        }
3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645
    } 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;
    }
3646

3647 3648 3649
    if (migrateFrom)
        start_paused = true;
    vm->state = start_paused ? VIR_DOMAIN_PAUSED : VIR_DOMAIN_RUNNING;
3650

3651
    for (i = 0 ; argv[i] ; i++)
3652 3653
        VIR_FREE(argv[i]);
    VIR_FREE(argv);
3654

3655 3656 3657 3658
    for (i = 0 ; progenv[i] ; i++)
        VIR_FREE(progenv[i]);
    VIR_FREE(progenv);

3659
    if (ret == -1) /* The VM failed to start; tear filters before taps */
3660
        virDomainConfVMNWFilterTeardown(vm);
3661

3662 3663 3664
    if (vmfds) {
        for (i = 0 ; i < nvmfds ; i++) {
            close(vmfds[i]);
3665
        }
3666
        VIR_FREE(vmfds);
3667 3668
    }

3669
    if (ret == -1) /* The VM failed to start */
3670 3671
        goto cleanup;

3672
    DEBUG0("Waiting for monitor to show up");
3673
    if (qemudWaitForMonitor(driver, vm, pos) < 0)
3674
        goto cleanup;
3675

3676
    DEBUG0("Detecting VCPU PIDs");
3677
    if (qemuDetectVcpuPIDs(driver, vm) < 0)
3678
        goto cleanup;
3679

3680
    DEBUG0("Setting any required VM passwords");
3681
    if (qemuInitPasswords(conn, driver, vm, qemuCmdFlags) < 0)
3682
        goto cleanup;
3683

D
Daniel P. Berrange 已提交
3684 3685 3686
    /* 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)) {
3687
        DEBUG0("Determining domain device PCI addresses");
D
Daniel P. Berrange 已提交
3688
        if (qemuInitPCIAddresses(driver, vm) < 0)
3689
            goto cleanup;
D
Daniel P. Berrange 已提交
3690
    }
3691

3692
    DEBUG0("Setting initial memory amount");
3693
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
3694
    if (qemuMonitorSetBalloon(priv->mon, vm->def->memory) < 0) {
3695
        qemuDomainObjExitMonitorWithDriver(driver, vm);
3696
        goto cleanup;
3697
    }
3698

3699
    if (!start_paused) {
3700
        DEBUG0("Starting domain CPUs");
3701 3702 3703
        /* Allow the CPUS to start executing */
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
            if (virGetLastError() == NULL)
3704 3705
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("resume operation failed"));
3706
            qemuDomainObjExitMonitorWithDriver(driver, vm);
3707
            goto cleanup;
3708 3709
        }
    }
3710
    qemuDomainObjExitMonitorWithDriver(driver, vm);
3711

3712

3713
    DEBUG0("Writing domain status to disk");
3714
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
3715
        goto cleanup;
3716

3717 3718 3719
    if (logfile != -1)
        close(logfile);

3720
    return 0;
3721 3722

cleanup:
3723 3724 3725
    /* We jump here if we failed to start the VM for any reason, or
     * if we failed to initialize the now running VM. kill it off and
     * pretend we never started it */
3726
    qemudShutdownVMDaemon(driver, vm, 0);
3727 3728 3729 3730 3731

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

    return -1;
3732 3733 3734
}


3735
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
3736 3737
                                  virDomainObjPtr vm,
                                  int migrated) {
D
Daniel P. Berrange 已提交
3738
    int ret;
3739
    int retries = 0;
3740
    qemuDomainObjPrivatePtr priv = vm->privateData;
3741
    virErrorPtr orig_err;
3742 3743
    virDomainDefPtr def;
    int i;
D
Daniel P. Berrange 已提交
3744

3745 3746
    VIR_DEBUG("Shutting down VM '%s' pid=%d migrated=%d",
              vm->def->name, vm->pid, migrated);
3747

3748 3749 3750 3751
    /* This method is routinely used in clean up paths. Disable error
     * reporting so we don't squash a legit error. */
    orig_err = virSaveLastError();

3752
    virDomainConfVMNWFilterTeardown(vm);
S
Stefan Berger 已提交
3753

3754
    if (driver->macFilter) {
3755
        def = vm->def;
3756 3757 3758 3759
        for (i = 0 ; i < def->nnets ; i++) {
            virDomainNetDefPtr net = def->nets[i];
            if (net->ifname == NULL)
                continue;
3760
            if ((errno = networkDisallowMacOnPort(driver, net->ifname,
3761
                                                  net->mac))) {
3762
                virReportSystemError(errno,
3763 3764 3765 3766 3767 3768
             _("failed to remove ebtables rule to allow MAC address on  '%s'"),
                                     net->ifname);
            }
        }
    }

3769
    /* This will safely handle a non-running guest with pid=0 or pid=-1*/
G
Guido Günther 已提交
3770 3771
    if (virKillProcess(vm->pid, 0) == 0 &&
        virKillProcess(vm->pid, SIGTERM) < 0)
3772
        virReportSystemError(errno,
3773 3774
                             _("Failed to send SIGTERM to %s (%d)"),
                             vm->def->name, vm->pid);
3775

3776 3777
    if (priv->mon)
        qemuMonitorClose(priv->mon);
3778

3779 3780 3781 3782 3783
    if (priv->monConfig) {
        if (priv->monConfig->type == VIR_DOMAIN_CHR_TYPE_UNIX)
            unlink(priv->monConfig->data.nix.path);
        virDomainChrDefFree(priv->monConfig);
        priv->monConfig = NULL;
3784 3785
    }

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

3789 3790 3791 3792 3793 3794 3795 3796 3797 3798
    /* 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);
    }

3799
    /* Reset Security Labels */
3800
    if (driver->securityDriver &&
3801
        driver->securityDriver->domainRestoreSecurityAllLabel)
3802 3803
        driver->securityDriver->domainRestoreSecurityAllLabel(driver->securityDriver,
                                                              vm, migrated);
3804 3805
    if (driver->securityDriver &&
        driver->securityDriver->domainReleaseSecurityLabel)
3806 3807
        driver->securityDriver->domainReleaseSecurityLabel(driver->securityDriver,
                                                           vm);
3808

3809 3810 3811 3812 3813 3814 3815
    /* 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 已提交
3816
    virDomainDefClearDeviceAliases(vm->def);
3817 3818 3819 3820 3821
    if (!priv->persistentAddrs) {
        virDomainDefClearPCIAddresses(vm->def);
        qemuDomainPCIAddressSetFree(priv->pciaddrs);
        priv->pciaddrs = NULL;
    }
3822

3823
    qemuDomainReAttachHostDevices(driver, vm->def);
3824

S
Stefan Berger 已提交
3825 3826 3827 3828
#if WITH_MACVTAP
    def = vm->def;
    for (i = 0; i < def->nnets; i++) {
        virDomainNetDefPtr net = def->nets[i];
3829
        if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
3830
            delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
3831
                       &net->data.direct.virtPortProfile);
3832 3833
            VIR_FREE(net->ifname);
        }
S
Stefan Berger 已提交
3834 3835 3836
    }
#endif

3837
retry:
3838
    if ((ret = qemuRemoveCgroup(driver, vm, 0)) < 0) {
3839 3840 3841 3842 3843 3844 3845 3846
        if (ret == -EBUSY && (retries++ < 5)) {
            usleep(200*1000);
            goto retry;
        }
        VIR_WARN("Failed to remove cgroup for %s",
                 vm->def->name);
    }

3847
    qemudRemoveDomainStatus(driver, vm);
D
Daniel P. Berrange 已提交
3848

3849 3850 3851 3852 3853 3854
    /* Remove VNC port from port reservation bitmap, but only if it was
       reserved by the driver (autoport=yes)
    */
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
        vm->def->graphics[0]->data.vnc.autoport &&
3855
        vm->def->graphics[0]->data.vnc.port >= QEMU_VNC_PORT_MIN) {
3856 3857 3858 3859 3860 3861 3862 3863
        if (virBitmapClearBit(driver->reservedVNCPorts,
                              vm->def->graphics[0]->data.vnc.port - \
                              QEMU_VNC_PORT_MIN) < 0) {
            VIR_DEBUG("virBitmapClearBit failed on bit %d",
                      vm->def->graphics[0]->data.vnc.port - QEMU_VNC_PORT_MIN);
       }
    }

3864
    vm->pid = -1;
3865
    vm->def->id = -1;
3866
    vm->state = VIR_DOMAIN_SHUTOFF;
3867 3868
    VIR_FREE(priv->vcpupids);
    priv->nvcpupids = 0;
3869 3870

    if (vm->newDef) {
3871
        virDomainDefFree(vm->def);
3872
        vm->def = vm->newDef;
3873
        vm->def->id = -1;
3874 3875
        vm->newDef = NULL;
    }
3876 3877 3878 3879 3880

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
3881 3882 3883
}


3884
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
3885
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
3886
                                  int flags ATTRIBUTE_UNUSED) {
3887
    if (conn->uri == NULL) {
3888 3889 3890
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

3891
        conn->uri = xmlParseURI(qemu_driver->privileged ?
3892 3893
                                "qemu:///system" :
                                "qemu:///session");
3894
        if (!conn->uri) {
3895
            virReportOOMError();
3896 3897
            return VIR_DRV_OPEN_ERROR;
        }
3898 3899 3900 3901 3902 3903 3904 3905 3906 3907
    } 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;

3908
        if (qemu_driver == NULL) {
3909 3910
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("qemu state driver is not active"));
3911 3912 3913
            return VIR_DRV_OPEN_ERROR;
        }

3914
        if (conn->uri->path == NULL) {
3915 3916 3917 3918 3919
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no QEMU URI path given, try %s"),
                            qemu_driver->privileged
                            ? "qemu:///system"
                            : "qemu:///session");
3920 3921 3922
                return VIR_DRV_OPEN_ERROR;
        }

3923
        if (qemu_driver->privileged) {
3924 3925
            if (STRNEQ (conn->uri->path, "/system") &&
                STRNEQ (conn->uri->path, "/session")) {
3926 3927 3928
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///system"),
                                conn->uri->path);
3929 3930 3931 3932
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
3933 3934 3935
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///session"),
                                conn->uri->path);
3936 3937 3938
                return VIR_DRV_OPEN_ERROR;
            }
        }
3939 3940 3941 3942 3943 3944 3945
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
3946
    struct qemud_driver *driver = conn->privateData;
3947 3948

    /* Get rid of callbacks registered for this conn */
3949
    qemuDriverLock(driver);
3950
    virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
3951
    qemuDriverUnlock(driver);
3952 3953 3954 3955 3956 3957

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
3958 3959 3960 3961 3962
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
3963 3964 3965 3966 3967
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
3968 3969 3970
    }
}

3971
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
3972
    return "QEMU";
3973 3974
}

3975

3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988
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;
}


3989 3990 3991 3992
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
3993

3994 3995
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
3996
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
3997
        return -1;
3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008
    }

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

    close(fd);
    return maxvcpus;
}


4009
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
4010 4011 4012
    if (!type)
        return 16;

4013
    if (STRCASEEQ(type, "qemu"))
4014 4015
        return 16;

4016
    if (STRCASEEQ(type, "kvm"))
4017
        return kvmGetMaxVCPUs();
4018

4019
    if (STRCASEEQ(type, "kqemu"))
4020
        return 1;
4021

4022 4023
    qemuReportError(VIR_ERR_INVALID_ARG,
                    _("unknown type '%s'"), type);
4024 4025 4026
    return -1;
}

4027

4028
static char *qemudGetCapabilities(virConnectPtr conn) {
4029
    struct qemud_driver *driver = conn->privateData;
4030
    virCapsPtr caps = NULL;
4031
    char *xml = NULL;
4032

4033
    qemuDriverLock(driver);
4034

4035
    if ((caps = qemuCreateCapabilities(qemu_driver->caps,
4036
                                       qemu_driver)) == NULL) {
4037 4038 4039
        virCapabilitiesFree(caps);
        goto cleanup;
    }
4040

4041
    virCapabilitiesFree(qemu_driver->caps);
4042 4043 4044
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
4045
        virReportOOMError();
4046 4047

cleanup:
4048
    qemuDriverUnlock(driver);
4049

4050
    return xml;
4051 4052 4053
}


4054
static int qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid, int tid) {
D
Daniel P. Berrange 已提交
4055 4056
    char proc[PATH_MAX];
    FILE *pidinfo;
4057
    unsigned long long usertime, systime;
4058 4059
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
4060

4061 4062 4063 4064 4065 4066
    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 已提交
4067 4068 4069 4070
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
4071
        /*printf("cannot read pid info");*/
D
Daniel P. Berrange 已提交
4072
        /* VM probably shut down, so fake 0 */
4073 4074 4075 4076
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
D
Daniel P. Berrange 已提交
4077 4078 4079
        return 0;
    }

4080 4081 4082 4083 4084 4085 4086 4087 4088 4089
    /* 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) {
4090
        fclose(pidinfo);
4091 4092
        VIR_WARN0("cannot parse process status data");
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
4093 4094 4095 4096 4097 4098 4099 4100
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
4101 4102 4103 4104 4105
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

D
Daniel P. Berrange 已提交
4106

4107 4108
    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
              pid, tid, usertime, systime, cpu);
D
Daniel P. Berrange 已提交
4109 4110 4111 4112 4113 4114 4115

    fclose(pidinfo);

    return 0;
}


4116
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
4117
                                          int id) {
4118 4119 4120 4121
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

4122
    qemuDriverLock(driver);
4123
    vm  = virDomainFindByID(&driver->domains, id);
4124
    qemuDriverUnlock(driver);
4125 4126

    if (!vm) {
4127 4128
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching id %d"), id);
4129
        goto cleanup;
4130 4131
    }

4132
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4133
    if (dom) dom->id = vm->def->id;
4134 4135

cleanup:
4136 4137
    if (vm)
        virDomainObjUnlock(vm);
4138 4139
    return dom;
}
4140

4141
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
4142
                                            const unsigned char *uuid) {
4143 4144 4145
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
4146

4147
    qemuDriverLock(driver);
4148
    vm = virDomainFindByUUID(&driver->domains, uuid);
4149 4150
    qemuDriverUnlock(driver);

4151
    if (!vm) {
4152 4153
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
4154 4155
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4156
        goto cleanup;
4157 4158
    }

4159
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4160
    if (dom) dom->id = vm->def->id;
4161 4162

cleanup:
4163 4164
    if (vm)
        virDomainObjUnlock(vm);
4165 4166
    return dom;
}
4167

4168
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
4169
                                            const char *name) {
4170 4171 4172
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
4173

4174
    qemuDriverLock(driver);
4175
    vm = virDomainFindByName(&driver->domains, name);
4176 4177
    qemuDriverUnlock(driver);

4178
    if (!vm) {
4179 4180
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), name);
4181
        goto cleanup;
4182 4183
    }

4184
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4185
    if (dom) dom->id = vm->def->id;
4186 4187

cleanup:
4188 4189
    if (vm)
        virDomainObjUnlock(vm);
4190 4191 4192
    return dom;
}

4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203

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) {
4204
        qemuReportError(VIR_ERR_NO_DOMAIN, NULL);
4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224
        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) {
4225
        qemuReportError(VIR_ERR_NO_DOMAIN, NULL);
4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236
        goto cleanup;
    }
    ret = obj->persistent;

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


4237
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
4238 4239 4240
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

4241
    qemuDriverLock(driver);
4242
    if (qemudExtractVersion(driver) < 0)
4243
        goto cleanup;
4244

4245
    *version = qemu_driver->qemuVersion;
4246 4247 4248
    ret = 0;

cleanup:
4249
    qemuDriverUnlock(driver);
4250
    return ret;
D
Daniel P. Berrange 已提交
4251 4252
}

4253
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
4254
    struct qemud_driver *driver = conn->privateData;
4255
    int n;
4256

4257
    qemuDriverLock(driver);
4258
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
4259
    qemuDriverUnlock(driver);
4260

4261
    return n;
D
Daniel P. Berrange 已提交
4262
}
4263

4264
static int qemudNumDomains(virConnectPtr conn) {
4265
    struct qemud_driver *driver = conn->privateData;
4266
    int n;
4267

4268
    qemuDriverLock(driver);
4269
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
4270
    qemuDriverUnlock(driver);
4271

4272
    return n;
D
Daniel P. Berrange 已提交
4273
}
4274

4275
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
4276
                                      unsigned int flags) {
4277
    struct qemud_driver *driver = conn->privateData;
4278
    virDomainDefPtr def;
4279
    virDomainObjPtr vm = NULL;
4280
    virDomainPtr dom = NULL;
4281
    virDomainEventPtr event = NULL;
D
Daniel P. Berrange 已提交
4282

4283
    virCheckFlags(VIR_DOMAIN_START_PAUSED, NULL);
4284

4285
    qemuDriverLock(driver);
4286
    if (!(def = virDomainDefParseString(driver->caps, xml,
4287
                                        VIR_DOMAIN_XML_INACTIVE)))
4288
        goto cleanup;
4289

4290
    if (virSecurityDriverVerify(def) < 0)
4291 4292
        goto cleanup;

4293 4294
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
4295

4296 4297 4298 4299 4300 4301
    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

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

4302
    if (!(vm = virDomainAssignDef(driver->caps,
4303
                                  &driver->domains,
4304
                                  def, false)))
4305 4306 4307
        goto cleanup;

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

4309 4310 4311
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup; /* XXXX free the 'vm' we created ? */

4312 4313 4314
    if (qemudStartVMDaemon(conn, driver, vm, NULL,
                           (flags & VIR_DOMAIN_START_PAUSED) != 0,
                           -1, NULL) < 0) {
4315 4316 4317
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
4318
        vm = NULL;
4319
        goto cleanup;
D
Daniel P. Berrange 已提交
4320
    }
4321 4322 4323 4324

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

4326
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4327
    if (dom) dom->id = vm->def->id;
4328

4329 4330 4331
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4332

4333 4334
cleanup:
    virDomainDefFree(def);
4335 4336
    if (vm)
        virDomainObjUnlock(vm);
4337 4338
    if (event)
        qemuDomainEventQueue(driver, event);
4339
    qemuDriverUnlock(driver);
4340
    return dom;
D
Daniel P. Berrange 已提交
4341 4342 4343
}


4344
static int qemudDomainSuspend(virDomainPtr dom) {
4345 4346 4347
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4348
    virDomainEventPtr event = NULL;
4349
    qemuDomainObjPrivatePtr priv;
4350

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

D
Daniel P. Berrange 已提交
4354
    if (!vm) {
4355 4356
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4357 4358
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4359
        goto cleanup;
D
Daniel P. Berrange 已提交
4360
    }
D
Daniel P. Berrange 已提交
4361
    if (!virDomainObjIsActive(vm)) {
4362 4363
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4364
        goto cleanup;
D
Daniel P. Berrange 已提交
4365
    }
4366 4367 4368

    priv = vm->privateData;

4369
    if (priv->jobActive == QEMU_JOB_MIGRATION_OUT) {
4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383
        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"));
4384
            goto endjob;
4385
        }
4386 4387
        if (vm->state != VIR_DOMAIN_PAUSED) {
            int rc;
4388
            int state = vm->state;
4389

4390
            vm->state = VIR_DOMAIN_PAUSED;
4391 4392 4393
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorStopCPUs(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4394 4395
            if (rc < 0) {
                vm->state = state;
4396
                goto endjob;
4397
            }
4398 4399 4400 4401 4402 4403 4404
            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 已提交
4405
    }
4406

4407
endjob:
4408 4409
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4410

4411
cleanup:
4412 4413
    if (vm)
        virDomainObjUnlock(vm);
4414

4415
    if (event)
4416
        qemuDomainEventQueue(driver, event);
4417
    qemuDriverUnlock(driver);
4418
    return ret;
D
Daniel P. Berrange 已提交
4419 4420 4421
}


4422
static int qemudDomainResume(virDomainPtr dom) {
4423 4424 4425
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4426
    virDomainEventPtr event = NULL;
4427

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

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

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

D
Daniel P. Berrange 已提交
4442
    if (!virDomainObjIsActive(vm)) {
4443 4444
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4445
        goto endjob;
D
Daniel P. Berrange 已提交
4446
    }
4447
    if (vm->state == VIR_DOMAIN_PAUSED) {
4448
        qemuDomainObjPrivatePtr priv = vm->privateData;
4449
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
4450
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
4451
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4452
            if (virGetLastError() == NULL)
4453 4454
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resume operation failed"));
4455
            goto endjob;
4456
        }
4457
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4458
        vm->state = VIR_DOMAIN_RUNNING;
4459 4460 4461
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
4462
    }
4463
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
4464
        goto endjob;
4465 4466
    ret = 0;

4467
endjob:
4468 4469
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4470

4471
cleanup:
4472 4473
    if (vm)
        virDomainObjUnlock(vm);
4474
    if (event)
4475
        qemuDomainEventQueue(driver, event);
4476
    qemuDriverUnlock(driver);
4477
    return ret;
D
Daniel P. Berrange 已提交
4478 4479 4480
}


4481
static int qemudDomainShutdown(virDomainPtr dom) {
4482 4483 4484
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4485

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

4490
    if (!vm) {
4491 4492
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4493 4494
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4495
        goto cleanup;
4496 4497
    }

4498 4499 4500
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
4501
    if (!virDomainObjIsActive(vm)) {
4502 4503
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4504
        goto endjob;
4505 4506
    }

4507
    qemuDomainObjPrivatePtr priv = vm->privateData;
4508 4509 4510
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorSystemPowerdown(priv->mon);
    qemuDomainObjExitMonitor(vm);
4511

4512
endjob:
4513 4514
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4515

4516
cleanup:
4517 4518
    if (vm)
        virDomainObjUnlock(vm);
4519
    return ret;
4520 4521 4522
}


4523
static int qemudDomainDestroy(virDomainPtr dom) {
4524 4525 4526
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4527
    virDomainEventPtr event = NULL;
4528

4529
    qemuDriverLock(driver);
4530
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
4531
    if (!vm) {
4532 4533
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4534 4535
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4536
        goto cleanup;
D
Daniel P. Berrange 已提交
4537
    }
4538 4539 4540 4541

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

D
Daniel P. Berrange 已提交
4542
    if (!virDomainObjIsActive(vm)) {
4543 4544
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4545
        goto endjob;
4546
    }
4547

4548
    qemudShutdownVMDaemon(driver, vm, 0);
4549 4550 4551
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
4552
    if (!vm->persistent) {
4553 4554 4555
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
4556 4557
        vm = NULL;
    }
4558 4559
    ret = 0;

4560
endjob:
4561 4562 4563
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4564

4565
cleanup:
4566 4567
    if (vm)
        virDomainObjUnlock(vm);
4568 4569
    if (event)
        qemuDomainEventQueue(driver, event);
4570
    qemuDriverUnlock(driver);
4571
    return ret;
D
Daniel P. Berrange 已提交
4572 4573 4574
}


4575
static char *qemudDomainGetOSType(virDomainPtr dom) {
4576 4577 4578
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
4579

4580
    qemuDriverLock(driver);
4581
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4582
    qemuDriverUnlock(driver);
4583
    if (!vm) {
4584 4585
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4586 4587
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4588
        goto cleanup;
4589 4590
    }

4591
    if (!(type = strdup(vm->def->os.type)))
4592
        virReportOOMError();
4593 4594

cleanup:
4595 4596
    if (vm)
        virDomainObjUnlock(vm);
4597 4598 4599
    return type;
}

4600 4601
/* Returns max memory in kb, 0 if error */
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
4602 4603 4604
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
4605

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

4610
    if (!vm) {
4611 4612
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4613 4614
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4615
        goto cleanup;
4616 4617
    }

4618 4619 4620
    ret = vm->def->maxmem;

cleanup:
4621 4622
    if (vm)
        virDomainObjUnlock(vm);
4623
    return ret;
4624 4625 4626
}

static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
4627
    struct qemud_driver *driver = dom->conn->privateData;
4628
    qemuDomainObjPrivatePtr priv;
4629
    virDomainObjPtr vm;
4630
    int ret = -1, r;
4631

4632
    qemuDriverLock(driver);
4633
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4634
    qemuDriverUnlock(driver);
4635
    if (!vm) {
4636 4637
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4638 4639
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4640
        goto cleanup;
4641 4642
    }

4643 4644 4645 4646 4647 4648
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto cleanup;
    }

4649
    if (newmem > vm->def->maxmem) {
4650 4651
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("cannot set memory higher than max memory"));
4652
        goto cleanup;
4653 4654
    }

4655 4656 4657
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

4658 4659 4660 4661 4662 4663
    priv = vm->privateData;
    qemuDomainObjEnterMonitor(vm);
    r = qemuMonitorSetBalloon(priv->mon, newmem);
    qemuDomainObjExitMonitor(vm);
    if (r < 0)
        goto endjob;
4664

4665 4666 4667 4668 4669
    /* 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;
4670
    }
4671

4672
    ret = 0;
4673
endjob:
4674 4675
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4676

4677
cleanup:
4678 4679
    if (vm)
        virDomainObjUnlock(vm);
4680
    return ret;
4681 4682
}

4683
static int qemudDomainGetInfo(virDomainPtr dom,
4684
                              virDomainInfoPtr info) {
4685 4686 4687
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4688 4689
    int err;
    unsigned long balloon;
4690

4691
    qemuDriverLock(driver);
4692
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4693
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
4694
    if (!vm) {
4695 4696
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4697 4698
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4699
        goto cleanup;
D
Daniel P. Berrange 已提交
4700 4701
    }

4702
    info->state = vm->state;
D
Daniel P. Berrange 已提交
4703

D
Daniel P. Berrange 已提交
4704
    if (!virDomainObjIsActive(vm)) {
4705
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
4706
    } else {
4707
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
4708
            qemuReportError(VIR_ERR_OPERATION_FAILED, ("cannot read cputime for domain"));
4709
            goto cleanup;
D
Daniel P. Berrange 已提交
4710 4711 4712
        }
    }

4713
    info->maxMem = vm->def->maxmem;
4714

D
Daniel P. Berrange 已提交
4715
    if (virDomainObjIsActive(vm)) {
4716
        qemuDomainObjPrivatePtr priv = vm->privateData;
4717 4718 4719
        if (!priv->jobActive) {
            if (qemuDomainObjBeginJob(vm) < 0)
                goto cleanup;
4720

4721 4722 4723 4724
            qemuDomainObjEnterMonitor(vm);
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
            qemuDomainObjExitMonitor(vm);
            if (err < 0) {
4725 4726
                if (qemuDomainObjEndJob(vm) == 0)
                    vm = NULL;
4727 4728 4729 4730 4731 4732 4733 4734 4735
                goto cleanup;
            }

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

4736 4737 4738 4739
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
                goto cleanup;
            }
4740 4741 4742
        } else {
            info->memory = vm->def->memory;
        }
4743 4744 4745 4746
    } else {
        info->memory = vm->def->memory;
    }

4747
    info->nrVirtCpu = vm->def->vcpus;
4748 4749 4750
    ret = 0;

cleanup:
4751 4752
    if (vm)
        virDomainObjUnlock(vm);
4753
    return ret;
D
Daniel P. Berrange 已提交
4754 4755 4756
}


4757 4758 4759 4760 4761 4762 4763 4764
/** qemuDomainMigrateOffline:
 * Pause domain for non-live migration.
 */
static int
qemuDomainMigrateOffline(struct qemud_driver *driver,
                         virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4765
    int state = vm->state;
4766 4767
    int ret;

4768
    vm->state = VIR_DOMAIN_PAUSED;
4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780
    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);
4781 4782
    } else
        vm->state = state;
4783 4784 4785 4786 4787

    return ret;
}


4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801
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 */
4802
        struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
4803 4804 4805
        struct timeval now;
        int rc;

4806 4807 4808 4809 4810 4811
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit during migration"));
            goto cleanup;
        }

4812 4813
        if (priv->jobSignals & QEMU_JOB_SIGNAL_CANCEL) {
            priv->jobSignals ^= QEMU_JOB_SIGNAL_CANCEL;
4814 4815 4816 4817 4818 4819 4820
            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");
            }
4821 4822 4823 4824 4825
        } 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");
4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836
        } 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");
4837 4838
        }

4839 4840 4841 4842 4843 4844 4845 4846 4847
        /* Repeat check because the job signals might have caused
         * guest to die
         */
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit during migration"));
            goto cleanup;
        }

4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919
        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;
}


4920
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
4921 4922 4923
#define QEMUD_SAVE_VERSION 2

enum qemud_save_formats {
4924 4925 4926
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
4927 4928
    /*
     * Deprecated by xz and never used as part of a release
4929
     * QEMUD_SAVE_FORMAT_LZMA
4930 4931
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
4932
    QEMUD_SAVE_FORMAT_LZOP = 4,
4933 4934 4935
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
4936 4937

    QEMUD_SAVE_FORMAT_LAST
4938
};
4939

4940 4941 4942 4943 4944
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
4945 4946
              "xz",
              "lzop")
4947

4948 4949 4950 4951 4952
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
    int version;
    int xml_len;
    int was_running;
4953 4954
    int compressed;
    int unused[15];
4955 4956
};

4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970
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,
4971 4972
                        _("failed to write header to domain save file '%s'"),
                        hdata->path);
4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986
        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;
}


4987 4988
static int qemudDomainSaveFlag(virDomainPtr dom, const char *path,
                               int compressed)
4989
{
4990
    struct qemud_driver *driver = dom->conn->privateData;
4991
    virDomainObjPtr vm = NULL;
4992
    char *xml = NULL;
4993
    struct qemud_save_header header;
4994 4995
    struct fileOpHookData hdata;
    int bypassSecurityDriver = 0;
4996
    int ret = -1;
4997
    int rc;
4998
    virDomainEventPtr event = NULL;
4999
    qemuDomainObjPrivatePtr priv;
5000 5001
    struct stat sb;
    int is_reg = 0;
5002
    unsigned long long offset;
5003
    virCgroupPtr cgroup = NULL;
5004 5005 5006 5007 5008

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

5009
    qemuDriverLock(driver);
5010 5011

    header.compressed = compressed;
5012

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

D
Daniel P. Berrange 已提交
5015
    if (!vm) {
5016 5017
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5018 5019
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5020
        goto cleanup;
D
Daniel P. Berrange 已提交
5021
    }
5022
    priv = vm->privateData;
5023

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

D
Daniel P. Berrange 已提交
5027
    if (!virDomainObjIsActive(vm)) {
5028 5029
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
5030
        goto endjob;
D
Daniel P. Berrange 已提交
5031
    }
5032

5033 5034 5035
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

5036 5037 5038
    /* Pause */
    if (vm->state == VIR_DOMAIN_RUNNING) {
        header.was_running = 1;
5039
        vm->state = VIR_DOMAIN_PAUSED;
5040
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5041
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
5042
            qemuDomainObjExitMonitorWithDriver(driver, vm);
5043
            vm->state = VIR_DOMAIN_RUNNING;
5044
            goto endjob;
5045
        }
5046
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5047 5048 5049 5050 5051 5052

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto endjob;
        }
5053 5054 5055
    }

    /* Get XML for the domain */
5056
    xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
5057
    if (!xml) {
5058 5059
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
5060
        goto endjob;
5061 5062 5063
    }
    header.xml_len = strlen(xml) + 1;

5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076
    /* 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);
    }

5077 5078 5079 5080 5081
    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
5082 5083
     * it by padding the XML string with NULLs.
     */
5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096
    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;
    }
5097

5098 5099 5100 5101 5102 5103
    /* Setup hook data needed by virFileOperation hook function */
    hdata.dom = dom;
    hdata.path = path;
    hdata.xml = xml;
    hdata.header = &header;

5104 5105
    /* Write header to file, followed by XML */

5106
    /* First try creating the file as root */
5107 5108 5109 5110
    if (!is_reg) {
        int fd = open(path, O_WRONLY | O_TRUNC);
        if (fd < 0) {
            virReportSystemError(errno, _("unable to open %s"), path);
5111 5112
            goto endjob;
        }
5113
        if (qemudDomainSaveFileOpHook(fd, &hdata) != 0) {
5114 5115 5116 5117 5118
            close(fd);
            goto endjob;
        }
        if (close(fd) < 0) {
            virReportSystemError(errno, _("unable to close %s"), path);
5119 5120
            goto endjob;
        }
5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139
    } 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;
            }
5140

5141
            /* On Linux we can also verify the FS-type of the directory. */
5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164
            switch (virStorageFileIsSharedFS(path)) {
                case 1:
                   /* it was on a network share, so we'll continue
                    * as outlined above
                    */
                   break;

                case -1:
                   virReportSystemError(errno,
                                        _("Failed to create domain save file "
                                          "'%s': couldn't determine fs type"),
                                        path);
                   goto endjob;
                   break;

                case 0:
                default:
                   /* local file - log the error returned by virFileOperation */
                   virReportSystemError(rc,
                                        _("Failed to create domain save file '%s'"),
                                        path);
                   goto endjob;
                   break;
5165 5166 5167

            }

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

5170 5171 5172 5173 5174 5175
            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'"),
5176
                                 path);
5177 5178
                goto endjob;
            }
5179

5180 5181 5182
            /* 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 */
5183

5184 5185
            bypassSecurityDriver = 1;
        }
5186
    }
5187

5188

5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205
    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;
        }
    }

5206 5207
    if ((!bypassSecurityDriver) &&
        driver->securityDriver &&
5208
        driver->securityDriver->domainSetSavedStateLabel &&
5209 5210
        driver->securityDriver->domainSetSavedStateLabel(driver->securityDriver,
                                                         vm, path) == -1)
5211 5212
        goto endjob;

5213 5214
    if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = { "cat", NULL };
M
Matthias Bolte 已提交
5215
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5216 5217 5218
        rc = qemuMonitorMigrateToFile(priv->mon,
                                      QEMU_MONITOR_MIGRATE_BACKGROUND,
                                      args, path, offset);
M
Matthias Bolte 已提交
5219
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5220
    } else {
5221
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
5222 5223 5224 5225 5226
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
M
Matthias Bolte 已提交
5227
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5228 5229 5230
        rc = qemuMonitorMigrateToFile(priv->mon,
                                      QEMU_MONITOR_MIGRATE_BACKGROUND,
                                      args, path, offset);
M
Matthias Bolte 已提交
5231
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5232 5233
    }

5234 5235 5236 5237 5238
    if (rc < 0)
        goto endjob;

    rc = qemuDomainWaitForMigrationComplete(driver, vm);

5239
    if (rc < 0)
5240
        goto endjob;
5241

5242 5243
    if ((!bypassSecurityDriver) &&
        driver->securityDriver &&
5244
        driver->securityDriver->domainRestoreSavedStateLabel &&
5245 5246
        driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver,
                                                             vm, path) == -1)
5247
        VIR_WARN("failed to restore save state label on %s", path);
5248

5249 5250
    if (cgroup != NULL) {
        rc = virCgroupDenyDevicePath(cgroup, path);
5251 5252 5253
        if (rc != 0)
            VIR_WARN("Unable to deny device %s for %s %d",
                     path, vm->def->name, rc);
5254 5255
    }

5256 5257
    ret = 0;

5258
    /* Shut it down */
5259
    qemudShutdownVMDaemon(driver, vm, 0);
5260 5261 5262
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
5263
    if (!vm->persistent) {
5264 5265 5266
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
5267 5268
        vm = NULL;
    }
5269

5270
endjob:
5271
    if (vm) {
5272
        if (ret != 0) {
5273
            if (header.was_running && virDomainObjIsActive(vm)) {
5274 5275 5276 5277 5278 5279 5280 5281
                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;
            }
5282

5283 5284 5285 5286 5287
            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);
5288
            }
5289 5290 5291 5292

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

5298
        if (qemuDomainObjEndJob(vm) == 0)
5299
            vm = NULL;
5300
    }
5301

5302 5303
cleanup:
    VIR_FREE(xml);
5304
    if (ret != 0 && is_reg)
5305
        unlink(path);
5306 5307
    if (vm)
        virDomainObjUnlock(vm);
5308 5309
    if (event)
        qemuDomainEventQueue(driver, event);
5310
    virCgroupFree(&cgroup);
5311
    qemuDriverUnlock(driver);
5312
    return ret;
D
Daniel P. Berrange 已提交
5313 5314
}

5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356
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;

5357
    virCheckFlags(0, -1);
5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417

    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;

5418
    virCheckFlags(0, -1);
5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451

    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;

5452
    virCheckFlags(0, -1);
5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476

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

P
Paolo Bonzini 已提交
5478 5479 5480 5481 5482 5483
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;
5484
    int ret = -1, fd = -1;
5485
    virDomainEventPtr event = NULL;
5486 5487 5488 5489
    const char *args[] = {
        "cat",
        NULL,
    };
5490
    qemuDomainObjPrivatePtr priv;
P
Paolo Bonzini 已提交
5491 5492 5493 5494 5495 5496 5497

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

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5498 5499
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
5500 5501
        goto cleanup;
    }
5502
    priv = vm->privateData;
P
Paolo Bonzini 已提交
5503

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

D
Daniel P. Berrange 已提交
5507
    if (!virDomainObjIsActive(vm)) {
5508 5509
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
5510
        goto endjob;
P
Paolo Bonzini 已提交
5511 5512
    }

5513 5514
    /* Create an empty file with appropriate ownership.  */
    if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
5515 5516
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("failed to create '%s'"), path);
5517 5518 5519 5520
        goto endjob;
    }

    if (close(fd) < 0) {
5521
        virReportSystemError(errno,
5522 5523 5524 5525 5526 5527 5528
                             _("unable to save file %s"),
                             path);
        goto endjob;
    }

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSavedStateLabel &&
5529 5530
        driver->securityDriver->domainSetSavedStateLabel(driver->securityDriver,
                                                         vm, path) == -1)
5531 5532
        goto endjob;

P
Paolo Bonzini 已提交
5533 5534
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
P
Paolo Bonzini 已提交
5535 5536 5537
    resume = (vm->state == VIR_DOMAIN_RUNNING);

    /* Pause domain for non-live dump */
P
Paolo Bonzini 已提交
5538
    if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
5539
        vm->state = VIR_DOMAIN_PAUSED;
5540
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5541
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
5542
            qemuDomainObjExitMonitorWithDriver(driver, vm);
5543
            vm->state = VIR_DOMAIN_RUNNING;
5544
            goto endjob;
5545
        }
5546
        qemuDomainObjExitMonitorWithDriver(driver, vm);
P
Paolo Bonzini 已提交
5547
        paused = 1;
5548 5549 5550 5551 5552 5553

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto endjob;
        }
P
Paolo Bonzini 已提交
5554 5555
    }

5556
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
5557 5558 5559
    ret = qemuMonitorMigrateToFile(priv->mon,
                                   QEMU_MONITOR_MIGRATE_BACKGROUND,
                                   args, path, 0);
5560
    qemuDomainObjExitMonitorWithDriver(driver, vm);
5561 5562 5563 5564 5565 5566 5567 5568 5569
    if (ret < 0)
        goto endjob;

    ret = qemuDomainWaitForMigrationComplete(driver, vm);

    if (ret < 0)
        goto endjob;

    paused = 1;
5570 5571 5572

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSavedStateLabel &&
5573 5574
        driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver,
                                                             vm, path) == -1)
5575 5576 5577
        goto endjob;

endjob:
5578
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
5579
        qemudShutdownVMDaemon(driver, vm, 0);
5580 5581 5582 5583 5584
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
5585 5586 5587
    /* 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.  */
5588
    else if (resume && paused && virDomainObjIsActive(vm)) {
5589
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5590
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
5591
            if (virGetLastError() == NULL)
5592 5593
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
5594
        }
5595
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5596
        vm->state = VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
5597
    }
5598

5599 5600
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5601
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
5602 5603 5604 5605
        virDomainRemoveInactive(&driver->domains,
                                vm);
        vm = NULL;
    }
5606 5607

cleanup:
5608 5609
    if (ret != 0)
        unlink(path);
P
Paolo Bonzini 已提交
5610 5611
    if (vm)
        virDomainObjUnlock(vm);
5612 5613
    if (event)
        qemuDomainEventQueue(driver, event);
5614
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
5615 5616 5617 5618
    return ret;
}


5619 5620 5621 5622 5623 5624
static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int i, rc;
    int ret = -1;

5625 5626
    qemuDomainObjEnterMonitor(vm);

5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656
    /* 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 */
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
            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 */
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

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

    ret = 0;

cleanup:
5657
    qemuDomainObjExitMonitor(vm);
5658 5659 5660 5661 5662 5663 5664 5665 5666 5667
    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) {
5668 5669
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5670 5671
    const char * type;
    int max;
5672
    int ret = -1;
5673

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

5678
    if (!vm) {
5679 5680
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5681 5682
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5683
        goto cleanup;
5684 5685
    }

5686 5687 5688
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

5689 5690 5691
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
5692
        goto endjob;
5693 5694
    }

5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719
    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;
5720

5721
cleanup:
5722 5723
    if (vm)
        virDomainObjUnlock(vm);
5724
    return ret;
5725 5726
}

5727 5728 5729 5730 5731 5732

static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
5733 5734
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5735
    int maxcpu, hostcpus;
5736
    virNodeInfo nodeinfo;
5737
    int ret = -1;
5738
    qemuDomainObjPrivatePtr priv;
5739

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

5744 5745 5746
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5747 5748
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5749 5750 5751
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
5752
    if (!virDomainObjIsActive(vm)) {
5753 5754
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",_("cannot pin vcpus on an inactive domain"));
5755
        goto cleanup;
5756 5757
    }

5758 5759 5760
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
5761 5762 5763
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("vcpu number out of range %d > %d"),
                        vcpu, priv->nvcpupids);
5764
        goto cleanup;
5765 5766
    }

5767
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
5768
        goto cleanup;
5769

5770
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
5771
    maxcpu = maplen * 8;
5772 5773
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
5774

5775 5776
    if (priv->vcpupids != NULL) {
        if (virProcessInfoSetAffinity(priv->vcpupids[vcpu],
5777
                                      cpumap, maplen, maxcpu) < 0)
5778
            goto cleanup;
5779
    } else {
5780 5781
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cpu affinity is not supported"));
5782
        goto cleanup;
5783
    }
5784
    ret = 0;
5785

5786
cleanup:
5787 5788
    if (vm)
        virDomainObjUnlock(vm);
5789
    return ret;
5790 5791 5792 5793 5794 5795 5796 5797
}

static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
5798 5799
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5800
    virNodeInfo nodeinfo;
5801
    int i, v, maxcpu, hostcpus;
5802
    int ret = -1;
5803
    qemuDomainObjPrivatePtr priv;
5804

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

5809 5810 5811
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5812 5813
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5814 5815 5816
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
5817
    if (!virDomainObjIsActive(vm)) {
5818 5819 5820
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",
                        _("cannot list vcpu pinning for an inactive domain"));
5821
        goto cleanup;
5822 5823
    }

5824 5825
    priv = vm->privateData;

5826
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
5827
        goto cleanup;
5828

5829
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
5830
    maxcpu = maplen * 8;
5831 5832
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
5833 5834

    /* Clamp to actual number of vcpus */
5835 5836
    if (maxinfo > priv->nvcpupids)
        maxinfo = priv->nvcpupids;
5837

5838 5839 5840 5841 5842 5843
    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;
5844

5845
                if (priv->vcpupids != NULL &&
5846 5847 5848
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
                                        vm->pid,
5849
                                        priv->vcpupids[i]) < 0) {
5850
                    virReportSystemError(errno, "%s",
5851 5852 5853
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
5854
            }
5855 5856
        }

5857 5858
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
5859
            if (priv->vcpupids != NULL) {
5860 5861 5862
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);

5863
                    if (virProcessInfoGetAffinity(priv->vcpupids[v],
5864
                                                  cpumap, maplen, maxcpu) < 0)
5865
                        goto cleanup;
5866
                }
5867
            } else {
5868 5869
                qemuReportError(VIR_ERR_NO_SUPPORT,
                                "%s", _("cpu affinity is not available"));
5870
                goto cleanup;
5871 5872 5873
            }
        }
    }
5874
    ret = maxinfo;
5875

5876
cleanup:
5877 5878
    if (vm)
        virDomainObjUnlock(vm);
5879
    return ret;
5880 5881 5882
}


5883
static int qemudDomainGetMaxVcpus(virDomainPtr dom) {
5884 5885
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5886
    const char *type;
5887
    int ret = -1;
5888

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

5893
    if (!vm) {
5894 5895
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5896 5897
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5898
        goto cleanup;
5899 5900
    }

5901
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
5902 5903 5904
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
5905
        goto cleanup;
5906 5907
    }

5908
    ret = qemudGetMaxVCPUs(NULL, type);
5909

5910
cleanup:
5911 5912
    if (vm)
        virDomainObjUnlock(vm);
5913 5914 5915
    return ret;
}

5916 5917 5918 5919 5920 5921 5922 5923 5924
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);

5925 5926
    memset(seclabel, 0, sizeof(*seclabel));

5927 5928 5929
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5930 5931
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5932 5933 5934
        goto cleanup;
    }

5935
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
5936 5937 5938
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955
        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 已提交
5956
    if (virDomainObjIsActive(vm)) {
5957 5958 5959 5960 5961 5962 5963
        if (driver->securityDriver &&
            driver->securityDriver->domainGetSecurityProcessLabel &&
            driver->securityDriver->domainGetSecurityProcessLabel(driver->securityDriver,
                                                                  vm, seclabel) < 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Failed to get security label"));
            goto cleanup;
5964 5965 5966 5967 5968 5969 5970 5971
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
5972
    qemuDriverUnlock(driver);
5973 5974 5975
    return ret;
}

5976 5977
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
5978 5979 5980
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
5981
    int ret = 0;
5982

5983
    qemuDriverLock(driver);
5984
    if (!driver->securityPrimaryDriver) {
5985
        memset(secmodel, 0, sizeof (*secmodel));
5986 5987
        goto cleanup;
    }
5988

5989 5990
    p = driver->caps->host.secModel.model;
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
5991 5992 5993
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security model string exceeds max %d bytes"),
                        VIR_SECURITY_MODEL_BUFLEN-1);
5994 5995
        ret = -1;
        goto cleanup;
5996 5997 5998 5999 6000
    }
    strcpy(secmodel->model, p);

    p = driver->caps->host.secModel.doi;
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
6001 6002 6003
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security DOI string exceeds max %d bytes"),
                        VIR_SECURITY_DOI_BUFLEN-1);
6004 6005
        ret = -1;
        goto cleanup;
6006 6007
    }
    strcpy(secmodel->doi, p);
6008 6009 6010 6011

cleanup:
    qemuDriverUnlock(driver);
    return ret;
6012 6013
}

6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145
/* 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);
}

J
Jiri Denemark 已提交
6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173
static int qemudDomainSaveImageClose(int fd, pid_t read_pid, int *status)
{
    int ret = 0;

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

    if (read_pid != -1) {
        /* reap the process that read the file */
        while ((ret = waitpid(read_pid, status, 0)) == -1
               && errno == EINTR) {
            /* empty */
        }
    } else if (status) {
        *status = 0;
    }

    return ret;
}

static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5)
qemudDomainSaveImageOpen(struct qemud_driver *driver,
                                    const char *path,
                                    virDomainDefPtr *ret_def,
                                    struct qemud_save_header *ret_header,
                                    pid_t *ret_read_pid)
{
    int fd;
6174
    pid_t read_pid = -1;
6175
    struct qemud_save_header header;
J
Jiri Denemark 已提交
6176 6177
    char *xml = NULL;
    virDomainDefPtr def = NULL;
6178 6179

    if ((fd = open(path, O_RDONLY)) < 0) {
6180 6181 6182
        if ((driver->user == 0) || (getuid() != 0)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("cannot read domain image"));
J
Jiri Denemark 已提交
6183
            goto error;
6184 6185 6186 6187 6188 6189 6190 6191
        }

        /* 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 */
J
Jiri Denemark 已提交
6192
            goto error;
6193
        }
6194 6195 6196
    }

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
6197 6198
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
6199
        goto error;
6200 6201 6202
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
6203 6204
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("image magic is incorrect"));
J
Jiri Denemark 已提交
6205
        goto error;
6206 6207 6208
    }

    if (header.version > QEMUD_SAVE_VERSION) {
6209 6210 6211
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("image version is not supported (%d > %d)"),
                        header.version, QEMUD_SAVE_VERSION);
J
Jiri Denemark 已提交
6212
        goto error;
6213 6214
    }

6215 6216 6217
    if (header.xml_len <= 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
6218
        goto error;
6219 6220
    }

6221 6222
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
J
Jiri Denemark 已提交
6223
        goto error;
6224 6225 6226
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
6227 6228
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
6229
        goto error;
6230 6231 6232
    }

    /* Create a domain from this XML */
6233
    if (!(def = virDomainDefParseString(driver->caps, xml,
6234
                                        VIR_DOMAIN_XML_INACTIVE))) {
6235 6236
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
J
Jiri Denemark 已提交
6237
        goto error;
6238 6239
    }

J
Jiri Denemark 已提交
6240
    VIR_FREE(xml);
6241

J
Jiri Denemark 已提交
6242 6243 6244
    *ret_def = def;
    *ret_header = header;
    *ret_read_pid = read_pid;
6245

J
Jiri Denemark 已提交
6246
    return fd;
6247

J
Jiri Denemark 已提交
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
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
    qemudDomainSaveImageClose(fd, read_pid, NULL);

    return -1;
}

static int ATTRIBUTE_NONNULL(6)
qemudDomainSaveImageStartVM(virConnectPtr conn,
                            struct qemud_driver *driver,
                            virDomainObjPtr vm,
                            int fd,
                            pid_t read_pid,
                            const struct qemud_save_header *header,
                            const char *path)
{
    int ret = -1;
    virDomainEventPtr event;
    int intermediatefd = -1;
    pid_t intermediate_pid = -1;
    int childstat;
    int wait_ret;
    int status;

    if (header->version == 2) {
6274
        const char *intermediate_argv[3] = { NULL, "-dc", NULL };
J
Jiri Denemark 已提交
6275
        const char *prog = qemudSaveCompressionTypeToString(header->compressed);
6276
        if (prog == NULL) {
6277 6278
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("Invalid compressed save format %d"),
J
Jiri Denemark 已提交
6279 6280
                            header->compressed);
            goto out;
6281
        }
6282

J
Jiri Denemark 已提交
6283
        if (header->compressed != QEMUD_SAVE_FORMAT_RAW) {
6284
            intermediate_argv[0] = prog;
6285 6286
            intermediatefd = fd;
            fd = -1;
6287
            if (virExec(intermediate_argv, NULL, NULL,
6288
                        &intermediate_pid, intermediatefd, &fd, NULL, 0) < 0) {
6289 6290 6291
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Failed to start decompression binary %s"),
                                intermediate_argv[0]);
J
Jiri Denemark 已提交
6292
                goto out;
6293 6294 6295
            }
        }
    }
J
Jiri Denemark 已提交
6296

6297
    /* Set the migration source and start it up. */
6298
    ret = qemudStartVMDaemon(conn, driver, vm, "stdio", true, fd, path);
J
Jiri Denemark 已提交
6299

6300 6301 6302
    if (intermediate_pid != -1) {
        /* Wait for intermediate process to exit */
        while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
J
Jiri Denemark 已提交
6303 6304 6305
               errno == EINTR) {
            /* empty */
        }
6306 6307 6308
    }
    if (intermediatefd != -1)
        close(intermediatefd);
J
Jiri Denemark 已提交
6309 6310

    wait_ret = qemudDomainSaveImageClose(fd, read_pid, &status);
6311
    fd = -1;
6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333
    if (read_pid != -1) {
        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;
            }
        }
    }
J
Jiri Denemark 已提交
6334 6335 6336

    if (ret < 0)
        goto out;
6337

6338 6339 6340
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
J
Jiri Denemark 已提交
6341 6342 6343
    if (event)
        qemuDomainEventQueue(driver, event);

6344

6345
    /* If it was running before, resume it now. */
J
Jiri Denemark 已提交
6346
    if (header->was_running) {
6347
        qemuDomainObjPrivatePtr priv = vm->privateData;
6348
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
6349
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
6350
            if (virGetLastError() == NULL)
6351 6352
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("failed to resume domain"));
6353
            qemuDomainObjExitMonitorWithDriver(driver,vm);
J
Jiri Denemark 已提交
6354
            goto out;
6355
        }
6356
        qemuDomainObjExitMonitorWithDriver(driver, vm);
6357
        vm->state = VIR_DOMAIN_RUNNING;
6358 6359
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
J
Jiri Denemark 已提交
6360
            goto out;
6361
        }
6362
    }
J
Jiri Denemark 已提交
6363

6364
    ret = 0;
6365

J
Jiri Denemark 已提交
6366
out:
6367 6368
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSavedStateLabel &&
6369 6370
        driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver,
                                                             vm, path) == -1)
6371 6372
        VIR_WARN("failed to restore save state label on %s", path);

J
Jiri Denemark 已提交
6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397
    return ret;
}

static int qemudDomainRestore(virConnectPtr conn,
                              const char *path) {
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    pid_t read_pid = -1;
    int ret = -1;
    struct qemud_save_header header;

    qemuDriverLock(driver);

    fd = qemudDomainSaveImageOpen(driver, path, &def, &header, &read_pid);
    if (fd < 0)
        goto cleanup;

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

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, true))) {
6398
        /* virDomainAssignDef already set the error */
J
Jiri Denemark 已提交
6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409
        goto cleanup;
    }
    def = NULL;

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

    ret = qemudDomainSaveImageStartVM(conn, driver, vm, fd,
                                      read_pid, &header, path);

    if (qemuDomainObjEndJob(vm) == 0)
6410
        vm = NULL;
J
Jiri Denemark 已提交
6411 6412 6413 6414
    else if (ret < 0 && !vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
6415

6416 6417
cleanup:
    virDomainDefFree(def);
J
Jiri Denemark 已提交
6418
    qemudDomainSaveImageClose(fd, read_pid, NULL);
6419 6420 6421
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
6422
    return ret;
D
Daniel P. Berrange 已提交
6423 6424
}

J
Jiri Denemark 已提交
6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465
static int qemudDomainObjRestore(virConnectPtr conn,
                                 struct qemud_driver *driver,
                                 virDomainObjPtr vm,
                                 const char *path)
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    pid_t read_pid = -1;
    int ret = -1;
    struct qemud_save_header header;

    fd = qemudDomainSaveImageOpen(driver, path, &def, &header, &read_pid);
    if (fd < 0)
        goto cleanup;

    if (STRNEQ(vm->def->name, def->name) ||
        memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) {
        char vm_uuidstr[VIR_UUID_STRING_BUFLEN];
        char def_uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(vm->def->uuid, vm_uuidstr);
        virUUIDFormat(def->uuid, def_uuidstr);
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("cannot restore domain '%s' uuid %s from a file"
                          " which belongs to domain '%s' uuid %s"),
                        vm->def->name, vm_uuidstr,
                        def->name, def_uuidstr);
        goto cleanup;
    }

    virDomainObjAssignDef(vm, def, true);
    def = NULL;

    ret = qemudDomainSaveImageStartVM(conn, driver, vm, fd,
                                      read_pid, &header, path);

cleanup:
    virDomainDefFree(def);
    qemudDomainSaveImageClose(fd, read_pid, NULL);
    return ret;
}

D
Daniel P. Berrange 已提交
6466

6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504
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;
}


6505
static char *qemudDomainDumpXML(virDomainPtr dom,
6506
                                int flags) {
6507 6508 6509
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
6510 6511
    unsigned long balloon;
    int err;
6512

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

D
Daniel P. Berrange 已提交
6516
    if (!vm) {
6517 6518
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6519 6520
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6521
        goto cleanup;
D
Daniel P. Berrange 已提交
6522 6523
    }

6524
    /* Refresh current memory based on balloon info */
D
Daniel P. Berrange 已提交
6525
    if (virDomainObjIsActive(vm)) {
6526
        qemuDomainObjPrivatePtr priv = vm->privateData;
6527 6528 6529
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
        if (!priv->jobActive) {
6530
            if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
6531 6532
                goto cleanup;

6533
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
6534
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
6535
            qemuDomainObjExitMonitorWithDriver(driver, vm);
6536 6537 6538 6539
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
                goto cleanup;
            }
6540 6541 6542 6543 6544 6545
            if (err < 0)
                goto cleanup;
            if (err > 0)
                vm->def->memory = balloon;
            /* err == 0 indicates no balloon support, so ignore it */
        }
6546
    }
6547

6548
    ret = qemudVMDumpXML(driver, vm, flags);
6549 6550

cleanup:
6551 6552
    if (vm)
        virDomainObjUnlock(vm);
6553
    qemuDriverUnlock(driver);
6554
    return ret;
D
Daniel P. Berrange 已提交
6555 6556 6557
}


6558 6559 6560 6561
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
                                     unsigned int flags ATTRIBUTE_UNUSED) {
6562
    struct qemud_driver *driver = conn->privateData;
6563 6564 6565 6566
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
6567 6568
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
6569 6570 6571
        goto cleanup;
    }

6572
    qemuDriverLock(driver);
6573
    def = qemuParseCommandLineString(driver->caps, config);
6574
    qemuDriverUnlock(driver);
6575 6576 6577
    if (!def)
        goto cleanup;

6578
    xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
6579 6580 6581 6582 6583 6584

cleanup:
    virDomainDefFree(def);
    return xml;
}

6585 6586 6587 6588 6589 6590
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;
6591
    virDomainChrDef monConfig;
6592
    const char *emulator;
6593
    unsigned long long qemuCmdFlags;
6594 6595 6596 6597 6598 6599 6600 6601
    struct stat sb;
    const char **retargv = NULL;
    const char **retenv = NULL;
    const char **tmp;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *ret = NULL;
    int i;

6602 6603
    qemuDriverLock(driver);

6604
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
6605 6606
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
6607 6608 6609
        goto cleanup;
    }

6610
    def = virDomainDefParseString(driver->caps, xmlData, 0);
6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654
    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) {
6655
        virReportSystemError(errno,
6656 6657 6658 6659 6660 6661 6662 6663
                             _("Cannot find QEMU binary %s"),
                             emulator);
        goto cleanup;
    }

    if (qemudExtractVersionInfo(emulator,
                                NULL,
                                &qemuCmdFlags) < 0) {
6664 6665 6666
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot determine QEMU argv syntax %s"),
                        emulator);
6667 6668 6669
        goto cleanup;
    }

6670
    if (qemuPrepareMonitorChr(driver, &monConfig, def->name) < 0)
6671
        goto cleanup;
6672 6673

    if (qemudBuildCommandLine(conn, driver, def,
D
Daniel P. Berrange 已提交
6674
                              &monConfig, 0, qemuCmdFlags,
6675 6676
                              &retargv, &retenv,
                              NULL, NULL, /* Don't want it to create TAP devices */
C
Chris Lalancette 已提交
6677
                              NULL, NULL) < 0) {
6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693
        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++;
    }

6694 6695
    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
6696
        virReportOOMError();
6697
        goto cleanup;
6698
    }
6699 6700 6701 6702

    ret = virBufferContentAndReset(&buf);

cleanup:
6703
    qemuDriverUnlock(driver);
6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716
    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;
}


6717
static int qemudListDefinedDomains(virConnectPtr conn,
6718
                            char **const names, int nnames) {
6719
    struct qemud_driver *driver = conn->privateData;
6720
    int n;
6721

6722
    qemuDriverLock(driver);
6723
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
6724
    qemuDriverUnlock(driver);
6725
    return n;
D
Daniel P. Berrange 已提交
6726 6727
}

6728
static int qemudNumDefinedDomains(virConnectPtr conn) {
6729
    struct qemud_driver *driver = conn->privateData;
6730
    int n;
6731

6732
    qemuDriverLock(driver);
6733
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
6734
    qemuDriverUnlock(driver);
6735

6736
    return n;
D
Daniel P. Berrange 已提交
6737 6738 6739
}


J
Jiri Denemark 已提交
6740 6741
static int qemudDomainObjStart(virConnectPtr conn,
                               struct qemud_driver *driver,
6742 6743
                               virDomainObjPtr vm,
                               bool start_paused)
J
Jiri Denemark 已提交
6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763
{
    int ret = -1;
    char *managed_save;

    /*
     * 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))) {
        ret = qemudDomainObjRestore(conn, driver, vm, managed_save);

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

        if (ret == 0)
            goto cleanup;
    }

6764
    ret = qemudStartVMDaemon(conn, driver, vm, NULL, start_paused, -1, NULL);
J
Jiri Denemark 已提交
6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778
    if (ret != -1) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

6779 6780 6781
static int
qemudDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
{
6782 6783 6784
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
6785

6786
    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);
6787

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

6791
    if (!vm) {
6792 6793
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6794 6795
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6796
        goto cleanup;
6797 6798
    }

6799 6800 6801 6802
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
6803 6804
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is already running"));
6805 6806 6807
        goto endjob;
    }

6808 6809
    ret = qemudDomainObjStart(dom->conn, driver, vm,
                              (flags & VIR_DOMAIN_START_PAUSED) != 0);
6810

6811
endjob:
6812 6813
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
6814

6815
cleanup:
6816 6817
    if (vm)
        virDomainObjUnlock(vm);
6818
    qemuDriverUnlock(driver);
6819
    return ret;
D
Daniel P. Berrange 已提交
6820 6821
}

6822 6823 6824 6825 6826 6827
static int
qemudDomainStart(virDomainPtr dom)
{
    return qemudDomainStartWithFlags(dom, 0);
}

6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842
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;

6843
        if (STRNEQ(def->os.machine, machine->name))
6844 6845 6846
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
6847
            virReportOOMError();
6848 6849 6850 6851 6852 6853 6854 6855 6856
            return -1;
        }

        break;
    }

    return 0;
}

6857 6858 6859 6860 6861 6862 6863
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
    int i, nmachines = 0;

    if (qemudProbeMachineTypes(def->emulator, &machines, &nmachines) < 0) {
6864
        virReportOOMError();
6865 6866 6867 6868 6869 6870 6871
        return -1;
    }

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

6872
        if (STRNEQ(def->os.machine, machines[i]->name))
6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

6885 6886
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
6887 6888 6889 6890 6891 6892
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
6893
        virCapsGuestDomainInfoPtr info;
6894 6895 6896
        int j;

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

6899 6900 6901 6902 6903 6904 6905 6906 6907
            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;
6908 6909
        }

6910 6911 6912 6913
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
6914 6915 6916 6917
                return -1;
            goto out;
        }
    }
6918 6919 6920 6921

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

6922 6923 6924 6925 6926 6927 6928
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
6929

6930
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
6931
    struct qemud_driver *driver = conn->privateData;
6932
    virDomainDefPtr def;
6933
    virDomainObjPtr vm = NULL;
6934
    virDomainPtr dom = NULL;
6935
    virDomainEventPtr event = NULL;
6936
    int dupVM;
6937

6938
    qemuDriverLock(driver);
6939
    if (!(def = virDomainDefParseString(driver->caps, xml,
6940
                                        VIR_DOMAIN_XML_INACTIVE)))
6941
        goto cleanup;
6942

6943
    if (virSecurityDriverVerify(def) < 0)
6944 6945
        goto cleanup;

6946 6947
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
6948

6949
    if (qemudCanonicalizeMachine(driver, def) < 0)
6950 6951
        goto cleanup;

6952 6953 6954
    if (qemuAssignPCIAddresses(def) < 0)
        goto cleanup;

6955
    if (!(vm = virDomainAssignDef(driver->caps,
6956
                                  &driver->domains,
6957
                                  def, false))) {
6958
        goto cleanup;
6959
    }
6960
    def = NULL;
6961
    vm->persistent = 1;
6962

6963
    if (virDomainSaveConfig(driver->configDir,
6964
                            vm->newDef ? vm->newDef : vm->def) < 0) {
6965 6966
        virDomainRemoveInactive(&driver->domains,
                                vm);
6967
        vm = NULL;
6968
        goto cleanup;
6969 6970
    }

6971 6972
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
6973
                                     !dupVM ?
6974 6975
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
6976

6977
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
6978
    if (dom) dom->id = vm->def->id;
6979 6980

cleanup:
6981
    virDomainDefFree(def);
6982 6983
    if (vm)
        virDomainObjUnlock(vm);
6984 6985
    if (event)
        qemuDomainEventQueue(driver, event);
6986
    qemuDriverUnlock(driver);
6987
    return dom;
D
Daniel P. Berrange 已提交
6988 6989
}

6990
static int qemudDomainUndefine(virDomainPtr dom) {
6991 6992
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6993
    virDomainEventPtr event = NULL;
6994
    int ret = -1;
D
Daniel P. Berrange 已提交
6995

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

D
Daniel P. Berrange 已提交
6999
    if (!vm) {
7000 7001
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7002 7003
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7004
        goto cleanup;
D
Daniel P. Berrange 已提交
7005 7006
    }

D
Daniel P. Berrange 已提交
7007
    if (virDomainObjIsActive(vm)) {
7008 7009
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot delete active domain"));
7010
        goto cleanup;
D
Daniel P. Berrange 已提交
7011 7012
    }

7013
    if (!vm->persistent) {
7014 7015
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot undefine transient domain"));
7016
        goto cleanup;
7017 7018
    }

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

7022 7023 7024
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
7025

7026 7027
    virDomainRemoveInactive(&driver->domains,
                            vm);
7028
    vm = NULL;
7029
    ret = 0;
D
Daniel P. Berrange 已提交
7030

7031
cleanup:
7032 7033
    if (vm)
        virDomainObjUnlock(vm);
7034 7035
    if (event)
        qemuDomainEventQueue(driver, event);
7036
    qemuDriverUnlock(driver);
7037
    return ret;
D
Daniel P. Berrange 已提交
7038 7039
}

7040

7041
static int qemudDomainChangeEjectableMedia(struct qemud_driver *driver,
7042
                                           virDomainObjPtr vm,
7043 7044
                                           virDomainDiskDefPtr disk,
                                           unsigned long long qemuCmdFlags)
7045
{
7046
    virDomainDiskDefPtr origdisk = NULL;
7047
    int i;
7048
    int ret;
7049
    char *driveAlias = NULL;
7050

7051
    origdisk = NULL;
7052
    for (i = 0 ; i < vm->def->ndisks ; i++) {
7053 7054
        if (vm->def->disks[i]->bus == disk->bus &&
            STREQ(vm->def->disks[i]->dst, disk->dst)) {
7055
            origdisk = vm->def->disks[i];
7056
            break;
7057
        }
7058 7059 7060
    }

    if (!origdisk) {
7061 7062 7063 7064
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No device with bus '%s' and target '%s'"),
                        virDomainDiskBusTypeToString(disk->bus),
                        disk->dst);
7065 7066 7067
        return -1;
    }

7068
    if (!origdisk->info.alias) {
7069 7070
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), origdisk->dst);
7071 7072
        return -1;
    }
7073

7074 7075
    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
7076 7077 7078
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Removable media not supported for %s device"),
                        virDomainDiskDeviceTypeToString(disk->device));
7079
        return -1;
7080
    }
7081

7082 7083
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
7084 7085
        driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver,
                                                            vm, disk) < 0)
7086 7087
        return -1;

7088 7089 7090
    if (!(driveAlias = qemuDeviceDriveHostAlias(origdisk, qemuCmdFlags)))
        goto error;

7091
    qemuDomainObjPrivatePtr priv = vm->privateData;
7092
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7093
    if (disk->src) {
7094
        const char *format = NULL;
7095 7096 7097
        if (disk->type != VIR_DOMAIN_DISK_TYPE_DIR) {
            if (disk->driverType)
                format = disk->driverType;
7098 7099 7100
            else if (origdisk->driverType)
                format = origdisk->driverType;
        }
7101
        ret = qemuMonitorChangeMedia(priv->mon,
7102
                                     driveAlias,
7103
                                     disk->src, format);
7104
    } else {
7105
        ret = qemuMonitorEjectMedia(priv->mon, driveAlias);
7106
    }
7107
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7108

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

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7114 7115
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, origdisk) < 0)
7116 7117 7118
        VIR_WARN("Unable to restore security label on ejected image %s", origdisk->src);

    VIR_FREE(origdisk->src);
7119 7120 7121 7122
    origdisk->src = disk->src;
    disk->src = NULL;
    origdisk->type = disk->type;

7123 7124
    VIR_FREE(driveAlias);

7125
    virDomainDiskDefFree(disk);
7126

7127
    return ret;
7128 7129

error:
7130
    VIR_FREE(driveAlias);
7131 7132
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7133 7134
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, disk) < 0)
7135
        VIR_WARN("Unable to restore security label on new media %s", disk->src);
7136
    return -1;
7137 7138
}

7139

7140
static int qemudDomainAttachPciDiskDevice(struct qemud_driver *driver,
7141
                                          virDomainObjPtr vm,
7142
                                          virDomainDiskDefPtr disk,
7143
                                          unsigned long long qemuCmdFlags)
7144
{
7145
    int i, ret;
7146
    const char* type = virDomainDiskBusTypeToString(disk->bus);
7147
    qemuDomainObjPrivatePtr priv = vm->privateData;
7148 7149
    char *devstr = NULL;
    char *drivestr = NULL;
7150 7151

    for (i = 0 ; i < vm->def->ndisks ; i++) {
7152
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
7153 7154
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
7155 7156 7157 7158
            return -1;
        }
    }

7159 7160
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
7161 7162
        driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver,
                                                            vm, disk) < 0)
7163 7164
        return -1;

7165
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7166 7167
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
            goto error;
7168 7169
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
7170

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

7174
        if (!(devstr = qemuBuildDriveDevStr(disk)))
7175 7176 7177
            goto error;
    }

7178
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
7179
        virReportOOMError();
7180
        goto error;
7181 7182
    }

7183
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7184 7185
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDrive(priv->mon, drivestr);
7186 7187 7188
        if (ret == 0) {
            ret = qemuMonitorAddDevice(priv->mon, devstr);
            if (ret < 0) {
7189
                VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
7190 7191 7192 7193 7194
                         drivestr, devstr);
                /* XXX should call 'drive_del' on error but this does not
                   exist yet */
            }
        }
7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205
    } 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));
        }
    }
7206
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7207

7208 7209
    if (ret < 0)
        goto error;
7210

7211
    virDomainDiskInsertPreAlloced(vm->def, disk);
7212

7213 7214 7215
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7216 7217 7218
    return 0;

error:
7219 7220 7221
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7222 7223 7224 7225 7226
    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);

7227 7228
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7229 7230
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, disk) < 0)
7231
        VIR_WARN("Unable to restore security label on %s", disk->src);
7232 7233

    return -1;
7234
}
7235

7236

7237
static int qemudDomainAttachPciControllerDevice(struct qemud_driver *driver,
7238
                                                virDomainObjPtr vm,
7239
                                                virDomainControllerDefPtr controller,
7240
                                                unsigned long long qemuCmdFlags)
7241
{
7242 7243
    int i;
    int ret = -1;
7244
    const char* type = virDomainControllerTypeToString(controller->type);
7245
    char *devstr = NULL;
7246 7247 7248
    qemuDomainObjPrivatePtr priv = vm->privateData;

    for (i = 0 ; i < vm->def->ncontrollers ; i++) {
7249 7250
        if ((vm->def->controllers[i]->type == controller->type) &&
            (vm->def->controllers[i]->idx == controller->idx)) {
7251 7252 7253
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s:%d already exists"),
                            type, controller->idx);
7254 7255 7256 7257
            return -1;
        }
    }

7258 7259 7260 7261 7262 7263
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
            goto cleanup;
        if (qemuAssignDeviceControllerAlias(controller) < 0)
            goto cleanup;
    }
7264

7265
    if (!(devstr = qemuBuildControllerDevStr(controller))) {
7266
        virReportOOMError();
7267 7268 7269
        goto cleanup;
    }

7270
    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) {
7271
        virReportOOMError();
7272
        goto cleanup;
7273 7274 7275
    }

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7276 7277 7278 7279 7280 7281 7282
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    } else {
        ret = qemuMonitorAttachPCIDiskController(priv->mon,
                                                 type,
                                                 &controller->info.addr.pci);
    }
7283 7284 7285
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (ret == 0) {
7286 7287
        controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
        virDomainControllerInsertPreAlloced(vm->def, controller);
7288 7289
    }

7290
cleanup:
7291 7292 7293 7294 7295 7296
    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");

7297
    VIR_FREE(devstr);
7298 7299 7300
    return ret;
}

7301

7302
static virDomainControllerDefPtr
7303
qemuDomainFindOrCreateSCSIDiskController(struct qemud_driver *driver,
7304
                                         virDomainObjPtr vm,
7305
                                         int controller,
7306
                                         unsigned long long qemuCmdFlags)
7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319
{
    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 已提交
7320
    /* No SCSI controller present, for backward compatibility we
7321 7322
     * now hotplug a controller */
    if (VIR_ALLOC(cont) < 0) {
7323
        virReportOOMError();
7324 7325 7326 7327
        return NULL;
    }
    cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
    cont->idx = 0;
7328
    cont->model = -1;
7329 7330

    VIR_INFO0("No SCSI controller present, hotplugging one");
7331
    if (qemudDomainAttachPciControllerDevice(driver,
7332
                                             vm, cont, qemuCmdFlags) < 0) {
7333 7334 7335
        VIR_FREE(cont);
        return NULL;
    }
7336 7337 7338 7339 7340 7341 7342 7343 7344

    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("guest unexpectedly quit"));
        /* cont doesn't need freeing here, since the reference
         * now held in def->controllers */
        return NULL;
    }

7345 7346 7347
    return cont;
}

7348

7349
static int qemudDomainAttachSCSIDisk(struct qemud_driver *driver,
7350
                                     virDomainObjPtr vm,
7351
                                     virDomainDiskDefPtr disk,
7352
                                     unsigned long long qemuCmdFlags)
7353 7354 7355
{
    int i;
    qemuDomainObjPrivatePtr priv = vm->privateData;
7356
    virDomainControllerDefPtr cont = NULL;
7357
    char *drivestr = NULL;
7358
    char *devstr = NULL;
7359 7360 7361
    int ret = -1;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
7362
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
7363 7364
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
7365
            return -1;
7366 7367 7368
        }
    }

7369 7370 7371

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
7372 7373
        driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver,
                                                            vm, disk) < 0)
7374 7375
        return -1;

7376
    /* We should have an address already, so make sure */
7377
    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
7378 7379 7380
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected disk address type %s"),
                        virDomainDeviceAddressTypeToString(disk->info.type));
7381
        goto error;
7382 7383
    }

7384 7385 7386
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
7387
        if (!(devstr = qemuBuildDriveDevStr(disk)))
7388 7389 7390 7391 7392 7393
            goto error;
    }

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

7394
    for (i = 0 ; i <= disk->info.addr.drive.controller ; i++) {
7395
        cont = qemuDomainFindOrCreateSCSIDiskController(driver, vm, i, qemuCmdFlags);
7396
        if (!cont)
7397
            goto error;
7398 7399
    }

7400 7401 7402 7403 7404
    /* 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);

7405
    if (cont->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
7406 7407
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("SCSI controller %d was missing its PCI address"), cont->idx);
7408
        goto error;
7409 7410 7411
    }

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

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7417
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7418 7419 7420 7421
        ret = qemuMonitorAddDrive(priv->mon, drivestr);
        if (ret == 0) {
            ret = qemuMonitorAddDevice(priv->mon, devstr);
            if (ret < 0) {
7422
                VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
7423 7424 7425 7426 7427
                         drivestr, devstr);
                /* XXX should call 'drive_del' on error but this does not
                   exist yet */
            }
        }
7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440
    } 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));
        }
    }
7441 7442
    qemuDomainObjExitMonitorWithDriver(driver, vm);

7443 7444
    if (ret < 0)
        goto error;
7445

7446
    virDomainDiskInsertPreAlloced(vm->def, disk);
7447 7448

    VIR_FREE(devstr);
7449
    VIR_FREE(drivestr);
7450 7451 7452 7453

    return 0;

error:
7454
    VIR_FREE(devstr);
7455
    VIR_FREE(drivestr);
7456

7457 7458
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7459 7460
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, disk) < 0)
7461
        VIR_WARN("Unable to restore security label on %s", disk->src);
7462 7463

    return -1;
7464 7465
}

7466

7467
static int qemudDomainAttachUsbMassstorageDevice(struct qemud_driver *driver,
7468
                                                 virDomainObjPtr vm,
7469
                                                 virDomainDiskDefPtr disk,
7470
                                                 unsigned long long qemuCmdFlags)
7471
{
7472
    qemuDomainObjPrivatePtr priv = vm->privateData;
7473
    int i, ret;
7474 7475
    char *drivestr = NULL;
    char *devstr = NULL;
7476

7477
    for (i = 0 ; i < vm->def->ndisks ; i++) {
7478
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
7479 7480
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
7481 7482 7483 7484
            return -1;
        }
    }

7485 7486
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
7487 7488
        driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver,
                                                            vm, disk) < 0)
7489 7490
        return -1;

7491
    if (!disk->src) {
7492 7493
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("disk source path is missing"));
7494
        goto error;
7495 7496
    }

7497
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7498 7499
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
7500 7501
        if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
            goto error;
7502
        if (!(devstr = qemuBuildDriveDevStr(disk)))
7503 7504 7505
            goto error;
    }

7506
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
7507
        virReportOOMError();
7508
        goto error;
7509 7510
    }

7511
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7512
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7513 7514 7515 7516
        ret = qemuMonitorAddDrive(priv->mon, drivestr);
        if (ret == 0) {
            ret = qemuMonitorAddDevice(priv->mon, devstr);
            if (ret < 0) {
7517
                VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
7518 7519 7520 7521 7522
                         drivestr, devstr);
                /* XXX should call 'drive_del' on error but this does not
                   exist yet */
            }
        }
7523 7524 7525
    } else {
        ret = qemuMonitorAddUSBDisk(priv->mon, disk->src);
    }
7526
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7527

7528 7529 7530
    if (ret < 0)
        goto error;

7531
    virDomainDiskInsertPreAlloced(vm->def, disk);
7532

7533 7534 7535
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7536 7537 7538
    return 0;

error:
7539 7540 7541
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7542 7543
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7544 7545
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, disk) < 0)
7546
        VIR_WARN("Unable to restore security label on %s", disk->src);
7547 7548

    return -1;
7549 7550
}

7551

7552
/* XXX conn required for network -> bridge resolution */
M
Mark McLoughlin 已提交
7553
static int qemudDomainAttachNetDevice(virConnectPtr conn,
7554
                                      struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7555
                                      virDomainObjPtr vm,
7556
                                      virDomainNetDefPtr net,
7557
                                      unsigned long long qemuCmdFlags)
M
Mark McLoughlin 已提交
7558
{
7559
    qemuDomainObjPrivatePtr priv = vm->privateData;
7560
    char *tapfd_name = NULL;
7561
    int tapfd = -1;
7562
    char *nicstr = NULL;
7563
    char *netstr = NULL;
7564
    int ret = -1;
7565
    virDomainDevicePCIAddress guestAddr;
7566
    int vlan;
M
Mark McLoughlin 已提交
7567 7568

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
7569 7570
        qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                        _("installed qemu version does not support host_net_add"));
M
Mark McLoughlin 已提交
7571 7572 7573 7574 7575
        return -1;
    }

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
7576
        if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
7577 7578 7579 7580
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("network device type '%s' cannot be attached: "
                              "qemu is not using a unix socket monitor"),
                            virDomainNetTypeToString(net->type));
7581 7582 7583 7584 7585
            return -1;
        }

        if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
            return -1;
7586 7587 7588 7589 7590 7591 7592 7593 7594
    } 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 已提交
7595
        if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
7596 7597
                                           qemuCmdFlags,
                                           vm->def->uuid)) < 0)
7598
            return -1;
M
Mark McLoughlin 已提交
7599 7600
    }

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

7604 7605 7606 7607 7608
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
            goto cleanup;
    }
M
Mark McLoughlin 已提交
7609

7610 7611 7612 7613
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
        goto cleanup;

7614 7615 7616 7617 7618
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        vlan = -1;
    } else {
        vlan = qemuDomainNetVLAN(net);
M
Mark McLoughlin 已提交
7619

7620 7621 7622 7623 7624
        if (vlan < 0) {
            qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                            _("Unable to attach network devices without vlan"));
            goto cleanup;
        }
7625 7626
    }

7627
    if (tapfd != -1) {
7628
        if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0)
7629 7630
            goto no_memory;

7631
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7632
        if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0) {
7633
            qemuDomainObjExitMonitorWithDriver(driver, vm);
7634
            goto cleanup;
7635
        }
7636
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7637 7638 7639 7640 7641 7642

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto cleanup;
        }
7643 7644
    }

7645
    /* FIXME - need to support vhost-net here (5th arg) */
7646 7647 7648 7649 7650 7651 7652 7653 7654 7655
    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 已提交
7656

7657
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (qemuMonitorAddNetdev(priv->mon, netstr) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto try_tapfd_close;
        }
    } else {
        if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto try_tapfd_close;
        }
7669
    }
7670
    qemuDomainObjExitMonitorWithDriver(driver, vm);
M
Mark McLoughlin 已提交
7671

7672 7673 7674
    if (tapfd != -1)
        close(tapfd);
    tapfd = -1;
M
Mark McLoughlin 已提交
7675

7676 7677 7678 7679 7680 7681
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("guest unexpectedly quit"));
        goto cleanup;
    }

7682 7683 7684 7685 7686 7687 7688
    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 已提交
7689

7690
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703
    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));
7704
    }
7705
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7706

7707
    ret = 0;
M
Mark McLoughlin 已提交
7708 7709 7710

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

7711
cleanup:
7712 7713 7714 7715 7716 7717
    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");

7718
    if (ret != 0)
7719
        virDomainConfNWFilterTeardown(net);
S
Stefan Berger 已提交
7720

7721 7722 7723 7724 7725
    VIR_FREE(nicstr);
    VIR_FREE(netstr);
    VIR_FREE(tapfd_name);
    if (tapfd != -1)
        close(tapfd);
7726

7727
    return ret;
7728

7729
try_remove:
7730
    if (!virDomainObjIsActive(vm))
7731 7732
        goto cleanup;

7733
    if (vlan < 0) {
7734 7735 7736 7737 7738 7739 7740
        if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
            (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
            char *netdev_name;
            if (virAsprintf(&netdev_name, "host%s", net->info.alias) < 0)
                goto no_memory;
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            if (qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
7741
                VIR_WARN("Failed to remove network backend for netdev %s",
7742 7743 7744 7745
                         netdev_name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            VIR_FREE(netdev_name);
        } else {
7746
            VIR_WARN0("Unable to remove network backend");
7747
        }
7748 7749 7750 7751
    } else {
        char *hostnet_name;
        if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
            goto no_memory;
7752
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7753
        if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
7754
            VIR_WARN("Failed to remove network backend for vlan %d, net %s",
7755
                     vlan, hostnet_name);
7756
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7757
        VIR_FREE(hostnet_name);
7758
    }
7759
    goto cleanup;
7760

7761
try_tapfd_close:
7762
    if (!virDomainObjIsActive(vm))
7763 7764
        goto cleanup;

7765
    if (tapfd_name) {
7766
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7767
        if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
7768
            VIR_WARN("Failed to close tapfd with '%s'", tapfd_name);
7769
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7770
    }
7771

7772 7773
    goto cleanup;

7774
no_memory:
7775
    virReportOOMError();
7776
    goto cleanup;
M
Mark McLoughlin 已提交
7777 7778
}

7779

7780
static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
7781
                                          virDomainObjPtr vm,
7782
                                          virDomainHostdevDefPtr hostdev,
7783
                                          unsigned long long qemuCmdFlags)
7784
{
7785
    qemuDomainObjPrivatePtr priv = vm->privateData;
7786
    pciDevice *pci;
7787
    int ret;
7788
    char *devstr = NULL;
7789 7790
    int configfd = -1;
    char *configfd_name = NULL;
7791 7792

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

7797
    pci = pciGetDevice(hostdev->source.subsys.u.pci.domain,
7798 7799 7800
                       hostdev->source.subsys.u.pci.bus,
                       hostdev->source.subsys.u.pci.slot,
                       hostdev->source.subsys.u.pci.function);
7801
    if (!pci)
7802
        return -1;
7803

7804
    if (!pciDeviceIsAssignable(pci, !driver->relaxedACS) ||
7805
        (hostdev->managed && pciDettachDevice(pci, driver->activePciHostdevs) < 0) ||
7806 7807
        pciResetDevice(pci, driver->activePciHostdevs) < 0) {
        pciFreeDevice(pci);
7808 7809 7810
        return -1;
    }

7811 7812
    if (pciDeviceListAdd(driver->activePciHostdevs, pci) < 0) {
        pciFreeDevice(pci);
7813
        return -1;
7814
    }
7815
    pci = NULL; /* activePciHostdevs owns the 'pci' reference now */
7816

7817
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7818 7819
        if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
            goto error;
7820 7821
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
            goto error;
7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845
        if (qemuCmdFlags & QEMUD_CMD_FLAG_PCI_CONFIGFD) {
            configfd = qemudOpenPCIConfig(hostdev);
            if (configfd >= 0) {
                if (virAsprintf(&configfd_name, "fd-%s",
                                hostdev->info.alias) < 0) {
                    virReportOOMError();
                    goto error;
                }

                qemuDomainObjEnterMonitorWithDriver(driver, vm);
                if (qemuMonitorSendFileHandle(priv->mon, configfd_name,
                                              configfd) < 0) {
                    qemuDomainObjExitMonitorWithDriver(driver, vm);
                    goto error;
                }
                qemuDomainObjExitMonitorWithDriver(driver, vm);
            }
        }

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit during hotplug"));
            goto error;
        }
7846

7847
        if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name)))
7848
            goto error;
7849

7850
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7851
        ret = qemuMonitorAddDevice(priv->mon, devstr);
7852 7853 7854 7855 7856
        qemuDomainObjExitMonitorWithDriver(driver, vm);
    } else {
        virDomainDevicePCIAddress guestAddr;

        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7857 7858 7859
        ret = qemuMonitorAddPCIHostDevice(priv->mon,
                                          &hostdev->source.subsys.u.pci,
                                          &guestAddr);
7860 7861 7862 7863 7864
        qemuDomainObjExitMonitorWithDriver(driver, vm);

        hostdev->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
        memcpy(&hostdev->info.addr.pci, &guestAddr, sizeof(guestAddr));
    }
7865
    if (ret < 0)
7866
        goto error;
7867 7868 7869

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

7870
    VIR_FREE(devstr);
7871 7872 7873
    VIR_FREE(configfd_name);
    if (configfd >= 0)
        close(configfd);
7874

7875
    return 0;
7876 7877

error:
7878 7879 7880 7881 7882
    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");

7883 7884 7885 7886 7887
    pci = pciGetDevice(hostdev->source.subsys.u.pci.domain,
                       hostdev->source.subsys.u.pci.bus,
                       hostdev->source.subsys.u.pci.slot,
                       hostdev->source.subsys.u.pci.function);

7888
    pciDeviceListDel(driver->activePciHostdevs, pci);
7889 7890 7891 7892

    if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
        VIR_WARN0("Unable to reset PCI device after assign failure");
    else if (hostdev->managed &&
7893
             pciReAttachDevice(pci, driver->activePciHostdevs) < 0)
7894 7895 7896 7897 7898
        VIR_WARN0("Unable to re-attach PCI device after assign failure");
    pciFreeDevice(pci);


    VIR_FREE(devstr);
7899 7900 7901
    VIR_FREE(configfd_name);
    if (configfd >= 0)
        close(configfd);
7902 7903

    return -1;
7904 7905
}

7906

7907
static int qemudDomainAttachHostUsbDevice(struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7908
                                          virDomainObjPtr vm,
7909
                                          virDomainHostdevDefPtr hostdev,
7910
                                          unsigned long long qemuCmdFlags)
7911 7912
{
    int ret;
7913
    qemuDomainObjPrivatePtr priv = vm->privateData;
7914 7915
    char *devstr = NULL;

7916 7917 7918 7919 7920 7921
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
            goto error;
        if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
            goto error;
    }
7922

7923
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
7924
        virReportOOMError();
7925
        goto error;
7926
    }
7927

7928
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7929 7930 7931
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    else
7932
        ret = qemuMonitorAddUSBDeviceExact(priv->mon,
7933 7934
                                           hostdev->source.subsys.u.usb.bus,
                                           hostdev->source.subsys.u.usb.device);
7935
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7936 7937 7938 7939
    if (ret < 0)
        goto error;

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

7941
    VIR_FREE(devstr);
7942

7943 7944 7945 7946 7947
    return 0;

error:
    VIR_FREE(devstr);
    return -1;
7948 7949
}

7950

7951
static int qemudDomainAttachHostDevice(struct qemud_driver *driver,
M
Mark McLoughlin 已提交
7952
                                       virDomainObjPtr vm,
7953
                                       virDomainHostdevDefPtr hostdev,
7954
                                       unsigned long long qemuCmdFlags)
M
Mark McLoughlin 已提交
7955 7956
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
7957 7958 7959
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev mode '%s' not supported"),
                        virDomainHostdevModeTypeToString(hostdev->mode));
M
Mark McLoughlin 已提交
7960 7961 7962
        return -1;
    }

7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979
    /* 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);
    }


7980
    if (driver->securityDriver &&
7981
        driver->securityDriver->domainSetSecurityHostdevLabel &&
7982 7983
        driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
                                                              vm, hostdev) < 0)
7984
        return -1;
M
Mark McLoughlin 已提交
7985 7986

    switch (hostdev->source.subsys.type) {
7987
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
7988
        if (qemudDomainAttachHostPciDevice(driver, vm,
7989
                                           hostdev, qemuCmdFlags) < 0)
7990 7991 7992
            goto error;
        break;

M
Mark McLoughlin 已提交
7993
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
7994
        if (qemudDomainAttachHostUsbDevice(driver, vm,
7995
                                           hostdev, qemuCmdFlags) < 0)
7996 7997 7998
            goto error;
        break;

M
Mark McLoughlin 已提交
7999
    default:
8000 8001 8002
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev subsys type '%s' not supported"),
                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
8003
        goto error;
M
Mark McLoughlin 已提交
8004
    }
8005 8006 8007 8008 8009 8010

    return 0;

error:
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityHostdevLabel &&
8011 8012
        driver->securityDriver->domainRestoreSecurityHostdevLabel(driver->securityDriver,
                                                                  vm, hostdev) < 0)
8013 8014 8015
        VIR_WARN0("Unable to restore host device labelling on hotplug fail");

    return -1;
M
Mark McLoughlin 已提交
8016 8017
}

8018

8019
static int qemudDomainAttachDevice(virDomainPtr dom,
8020 8021
                                   const char *xml)
{
8022 8023 8024
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
8025
    unsigned long long qemuCmdFlags;
8026
    virCgroupPtr cgroup = NULL;
8027
    int ret = -1;
8028

8029
    qemuDriverLock(driver);
8030
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8031
    if (!vm) {
8032 8033
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8034 8035
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8036
        goto cleanup;
8037 8038
    }

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

D
Daniel P. Berrange 已提交
8042
    if (!virDomainObjIsActive(vm)) {
8043 8044
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot attach device on inactive domain"));
8045
        goto endjob;
8046 8047
    }

8048
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
8049
                                  VIR_DOMAIN_XML_INACTIVE);
8050
    if (dev == NULL)
8051
        goto endjob;
8052

8053 8054 8055
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
8056
        goto endjob;
8057

8058
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
8059
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
8060
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
8061 8062 8063
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Unable to find cgroup for %s\n"),
                                vm->def->name);
8064
                goto endjob;
8065
            }
8066
            if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0)
8067
                goto endjob;
8068 8069
        }

8070
        switch (dev->data.disk->device) {
8071 8072
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
8073 8074 8075
            ret = qemudDomainChangeEjectableMedia(driver, vm,
                                                  dev->data.disk,
                                                  qemuCmdFlags);
8076 8077
            if (ret == 0)
                dev->data.disk = NULL;
8078
            break;
8079

8080 8081
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
8082
                ret = qemudDomainAttachUsbMassstorageDevice(driver, vm,
8083
                                                            dev->data.disk, qemuCmdFlags);
8084 8085
                if (ret == 0)
                    dev->data.disk = NULL;
8086
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
8087
                ret = qemudDomainAttachPciDiskDevice(driver, vm,
8088
                                                     dev->data.disk, qemuCmdFlags);
8089 8090
                if (ret == 0)
                    dev->data.disk = NULL;
8091
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
8092
                ret = qemudDomainAttachSCSIDisk(driver, vm,
8093
                                                dev->data.disk, qemuCmdFlags);
8094 8095
                if (ret == 0)
                    dev->data.disk = NULL;
8096
            } else {
8097 8098 8099
                qemuReportError(VIR_ERR_NO_SUPPORT,
                                _("disk bus '%s' cannot be hotplugged."),
                                virDomainDiskBusTypeToString(dev->data.disk->bus));
8100
                /* fallthrough */
8101 8102
            }
            break;
8103

8104
        default:
8105 8106 8107
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk device type '%s' cannot be hotplugged"),
                            virDomainDiskDeviceTypeToString(dev->data.disk->device));
8108 8109
            /* Fallthrough */
        }
8110
        if (ret != 0 && cgroup) {
8111
            if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
8112 8113
                VIR_WARN("Failed to teardown cgroup for disk path %s",
                         NULLSTR(dev->data.disk->src));
8114
        }
8115 8116
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
8117
            ret = qemudDomainAttachPciControllerDevice(driver, vm,
8118
                                                       dev->data.controller, qemuCmdFlags);
8119 8120
            if (ret == 0)
                dev->data.controller = NULL;
8121
        } else {
8122 8123 8124
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk controller bus '%s' cannot be hotplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
8125 8126
            /* fallthrough */
        }
M
Mark McLoughlin 已提交
8127
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
8128 8129
        ret = qemudDomainAttachNetDevice(dom->conn, driver, vm,
                                         dev->data.net, qemuCmdFlags);
8130 8131
        if (ret == 0)
            dev->data.net = NULL;
M
Mark McLoughlin 已提交
8132
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
8133
        ret = qemudDomainAttachHostDevice(driver, vm,
8134
                                          dev->data.hostdev, qemuCmdFlags);
8135 8136
        if (ret == 0)
            dev->data.hostdev = NULL;
8137
    } else {
8138 8139 8140
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("device type '%s' cannot be attached"),
                        virDomainDeviceTypeToString(dev->type));
8141
        goto endjob;
8142 8143
    }

8144
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
8145 8146
        ret = -1;

8147
endjob:
8148 8149
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
8150

8151
cleanup:
8152 8153 8154
    if (cgroup)
        virCgroupFree(&cgroup);

8155
    virDomainDeviceDefFree(dev);
8156 8157
    if (vm)
        virDomainObjUnlock(vm);
8158
    qemuDriverUnlock(driver);
8159 8160 8161
    return ret;
}

8162 8163 8164 8165
static int qemudDomainAttachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
8166 8167
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
8168 8169 8170 8171 8172 8173
        return -1;
    }

    return qemudDomainAttachDevice(dom, xml);
}

8174

8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251
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;
}


8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262
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;

8263 8264 8265 8266
    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_CURRENT |
                  VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

8267 8268 8269 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
    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;
            }
8311
            if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0)
8312 8313 8314 8315 8316 8317
                goto endjob;
        }

        switch (dev->data.disk->device) {
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
8318 8319 8320
            ret = qemudDomainChangeEjectableMedia(driver, vm,
                                                  dev->data.disk,
                                                  qemuCmdFlags);
8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333
            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) {
8334
            if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
8335 8336
                VIR_WARN("Failed to teardown cgroup for disk path %s",
                         NULLSTR(dev->data.disk->src));
8337 8338 8339
        }
        break;

8340 8341 8342 8343
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;

8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369
    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 已提交
8370
static inline int qemudFindDisk(virDomainDefPtr def, const char *dst)
W
Wolfgang Mauerer 已提交
8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382
{
    int i;

    for (i = 0 ; i < def->ndisks ; i++) {
        if (STREQ(def->disks[i]->dst, dst)) {
            return i;
        }
    }

    return -1;
}

E
Eric Blake 已提交
8383
static inline void qemudShrinkDisks(virDomainDefPtr def, size_t i)
W
Wolfgang Mauerer 已提交
8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399
{
    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;
    }
}

8400
static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
8401
                                          virDomainObjPtr vm,
8402 8403
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
8404 8405 8406
{
    int i, ret = -1;
    virDomainDiskDefPtr detach = NULL;
8407
    qemuDomainObjPrivatePtr priv = vm->privateData;
8408
    virCgroupPtr cgroup = NULL;
8409

W
Wolfgang Mauerer 已提交
8410
    i = qemudFindDisk(vm->def, dev->data.disk->dst);
8411

W
Wolfgang Mauerer 已提交
8412
    if (i < 0) {
8413 8414
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk %s not found"), dev->data.disk->dst);
8415
        goto cleanup;
8416 8417
    }

W
Wolfgang Mauerer 已提交
8418 8419
    detach = vm->def->disks[i];

8420 8421 8422 8423 8424 8425 8426 8427 8428
    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 cleanup;
        }
    }

8429 8430
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
8431 8432
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("device cannot be detached without a PCI address"));
8433
        goto cleanup;
8434 8435
    }

8436
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447
    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;
        }
8448
    }
8449
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8450

W
Wolfgang Mauerer 已提交
8451 8452
    qemudShrinkDisks(vm->def, i);

8453 8454
    virDomainDiskDefFree(detach);

8455 8456
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
8457 8458
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, dev->data.disk) < 0)
8459 8460
        VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);

8461
    if (cgroup != NULL) {
8462
        if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
8463 8464 8465 8466
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(dev->data.disk->src));
    }

8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480
    ret = 0;

cleanup:
    return ret;
}

static int qemudDomainDetachSCSIDiskDevice(struct qemud_driver *driver,
                                           virDomainObjPtr vm,
                                           virDomainDeviceDefPtr dev,
                                           unsigned long long qemuCmdFlags)
{
    int i, ret = -1;
    virDomainDiskDefPtr detach = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
8481
    virCgroupPtr cgroup = NULL;
8482 8483 8484 8485 8486 8487 8488 8489 8490 8491

    i = qemudFindDisk(vm->def, dev->data.disk->dst);

    if (i < 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk %s not found"), dev->data.disk->dst);
        goto cleanup;
    }

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
8492
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
8493 8494 8495 8496 8497 8498
                        _("Underlying qemu does not support SCSI disk removal"));
        goto cleanup;
    }

    detach = vm->def->disks[i];

8499 8500 8501 8502 8503 8504 8505 8506 8507
    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 cleanup;
        }
    }

8508 8509 8510 8511 8512 8513 8514 8515 8516
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
        qemuDomainObjExitMonitor(vm);
        goto cleanup;
    }
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    qemudShrinkDisks(vm->def, i);

8517
    virDomainDiskDefFree(detach);
8518

8519 8520
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
8521 8522
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, dev->data.disk) < 0)
8523 8524
        VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);

8525
    if (cgroup != NULL) {
8526
        if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
8527 8528 8529 8530
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(dev->data.disk->src));
    }

8531
    ret = 0;
8532 8533

cleanup:
8534
    virCgroupFree(&cgroup);
8535 8536 8537
    return ret;
}

8538
static int qemudDomainDetachPciControllerDevice(struct qemud_driver *driver,
8539
                                                virDomainObjPtr vm,
8540 8541
                                                virDomainDeviceDefPtr dev,
                                                unsigned long long qemuCmdFlags)
8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555
{
    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) {
8556 8557 8558 8559
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk controller %s:%d not found"),
                        virDomainControllerTypeToString(dev->data.controller->type),
                        dev->data.controller->idx);
8560 8561 8562 8563 8564
        goto cleanup;
    }

    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
8565 8566
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("device cannot be detached without a PCI address"));
8567 8568 8569
        goto cleanup;
    }

8570 8571 8572 8573 8574
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceControllerAlias(detach) < 0)
            goto cleanup;
    }

8575
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586
    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;
        }
8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602
    }
    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;
    }
8603

8604 8605
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
8606 8607
        VIR_WARN0("Unable to release PCI address on controller");

8608 8609 8610 8611 8612 8613 8614 8615
    virDomainControllerDefFree(detach);

    ret = 0;

cleanup:
    return ret;
}

8616
static int
8617
qemudDomainDetachNetDevice(struct qemud_driver *driver,
8618
                           virDomainObjPtr vm,
8619 8620
                           virDomainDeviceDefPtr dev,
                           unsigned long long qemuCmdFlags)
8621 8622 8623
{
    int i, ret = -1;
    virDomainNetDefPtr detach = NULL;
8624
    qemuDomainObjPrivatePtr priv = vm->privateData;
8625 8626
    int vlan;
    char *hostnet_name = NULL;
8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637

    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) {
8638 8639 8640 8641 8642
        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]);
8643 8644 8645
        goto cleanup;
    }

8646 8647
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
8648 8649
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a PCI address"));
8650 8651 8652
        goto cleanup;
    }

8653
    if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
8654 8655
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("unable to determine original VLAN"));
8656 8657 8658 8659
        goto cleanup;
    }

    if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) {
8660
        virReportOOMError();
8661 8662 8663
        goto cleanup;
    }

8664
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675
    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;
        }
8676
    }
8677

8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto cleanup;
        }
    } else {
        if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            goto cleanup;
        }
8689
    }
8690
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8691

8692
    virDomainConfNWFilterTeardown(detach);
8693

8694
#if WITH_MACVTAP
8695
    if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
8696
        delMacvtap(detach->ifname, detach->mac, detach->data.direct.linkdev,
8697
                   &detach->data.direct.virtPortProfile);
8698 8699
        VIR_FREE(detach->ifname);
    }
8700 8701
#endif

8702
    if ((driver->macFilter) && (detach->ifname != NULL)) {
8703
        if ((errno = networkDisallowMacOnPort(driver,
8704 8705
                                              detach->ifname,
                                              detach->mac))) {
8706
            virReportSystemError(errno,
8707 8708 8709 8710 8711
             _("failed to remove ebtables rule on  '%s'"),
                                 detach->ifname);
        }
    }

8712 8713 8714 8715 8716 8717 8718 8719 8720 8721
    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 {
8722
        VIR_FREE(vm->def->nets);
8723
        vm->def->nnets = 0;
8724
    }
8725
    virDomainNetDefFree(detach);
8726

8727 8728 8729
    ret = 0;

cleanup:
8730
    VIR_FREE(hostnet_name);
8731 8732 8733
    return ret;
}

8734
static int qemudDomainDetachHostPciDevice(struct qemud_driver *driver,
8735
                                          virDomainObjPtr vm,
8736 8737
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
8738
{
8739
    virDomainHostdevDefPtr detach = NULL;
8740
    qemuDomainObjPrivatePtr priv = vm->privateData;
8741
    int i, ret;
8742
    pciDevice *pci;
8743 8744

    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
8745 8746 8747 8748
        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;

8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763
        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) {
8764 8765 8766 8767 8768 8769
        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);
8770 8771 8772
        return -1;
    }

8773 8774
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
8775 8776
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a PCI address"));
8777 8778 8779
        return -1;
    }

8780
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791
    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;
        }
8792
    }
8793
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8794 8795 8796

    ret = 0;

8797
    pci = pciGetDevice(detach->source.subsys.u.pci.domain,
8798 8799 8800 8801 8802 8803
                       detach->source.subsys.u.pci.bus,
                       detach->source.subsys.u.pci.slot,
                       detach->source.subsys.u.pci.function);
    if (!pci)
        ret = -1;
    else {
8804
        pciDeviceSetManaged(pci, detach->managed);
8805 8806
        pciDeviceListDel(driver->activePciHostdevs, pci);
        if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
8807
            ret = -1;
8808
        qemudReattachManagedDevice(pci, driver);
8809
        pciFreeDevice(pci);
8810 8811
    }

8812 8813
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
8814 8815
        VIR_WARN0("Unable to release PCI address on controller");

8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827
    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;
8828
    }
8829
    virDomainHostdevDefFree(detach);
8830 8831 8832 8833

    return ret;
}

8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849
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;
8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865
        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;
            }
8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915
        }
    }

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

8916
static int qemudDomainDetachHostDevice(struct qemud_driver *driver,
8917
                                       virDomainObjPtr vm,
8918 8919
                                       virDomainDeviceDefPtr dev,
                                       unsigned long long qemuCmdFlags)
8920 8921 8922 8923 8924
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
    int ret;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
8925 8926 8927
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev mode '%s' not supported"),
                        virDomainHostdevModeTypeToString(hostdev->mode));
8928 8929 8930 8931 8932
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
8933
        ret = qemudDomainDetachHostPciDevice(driver, vm, dev, qemuCmdFlags);
8934
        break;
8935 8936 8937
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        ret = qemudDomainDetachHostUsbDevice(driver, vm, dev, qemuCmdFlags);
        break;
8938
    default:
8939 8940 8941
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        _("hostdev subsys type '%s' not supported"),
                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
8942 8943 8944
        return -1;
    }

8945
    if (driver->securityDriver &&
8946
        driver->securityDriver->domainRestoreSecurityHostdevLabel &&
8947 8948
        driver->securityDriver->domainRestoreSecurityHostdevLabel(driver->securityDriver,
                                                                  vm, dev->data.hostdev) < 0)
8949
        VIR_WARN0("Failed to restore host device labelling");
8950

8951 8952 8953
    return ret;
}

8954 8955
static int qemudDomainDetachDevice(virDomainPtr dom,
                                   const char *xml) {
8956 8957
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8958
    unsigned long long qemuCmdFlags;
8959 8960
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;
8961

8962
    qemuDriverLock(driver);
8963
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8964
    if (!vm) {
8965 8966
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8967 8968
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8969
        goto cleanup;
8970 8971
    }

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

D
Daniel P. Berrange 已提交
8975
    if (!virDomainObjIsActive(vm)) {
8976 8977
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot detach device on inactive domain"));
8978
        goto endjob;
8979 8980
    }

8981
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
8982
                                  VIR_DOMAIN_XML_INACTIVE);
8983
    if (dev == NULL)
8984
        goto endjob;
8985

8986 8987 8988 8989
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
        goto endjob;
8990 8991

    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003
        dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
        if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
            ret = qemudDomainDetachPciDiskDevice(driver, vm, dev, qemuCmdFlags);
        }
        else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
            ret = qemudDomainDetachSCSIDiskDevice(driver, vm, dev,
                                                  qemuCmdFlags);
        }
        else {
            qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                            _("This type of disk cannot be hot unplugged"));
        }
9004
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
9005
        ret = qemudDomainDetachNetDevice(driver, vm, dev, qemuCmdFlags);
9006 9007
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
9008 9009
            ret = qemudDomainDetachPciControllerDevice(driver, vm, dev,
                                                       qemuCmdFlags);
9010
        } else {
9011 9012 9013
            qemuReportError(VIR_ERR_NO_SUPPORT,
                            _("disk controller bus '%s' cannot be hotunplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
9014 9015
            /* fallthrough */
        }
9016
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
9017
        ret = qemudDomainDetachHostDevice(driver, vm, dev, qemuCmdFlags);
9018
    } else {
9019 9020
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("This type of device cannot be hot unplugged"));
9021
    }
9022

9023
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
9024 9025
        ret = -1;

9026
endjob:
9027 9028
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9029

9030 9031
cleanup:
    virDomainDeviceDefFree(dev);
9032 9033
    if (vm)
        virDomainObjUnlock(vm);
9034
    qemuDriverUnlock(driver);
9035 9036 9037
    return ret;
}

9038 9039 9040 9041
static int qemudDomainDetachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
9042 9043
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
9044 9045 9046 9047 9048 9049
        return -1;
    }

    return qemudDomainDetachDevice(dom, xml);
}

9050
static int qemudDomainGetAutostart(virDomainPtr dom,
9051
                                   int *autostart) {
9052 9053 9054
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
9055

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

9060
    if (!vm) {
9061 9062
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9063 9064
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9065
        goto cleanup;
9066 9067 9068
    }

    *autostart = vm->autostart;
9069
    ret = 0;
9070

9071
cleanup:
9072 9073
    if (vm)
        virDomainObjUnlock(vm);
9074
    return ret;
9075 9076
}

9077
static int qemudDomainSetAutostart(virDomainPtr dom,
9078
                                   int autostart) {
9079 9080
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
9081 9082
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
9083

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

9087
    if (!vm) {
9088 9089
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9090 9091
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9092
        goto cleanup;
9093 9094
    }

9095
    if (!vm->persistent) {
9096 9097
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot set autostart for transient domain"));
9098
        goto cleanup;
9099 9100
    }

9101 9102
    autostart = (autostart != 0);

9103
    if (vm->autostart != autostart) {
9104
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
9105
            goto cleanup;
9106
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
9107
            goto cleanup;
9108

9109 9110
        if (autostart) {
            int err;
9111

9112
            if ((err = virFileMakePath(driver->autostartDir))) {
9113
                virReportSystemError(err,
9114 9115
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
9116 9117
                goto cleanup;
            }
9118

9119
            if (symlink(configFile, autostartLink) < 0) {
9120
                virReportSystemError(errno,
9121 9122
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
9123 9124 9125 9126
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
9127
                virReportSystemError(errno,
9128 9129
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
9130 9131
                goto cleanup;
            }
9132 9133
        }

9134
        vm->autostart = autostart;
9135
    }
9136
    ret = 0;
9137

9138 9139 9140
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
9141 9142
    if (vm)
        virDomainObjUnlock(vm);
9143
    qemuDriverUnlock(driver);
9144
    return ret;
9145 9146
}

9147 9148 9149 9150 9151

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

9154
    qemuDriverLock(driver);
9155
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
9156 9157
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
9158
        goto cleanup;
9159 9160 9161 9162 9163 9164 9165
    }

    if (nparams)
        *nparams = 1;

    ret = strdup("posix");
    if (!ret)
9166
        virReportOOMError();
9167 9168 9169

cleanup:
    qemuDriverUnlock(driver);
9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182
    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;

9183
    qemuDriverLock(driver);
9184
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
9185 9186
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
9187
        goto cleanup;
9188 9189 9190 9191 9192
    }

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

    if (vm == NULL) {
9193 9194
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
9195 9196 9197 9198
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
9199 9200
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
9201 9202 9203 9204 9205 9206 9207 9208 9209
        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) {
9210 9211
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for cpu_shares tunable, expected a 'ullong'"));
9212 9213 9214 9215 9216
                goto cleanup;
            }

            rc = virCgroupSetCpuShares(group, params[i].value.ul);
            if (rc != 0) {
9217
                virReportSystemError(-rc, "%s",
9218 9219 9220 9221
                                     _("unable to set cpu shares tunable"));
                goto cleanup;
            }
        } else {
9222 9223
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Invalid parameter `%s'"), param->field);
9224 9225 9226 9227 9228 9229 9230 9231 9232
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
9233
    qemuDriverUnlock(driver);
9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247
    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;

9248
    qemuDriverLock(driver);
9249
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
9250 9251
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
9252
        goto cleanup;
9253 9254 9255
    }

    if ((*nparams) != 1) {
9256 9257
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
9258
        goto cleanup;
9259 9260 9261 9262 9263
    }

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

    if (vm == NULL) {
9264 9265
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
9266 9267 9268 9269
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
9270 9271
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
9272 9273 9274 9275 9276
        goto cleanup;
    }

    rc = virCgroupGetCpuShares(group, &val);
    if (rc != 0) {
9277
        virReportSystemError(-rc, "%s",
9278 9279 9280 9281 9282
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
    params[0].value.ul = val;
    params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
C
Chris Lalancette 已提交
9283
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
9284 9285
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Field cpu_shares too long for destination"));
C
Chris Lalancette 已提交
9286 9287
        goto cleanup;
    }
9288 9289 9290 9291 9292 9293 9294

    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
9295
    qemuDriverUnlock(driver);
9296 9297 9298 9299
    return ret;
}


9300 9301 9302 9303 9304 9305 9306 9307 9308
/* 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)
{
9309
    struct qemud_driver *driver = dom->conn->privateData;
9310
    int i, ret = -1;
9311
    virDomainObjPtr vm;
9312
    virDomainDiskDefPtr disk = NULL;
9313

9314
    qemuDriverLock(driver);
9315
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
9316
    qemuDriverUnlock(driver);
9317
    if (!vm) {
9318 9319
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9320 9321
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9322
        goto cleanup;
9323
    }
9324 9325 9326 9327

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

D
Daniel P. Berrange 已提交
9328
    if (!virDomainObjIsActive (vm)) {
9329 9330
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
9331
        goto endjob;
9332 9333
    }

9334 9335 9336 9337 9338 9339 9340 9341
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
9342 9343
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path: %s"), path);
9344
        goto endjob;
9345 9346
    }

9347
    if (!disk->info.alias) {
9348 9349
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), disk->dst);
9350
        goto endjob;
9351
    }
9352

9353
    qemuDomainObjPrivatePtr priv = vm->privateData;
9354 9355
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
9356
                                       disk->info.alias,
9357 9358 9359 9360 9361 9362
                                       &stats->rd_req,
                                       &stats->rd_bytes,
                                       &stats->wr_req,
                                       &stats->wr_bytes,
                                       &stats->errs);
    qemuDomainObjExitMonitor(vm);
9363

9364
endjob:
9365 9366
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9367

9368
cleanup:
9369 9370
    if (vm)
        virDomainObjUnlock(vm);
9371
    return ret;
9372 9373
}

9374
#ifdef __linux__
9375 9376 9377 9378 9379
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
9380 9381
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
9382
    int i;
9383
    int ret = -1;
9384

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

9389
    if (!vm) {
9390 9391
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9392 9393
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9394
        goto cleanup;
9395 9396
    }

D
Daniel P. Berrange 已提交
9397
    if (!virDomainObjIsActive(vm)) {
9398 9399
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
9400
        goto cleanup;
9401 9402 9403
    }

    /* Check the path is one of the domain's network interfaces. */
9404 9405
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
9406 9407 9408 9409
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
9410 9411
    }

9412
    if (ret == 0)
9413
        ret = linuxDomainInterfaceStats(path, stats);
9414
    else
9415 9416
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path, '%s' is not a known interface"), path);
9417

9418
cleanup:
9419 9420
    if (vm)
        virDomainObjUnlock(vm);
9421 9422
    return ret;
}
9423
#else
9424 9425 9426 9427
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
9428 9429
    qemuReportError(VIR_ERR_NO_SUPPORT,
                    "%s", __FUNCTION__);
9430 9431
    return -1;
}
9432
#endif
9433

9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449
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);
9450 9451
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9452 9453 9454
        goto cleanup;
    }

9455 9456 9457
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

9458 9459 9460
    if (virDomainObjIsActive(vm)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        qemuDomainObjEnterMonitor(vm);
9461
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
9462 9463
        qemuDomainObjExitMonitor(vm);
    } else {
9464 9465
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
9466 9467
    }

9468 9469 9470
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

9471 9472 9473 9474 9475 9476
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

9477 9478 9479 9480 9481 9482 9483
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
9484 9485 9486
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
9487

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

9492
    if (!vm) {
9493 9494
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9495 9496
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9497
        goto cleanup;
9498 9499 9500
    }

    if (!path || path[0] == '\0') {
9501 9502
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("NULL or empty path"));
9503
        goto cleanup;
9504 9505 9506
    }

    /* Check the path belongs to this domain. */
9507 9508
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
9509 9510 9511 9512
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
9513 9514
    }

9515 9516 9517 9518 9519
    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) {
9520 9521
            virReportSystemError(errno,
                                 _("%s: failed to open"), path);
9522 9523
            goto cleanup;
        }
9524

9525 9526 9527 9528 9529 9530
        /* 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) {
9531 9532
            virReportSystemError(errno,
                                 _("%s: failed to seek or read"), path);
9533 9534 9535 9536 9537
            goto cleanup;
        }

        ret = 0;
    } else {
9538 9539
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("invalid path"));
9540 9541
    }

9542 9543 9544
cleanup:
    if (fd >= 0)
        close (fd);
9545 9546
    if (vm)
        virDomainObjUnlock(vm);
9547 9548 9549
    return ret;
}

R
Richard W.M. Jones 已提交
9550 9551 9552 9553 9554 9555
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
9556 9557
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
9558
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
9559 9560
    int fd = -1, ret = -1;

9561
    qemuDriverLock(driver);
9562
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
9563
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
9564 9565

    if (!vm) {
9566 9567
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9568 9569
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9570 9571 9572
        goto cleanup;
    }

9573
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
9574 9575
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
9576
        goto cleanup;
R
Richard W.M. Jones 已提交
9577 9578
    }

9579 9580 9581
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
9582
    if (!virDomainObjIsActive(vm)) {
9583 9584
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
9585
        goto endjob;
R
Richard W.M. Jones 已提交
9586 9587
    }

9588
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", driver->cacheDir) < 0) {
9589
        virReportOOMError();
9590
        goto endjob;
9591 9592
    }

R
Richard W.M. Jones 已提交
9593 9594
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
9595 9596
        virReportSystemError(errno,
                             _("mkstemp(\"%s\") failed"), tmp);
9597
        goto endjob;
R
Richard W.M. Jones 已提交
9598 9599
    }

9600
    qemuDomainObjPrivatePtr priv = vm->privateData;
9601
    qemuDomainObjEnterMonitor(vm);
9602
    if (flags == VIR_MEMORY_VIRTUAL) {
9603 9604
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
9605
            goto endjob;
9606
        }
9607
    } else {
9608 9609
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
9610
            goto endjob;
9611
        }
R
Richard W.M. Jones 已提交
9612
    }
9613
    qemuDomainObjExitMonitor(vm);
R
Richard W.M. Jones 已提交
9614 9615 9616

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
9617 9618 9619
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
9620
        goto endjob;
R
Richard W.M. Jones 已提交
9621 9622 9623
    }

    ret = 0;
9624

9625
endjob:
9626 9627
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9628

9629
cleanup:
9630
    VIR_FREE(tmp);
R
Richard W.M. Jones 已提交
9631 9632
    if (fd >= 0) close (fd);
    unlink (tmp);
9633 9634
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
9635 9636 9637
    return ret;
}

9638

9639 9640 9641 9642 9643 9644 9645 9646 9647 9648
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;
9649
    virDomainDiskDefPtr disk = NULL;
9650 9651
    struct stat sb;
    int i;
9652
    int format;
9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676

    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)) {
9677
            disk = vm->def->disks[i];
9678 9679 9680 9681
            break;
        }
    }

9682
    if (!disk) {
9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path %s not assigned to domain"), path);
        goto cleanup;
    }

    /* 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 */
9697 9698 9699 9700 9701 9702 9703 9704
    if (disk->driverType) {
        if ((format = virStorageFileFormatTypeFromString(disk->driverType)) < 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("unknown disk format %s for %s"),
                            disk->driverType, disk->src);
            goto cleanup;
        }
    } else {
9705 9706 9707 9708 9709 9710 9711
        if (driver->allowDiskFormatProbing) {
            if ((format = virStorageFileProbeFormat(disk->src)) < 0)
                goto cleanup;
        } else {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no disk format for %s and probing is disabled"),
                            disk->src);
9712
            goto cleanup;
9713
        }
9714 9715 9716 9717 9718
    }

    if (virStorageFileGetMetadataFromFD(path, fd,
                                        format,
                                        &meta) < 0)
9719 9720 9721 9722 9723 9724 9725 9726 9727 9728
        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)) {
9729
#ifndef WIN32
9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757
        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;

9758
    /* Set default value .. */
9759 9760
    info->allocation = info->physical;

9761 9762 9763 9764 9765
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
    if (virDomainObjIsActive(vm) &&
        disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
9766
        format != VIR_STORAGE_FILE_RAW &&
9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782
        S_ISBLK(sb.st_mode)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        if (qemuDomainObjBeginJob(vm) < 0)
            goto cleanup;

        qemuDomainObjEnterMonitor(vm);
        ret = qemuMonitorGetBlockExtent(priv->mon,
                                        disk->info.alias,
                                        &info->allocation);
        qemuDomainObjExitMonitor(vm);

        if (qemuDomainObjEndJob(vm) == 0)
            vm = NULL;
    } else {
        ret = 0;
    }
9783 9784 9785 9786 9787 9788 9789 9790 9791 9792

cleanup:
    if (fd != -1)
        close(fd);
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


9793
static int
9794 9795 9796 9797
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
9798
{
9799 9800 9801
    struct qemud_driver *driver = conn->privateData;
    int ret;

9802
    qemuDriverLock(driver);
9803 9804
    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
                                        callback, opaque, freecb);
9805
    qemuDriverUnlock(driver);
9806

9807
    return ret;
9808 9809
}

9810

9811
static int
9812 9813
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
9814
{
9815 9816 9817
    struct qemud_driver *driver = conn->privateData;
    int ret;

9818
    qemuDriverLock(driver);
9819 9820 9821 9822 9823 9824
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
                                               callback);
9825
    qemuDriverUnlock(driver);
9826

9827
    return ret;
9828 9829
}

9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872

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


9873 9874
static void qemuDomainEventDispatchFunc(virConnectPtr conn,
                                        virDomainEventPtr event,
9875
                                        virConnectDomainEventGenericCallback cb,
9876 9877
                                        void *cbopaque,
                                        void *opaque)
9878
{
9879
    struct qemud_driver *driver = opaque;
9880

9881 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924
    /* 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);
9925 9926
}

D
Daniel Veillard 已提交
9927 9928
/* Migration support. */

C
Chris Lalancette 已提交
9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947
/* 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) {
9948 9949
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9950 9951 9952 9953 9954
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch == 0) {
9955 9956
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream does not have a callback registered"));
C
Chris Lalancette 已提交
9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984
        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) {
9985 9986
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
9987 9988 9989 9990 9991
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch == 0) {
9992 9993
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream does not have a callback registered"));
C
Chris Lalancette 已提交
9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050
        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) {
10051 10052
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
10053 10054 10055 10056 10057
        return -1;
    }

    qemuDriverLock(driver);
    if (qemust->watch != 0) {
10058 10059
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream already has a callback registered"));
C
Chris Lalancette 已提交
10060 10061 10062 10063 10064 10065 10066 10067
        goto cleanup;
    }

    if ((qemust->watch = virEventAddHandle(qemust->fd,
                                           events,
                                           qemuStreamMigEvent,
                                           st,
                                           NULL)) < 0) {
10068 10069
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot register file watch on stream"));
C
Chris Lalancette 已提交
10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101
        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;

10102
    if (VIR_ALLOC(qemust) < 0) {
10103
        virReportOOMError();
C
Chris Lalancette 已提交
10104
        return NULL;
10105
    }
C
Chris Lalancette 已提交
10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166

    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) {
10167 10168
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("stream is not open"));
C
Chris Lalancette 已提交
10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182
        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;
10183
            virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221
                                 _("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;
10222
    unsigned long long qemuCmdFlags;
C
Chris Lalancette 已提交
10223
    struct qemuStreamMigFile *qemust = NULL;
10224 10225 10226 10227 10228 10229 10230 10231
    qemuDomainObjPrivatePtr priv = NULL;
    struct timeval now;

    if (gettimeofday(&now, NULL) < 0) {
        virReportSystemError(errno, "%s",
                             _("cannot get time of day"));
        return -1;
    }
C
Chris Lalancette 已提交
10232 10233 10234

    qemuDriverLock(driver);
    if (!dom_xml) {
10235 10236
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
10237 10238 10239
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
10240
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
10241 10242 10243 10244
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
10245 10246
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
10247 10248 10249 10250
        goto cleanup;
    }

    /* Parse the domain XML. */
10251
    if (!(def = virDomainDefParseString(driver->caps, dom_xml,
C
Chris Lalancette 已提交
10252
                                        VIR_DOMAIN_XML_INACTIVE))) {
10253 10254
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
C
Chris Lalancette 已提交
10255 10256 10257 10258
        goto cleanup;
    }

    /* Target domain name, maybe renamed. */
10259 10260 10261 10262 10263 10264
    if (dname) {
        VIR_FREE(def->name);
        def->name = strdup(dname);
        if (def->name == NULL)
            goto cleanup;
    }
C
Chris Lalancette 已提交
10265

10266 10267
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
C
Chris Lalancette 已提交
10268

10269
    if (!(vm = virDomainAssignDef(driver->caps,
C
Chris Lalancette 已提交
10270
                                  &driver->domains,
10271
                                  def, true))) {
10272
        /* virDomainAssignDef already set the error */
C
Chris Lalancette 已提交
10273 10274 10275
        goto cleanup;
    }
    def = NULL;
10276
    priv = vm->privateData;
C
Chris Lalancette 已提交
10277

10278 10279
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
10280
    priv->jobActive = QEMU_JOB_MIGRATION_OUT;
10281

C
Chris Lalancette 已提交
10282 10283 10284 10285 10286
    /* 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) {
10287
        virReportOOMError();
10288
        goto endjob;
C
Chris Lalancette 已提交
10289 10290 10291 10292 10293
    }
    unlink(unixfile);

    /* check that this qemu version supports the interactive exec */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
10294 10295 10296
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot determine QEMU argv syntax %s"),
                        vm->def->emulator);
10297
        goto endjob;
C
Chris Lalancette 已提交
10298 10299 10300 10301 10302 10303
    }
    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 {
10304 10305
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("Destination qemu is too old to support tunnelled migration"));
10306
        goto endjob;
C
Chris Lalancette 已提交
10307 10308
    }
    if (internalret < 0) {
10309
        virReportOOMError();
10310
        goto endjob;
C
Chris Lalancette 已提交
10311 10312 10313 10314
    }
    /* Start the QEMU daemon, with the same command-line arguments plus
     * -incoming unix:/path/to/file or exec:nc -U /path/to/file
     */
10315 10316
    internalret = qemudStartVMDaemon(dconn, driver, vm, migrateFrom, true,
                                     -1, NULL);
C
Chris Lalancette 已提交
10317 10318 10319 10320 10321 10322 10323 10324 10325
    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;
        }
10326
        goto endjob;
C
Chris Lalancette 已提交
10327 10328 10329 10330
    }

    qemust = qemuStreamMigOpen(st, unixfile);
    if (qemust == NULL) {
10331
        qemudShutdownVMDaemon(driver, vm, 0);
10332
        if (!vm->persistent) {
10333 10334
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
10335 10336
            vm = NULL;
        }
10337
        virReportSystemError(errno,
C
Chris Lalancette 已提交
10338 10339
                             _("cannot open unix socket '%s' for tunnelled migration"),
                             unixfile);
10340
        goto endjob;
C
Chris Lalancette 已提交
10341 10342 10343 10344 10345 10346 10347 10348 10349 10350
    }

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

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

10351
endjob:
10352 10353 10354
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
10355

10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367
    /* We set a fake job active which is held across
     * API calls until the finish() call. This prevents
     * any other APIs being invoked while incoming
     * migration is taking place
     */
    if (vm &&
        virDomainObjIsActive(vm)) {
        priv->jobActive = QEMU_JOB_MIGRATION_IN;
        priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
        priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    }

C
Chris Lalancette 已提交
10368 10369
cleanup:
    virDomainDefFree(def);
10370 10371
    if (unixfile)
        unlink(unixfile);
C
Chris Lalancette 已提交
10372 10373 10374 10375 10376 10377 10378 10379 10380
    VIR_FREE(unixfile);
    if (vm)
        virDomainObjUnlock(vm);
    if (event)
        qemuDomainEventQueue(driver, event);
    qemuDriverUnlock(driver);
    return ret;
}

D
Daniel Veillard 已提交
10381 10382 10383 10384
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
10385
static int ATTRIBUTE_NONNULL (5)
D
Daniel Veillard 已提交
10386 10387 10388 10389 10390
qemudDomainMigratePrepare2 (virConnectPtr dconn,
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
10391
                            unsigned long flags,
D
Daniel Veillard 已提交
10392 10393 10394 10395 10396
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
    static int port = 0;
10397 10398
    struct qemud_driver *driver = dconn->privateData;
    virDomainDefPtr def = NULL;
D
Daniel Veillard 已提交
10399 10400
    virDomainObjPtr vm = NULL;
    int this_port;
C
Chris Lalancette 已提交
10401
    char *hostname = NULL;
D
Daniel Veillard 已提交
10402 10403
    char migrateFrom [64];
    const char *p;
10404
    virDomainEventPtr event = NULL;
10405
    int ret = -1;
10406
    int internalret;
10407 10408 10409 10410 10411 10412 10413 10414
    qemuDomainObjPrivatePtr priv = NULL;
    struct timeval now;

    if (gettimeofday(&now, NULL) < 0) {
        virReportSystemError(errno, "%s",
                             _("cannot get time of day"));
        return -1;
    }
10415

C
Chris Lalancette 已提交
10416 10417 10418 10419 10420 10421 10422 10423 10424
    virCheckFlags(VIR_MIGRATE_LIVE |
                  VIR_MIGRATE_PEER2PEER |
                  VIR_MIGRATE_TUNNELLED |
                  VIR_MIGRATE_PERSIST_DEST |
                  VIR_MIGRATE_UNDEFINE_SOURCE |
                  VIR_MIGRATE_PAUSED |
                  VIR_MIGRATE_NON_SHARED_DISK |
                  VIR_MIGRATE_NON_SHARED_INC, -1);

10425
    *uri_out = NULL;
D
Daniel Veillard 已提交
10426

10427
    qemuDriverLock(driver);
C
Chris Lalancette 已提交
10428 10429 10430 10431
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
10432 10433
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
10434 10435 10436
        goto cleanup;
    }

D
Daniel Veillard 已提交
10437
    if (!dom_xml) {
10438 10439
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
10440
        goto cleanup;
D
Daniel Veillard 已提交
10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457
    }

    /* 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 */
C
Chris Lalancette 已提交
10458
        if ((hostname = virGetHostname(NULL)) == NULL)
10459
            goto cleanup;
D
Daniel Veillard 已提交
10460

C
Chris Lalancette 已提交
10461 10462 10463 10464 10465 10466
        if (STRPREFIX(hostname, "localhost")) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("hostname on destination resolved to localhost, but migration requires an FQDN"));
            goto cleanup;
        }

10467 10468 10469 10470 10471
        /* 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 已提交
10472
        /* Caller frees */
10473 10474
        internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
        if (internalret < 0) {
10475
            virReportOOMError();
10476
            goto cleanup;
D
Daniel Veillard 已提交
10477 10478 10479 10480 10481 10482
        }
    } 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.
         */
10483
        if (!STRPREFIX (uri_in, "tcp:")) {
10484 10485
            qemuReportError (VIR_ERR_INVALID_ARG,
                             "%s", _("only tcp URIs are supported for KVM/QEMU migrations"));
10486
            goto cleanup;
D
Daniel Veillard 已提交
10487 10488 10489 10490
        }

        /* Get the port number. */
        p = strrchr (uri_in, ':');
10491 10492 10493 10494 10495 10496 10497 10498
        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) {
10499
                virReportOOMError();
10500 10501 10502 10503 10504 10505 10506
                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)) {
10507 10508
                qemuReportError(VIR_ERR_INVALID_ARG,
                                "%s", _("URI ended with incorrect ':port'"));
10509 10510
                goto cleanup;
            }
D
Daniel Veillard 已提交
10511 10512 10513
        }
    }

10514
    if (*uri_out)
10515 10516
        VIR_DEBUG("Generated uri_out=%s", *uri_out);

D
Daniel Veillard 已提交
10517
    /* Parse the domain XML. */
10518
    if (!(def = virDomainDefParseString(driver->caps, dom_xml,
10519
                                        VIR_DOMAIN_XML_INACTIVE))) {
10520 10521
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
10522
        goto cleanup;
D
Daniel Veillard 已提交
10523 10524 10525
    }

    /* Target domain name, maybe renamed. */
10526 10527 10528 10529 10530 10531
    if (dname) {
        VIR_FREE(def->name);
        def->name = strdup(dname);
        if (def->name == NULL)
            goto cleanup;
    }
D
Daniel Veillard 已提交
10532

10533 10534
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
10535

10536
    if (!(vm = virDomainAssignDef(driver->caps,
D
Daniel Veillard 已提交
10537
                                  &driver->domains,
10538
                                  def, true))) {
10539
        /* virDomainAssignDef already set the error */
10540
        goto cleanup;
D
Daniel Veillard 已提交
10541
    }
10542
    def = NULL;
10543
    priv = vm->privateData;
D
Daniel Veillard 已提交
10544

10545 10546
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
10547
    priv->jobActive = QEMU_JOB_MIGRATION_OUT;
10548

D
Daniel Veillard 已提交
10549 10550 10551 10552 10553 10554 10555
    /* 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);
10556 10557
    if (qemudStartVMDaemon (dconn, driver, vm, migrateFrom, true,
                            -1, NULL) < 0) {
10558 10559 10560
        /* Note that we don't set an error here because qemudStartVMDaemon
         * should have already done that.
         */
10561
        if (!vm->persistent) {
10562 10563
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
10564 10565
            vm = NULL;
        }
10566
        goto endjob;
D
Daniel Veillard 已提交
10567
    }
10568 10569 10570 10571

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

10574
endjob:
10575 10576 10577
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
10578

10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590
    /* We set a fake job active which is held across
     * API calls until the finish() call. This prevents
     * any other APIs being invoked while incoming
     * migration is taking place
     */
    if (vm &&
        virDomainObjIsActive(vm)) {
        priv->jobActive = QEMU_JOB_MIGRATION_IN;
        priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
        priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    }

10591
cleanup:
C
Chris Lalancette 已提交
10592
    VIR_FREE(hostname);
10593
    virDomainDefFree(def);
C
Chris Lalancette 已提交
10594
    if (ret != 0)
10595
        VIR_FREE(*uri_out);
10596 10597
    if (vm)
        virDomainObjUnlock(vm);
10598 10599
    if (event)
        qemuDomainEventQueue(driver, event);
10600
    qemuDriverUnlock(driver);
10601
    return ret;
C
Chris Lalancette 已提交
10602 10603 10604

}

10605 10606 10607 10608

/* Perform migration using QEMU's native TCP migrate support,
 * not encrypted obviously
 */
10609
static int doNativeMigrate(struct qemud_driver *driver,
10610 10611
                           virDomainObjPtr vm,
                           const char *uri,
10612
                           unsigned int flags,
10613 10614 10615 10616
                           const char *dname ATTRIBUTE_UNUSED,
                           unsigned long resource)
{
    int ret = -1;
10617
    xmlURIPtr uribits = NULL;
10618
    qemuDomainObjPrivatePtr priv = vm->privateData;
10619
    unsigned int background_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
10620

10621 10622 10623 10624 10625
    /* 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) {
10626
            virReportOOMError();
10627 10628 10629 10630 10631 10632 10633 10634
            goto cleanup;
        }
        uribits = xmlParseURI(tmpuri);
        VIR_FREE(tmpuri);
    } else {
        uribits = xmlParseURI(uri);
    }
    if (!uribits) {
10635 10636
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot parse URI %s"), uri);
10637 10638 10639
        goto cleanup;
    }

10640
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
10641
    if (resource > 0 &&
10642
        qemuMonitorSetMigrationSpeed(priv->mon, resource) < 0) {
10643
        qemuDomainObjExitMonitorWithDriver(driver, vm);
10644
        goto cleanup;
10645
    }
10646

10647 10648 10649 10650 10651 10652 10653 10654
    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) {
10655
        qemuDomainObjExitMonitorWithDriver(driver, vm);
10656 10657
        goto cleanup;
    }
10658
    qemuDomainObjExitMonitorWithDriver(driver, vm);
10659

10660
    if (qemuDomainWaitForMigrationComplete(driver, vm) < 0)
10661 10662 10663 10664 10665 10666 10667 10668 10669 10670
        goto cleanup;

    ret = 0;

cleanup:
    xmlFreeURI(uribits);
    return ret;
}


10671 10672
#define TUNNEL_SEND_BUF_SIZE 65536

10673
static int doTunnelSendAll(virStreamPtr st,
10674 10675
                           int sock)
{
10676 10677 10678 10679 10680 10681 10682 10683
    char *buffer;
    int nbytes = TUNNEL_SEND_BUF_SIZE;

    if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0) {
        virReportOOMError();
        virStreamAbort(st);
        return -1;
    }
10684 10685 10686 10687 10688

    /* XXX should honour the 'resource' parameter here */
    for (;;) {
        nbytes = saferead(sock, buffer, nbytes);
        if (nbytes < 0) {
10689
            virReportSystemError(errno, "%s",
10690
                                 _("tunnelled migration failed to read from qemu"));
10691 10692
            virStreamAbort(st);
            VIR_FREE(buffer);
10693 10694 10695 10696 10697 10698 10699
            return -1;
        }
        else if (nbytes == 0)
            /* EOF; get out of here */
            break;

        if (virStreamSend(st, buffer, nbytes) < 0) {
10700 10701
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("Failed to write migration data to remote libvirtd"));
10702
            VIR_FREE(buffer);
10703 10704 10705 10706
            return -1;
        }
    }

10707 10708
    VIR_FREE(buffer);

10709 10710 10711 10712 10713 10714 10715
    if (virStreamFinish(st) < 0)
        /* virStreamFinish set the error for us */
        return -1;

    return 0;
}

C
Chris Lalancette 已提交
10716
static int doTunnelMigrate(virDomainPtr dom,
10717
                           struct qemud_driver *driver,
10718
                           virConnectPtr dconn,
C
Chris Lalancette 已提交
10719
                           virDomainObjPtr vm,
10720
                           const char *dom_xml,
C
Chris Lalancette 已提交
10721 10722 10723 10724 10725
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
10726
    qemuDomainObjPrivatePtr priv = vm->privateData;
10727 10728
    int client_sock = -1;
    int qemu_sock = -1;
C
Chris Lalancette 已提交
10729 10730
    struct sockaddr_un sa_qemu, sa_client;
    socklen_t addrlen;
10731
    virDomainPtr ddomain = NULL;
C
Chris Lalancette 已提交
10732
    int retval = -1;
10733
    virStreamPtr st = NULL;
C
Chris Lalancette 已提交
10734 10735
    char *unixfile = NULL;
    int internalret;
10736
    unsigned long long qemuCmdFlags;
C
Chris Lalancette 已提交
10737 10738
    int status;
    unsigned long long transferred, remaining, total;
10739
    unsigned int background_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
C
Chris Lalancette 已提交
10740

10741 10742 10743 10744 10745 10746 10747 10748
    /*
     * 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 已提交
10749 10750
     */

10751

10752
    /* Stage 1. setup local support infrastructure */
C
Chris Lalancette 已提交
10753 10754 10755

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
                    driver->stateDir, vm->def->name) < 0) {
10756
        virReportOOMError();
10757
        goto cleanup;
C
Chris Lalancette 已提交
10758 10759 10760 10761
    }

    qemu_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (qemu_sock < 0) {
10762
        virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
10763
                             _("cannot open tunnelled migration socket"));
10764
        goto cleanup;
C
Chris Lalancette 已提交
10765 10766 10767 10768 10769
    }
    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) {
10770 10771 10772
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Unix socket '%s' too big for destination"),
                        unixfile);
10773
        goto cleanup;
C
Chris Lalancette 已提交
10774 10775 10776
    }
    unlink(unixfile);
    if (bind(qemu_sock, (struct sockaddr *)&sa_qemu, sizeof(sa_qemu)) < 0) {
10777
        virReportSystemError(errno,
C
Chris Lalancette 已提交
10778 10779
                             _("Cannot bind to unix socket '%s' for tunnelled migration"),
                             unixfile);
10780
        goto cleanup;
C
Chris Lalancette 已提交
10781 10782
    }
    if (listen(qemu_sock, 1) < 0) {
10783
        virReportSystemError(errno,
C
Chris Lalancette 已提交
10784 10785
                             _("Cannot listen on unix socket '%s' for tunnelled migration"),
                             unixfile);
10786
        goto cleanup;
C
Chris Lalancette 已提交
10787 10788 10789 10790
    }

    /* check that this qemu version supports the unix migration */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
10791 10792 10793
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot extract Qemu version from '%s'"),
                        vm->def->emulator);
10794 10795 10796 10797 10798
        goto cleanup;
    }

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX) &&
        !(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
10799 10800
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("Source qemu is too old to support tunnelled migration"));
10801
        goto cleanup;
C
Chris Lalancette 已提交
10802
    }
10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814


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

10815
    qemuDomainObjEnterRemoteWithDriver(driver, vm);
10816 10817 10818
    internalret = dconn->driver->domainMigratePrepareTunnel(dconn, st,
                                                            flags, dname,
                                                            resource, dom_xml);
10819
    qemuDomainObjExitRemoteWithDriver(driver, vm);
10820 10821 10822 10823 10824

    if (internalret < 0)
        /* domainMigratePrepareTunnel sets the error for us */
        goto cleanup;

10825 10826 10827 10828 10829 10830 10831 10832 10833
    /* the domain may have shutdown or crashed while we had the locks dropped
     * in qemuDomainObjEnterRemoteWithDriver, so check again
     */
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("guest unexpectedly quit"));
        goto cleanup;
    }

10834
    /*   3. start migration on source */
10835
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
10836 10837 10838 10839 10840 10841 10842 10843
    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 已提交
10844 10845
    else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
        const char *args[] = { "nc", "-U", unixfile, NULL };
10846
        internalret = qemuMonitorMigrateToCommand(priv->mon, QEMU_MONITOR_MIGRATE_BACKGROUND, args);
10847 10848
    } else {
        internalret = -1;
C
Chris Lalancette 已提交
10849
    }
10850
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
10851
    if (internalret < 0) {
10852 10853
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("tunnelled migration monitor command failed"));
10854
        goto finish;
C
Chris Lalancette 已提交
10855 10856
    }

10857 10858 10859 10860 10861 10862
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("guest unexpectedly quit"));
        goto cleanup;
    }

10863 10864 10865
    /* From this point onwards we *must* call cancel to abort the
     * migration on source if anything goes wrong */

C
Chris Lalancette 已提交
10866 10867 10868
    /* it is also possible that the migrate didn't fail initially, but
     * rather failed later on.  Check the output of "info migrate"
     */
10869
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
10870 10871
    if (qemuMonitorGetMigrationStatus(priv->mon,
                                      &status,
C
Chris Lalancette 已提交
10872 10873 10874
                                      &transferred,
                                      &remaining,
                                      &total) < 0) {
10875
        qemuDomainObjExitMonitorWithDriver(driver, vm);
10876
        goto cancel;
C
Chris Lalancette 已提交
10877
    }
10878
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
10879 10880

    if (status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
10881 10882
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s",_("migrate failed"));
10883
        goto cancel;
C
Chris Lalancette 已提交
10884 10885 10886 10887 10888 10889
    }

    addrlen = sizeof(sa_client);
    while ((client_sock = accept(qemu_sock, (struct sockaddr *)&sa_client, &addrlen)) < 0) {
        if (errno == EAGAIN || errno == EINTR)
            continue;
10890
        virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
10891
                             _("tunnelled migration failed to accept from qemu"));
10892
        goto cancel;
C
Chris Lalancette 已提交
10893 10894
    }

10895
    retval = doTunnelSendAll(st, client_sock);
10896

10897
cancel:
10898
    if (retval != 0 && virDomainObjIsActive(vm)) {
10899
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
10900
        qemuMonitorMigrateCancel(priv->mon);
10901
        qemuDomainObjExitMonitorWithDriver(driver, vm);
10902
    }
C
Chris Lalancette 已提交
10903

10904
finish:
C
Chris Lalancette 已提交
10905
    dname = dname ? dname : dom->name;
10906
    qemuDomainObjEnterRemoteWithDriver(driver, vm);
C
Chris Lalancette 已提交
10907 10908
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri, flags, retval);
10909
    qemuDomainObjExitRemoteWithDriver(driver, vm);
10910 10911 10912 10913 10914 10915 10916

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

C
Chris Lalancette 已提交
10917 10918 10919
    if (ddomain)
        virUnrefDomain(ddomain);

10920 10921 10922 10923
    if (unixfile) {
        unlink(unixfile);
        VIR_FREE(unixfile);
    }
C
Chris Lalancette 已提交
10924

10925 10926 10927
    if (st)
        /* don't call virStreamFree(), because that resets any pending errors */
        virUnrefStream(st);
10928 10929 10930 10931
    return retval;
}


10932 10933 10934 10935
/* 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,
10936
                              struct qemud_driver *driver,
10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947
                              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;
10948
    int rc;
10949

10950
    qemuDomainObjEnterRemoteWithDriver(driver, vm);
10951 10952
    /* NB we don't pass 'uri' into this, since that's the libvirtd
     * URI in this context - so we let dest pick it */
10953 10954 10955 10956 10957 10958 10959 10960 10961
    rc = dconn->driver->domainMigratePrepare2(dconn,
                                              NULL, /* cookie */
                                              0, /* cookielen */
                                              NULL, /* uri */
                                              &uri_out,
                                              flags, dname,
                                              resource, dom_xml);
    qemuDomainObjExitRemoteWithDriver(driver, vm);
    if (rc < 0)
10962 10963 10964
        /* domainMigratePrepare2 sets the error for us */
        goto cleanup;

10965 10966 10967 10968 10969 10970 10971 10972 10973
    /* the domain may have shutdown or crashed while we had the locks dropped
     * in qemuDomainObjEnterRemoteWithDriver, so check again
     */
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("guest unexpectedly quit"));
        goto cleanup;
    }

10974
    if (uri_out == NULL) {
10975 10976
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("domainMigratePrepare2 did not set uri"));
10977
        goto cleanup;
10978 10979
    }

10980
    if (doNativeMigrate(driver, vm, uri_out, flags, dname, resource) < 0)
10981 10982 10983 10984 10985 10986
        goto finish;

    retval = 0;

finish:
    dname = dname ? dname : dom->name;
10987
    qemuDomainObjEnterRemoteWithDriver(driver, vm);
10988 10989
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri_out, flags, retval);
10990
    qemuDomainObjExitRemoteWithDriver(driver, vm);
10991 10992 10993 10994 10995 10996 10997 10998 10999

    if (ddomain)
        virUnrefDomain(ddomain);

cleanup:
    return retval;
}


11000
static int doPeer2PeerMigrate(virDomainPtr dom,
11001
                              struct qemud_driver *driver,
11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017
                              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) {
11018 11019
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("Failed to connect to remote libvirt URI %s"), uri);
11020 11021 11022
        return -1;
    }
    if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
11023
                                  VIR_DRV_FEATURE_MIGRATION_P2P)) {
11024 11025
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("Destination libvirt does not support peer-to-peer migration protocol"));
11026 11027 11028
        goto cleanup;
    }

11029 11030 11031
    dom_xml = qemudVMDumpXML(driver, vm,
                             VIR_DOMAIN_XML_SECURE |
                             VIR_DOMAIN_XML_UPDATE_CPU);
11032
    if (!dom_xml) {
11033 11034
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
11035 11036 11037
        goto cleanup;
    }

11038
    if (flags & VIR_MIGRATE_TUNNELLED)
11039
        ret = doTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
11040
    else
11041
        ret = doNonTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
11042 11043 11044

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

11048
    return ret;
D
Daniel Veillard 已提交
11049 11050
}

11051

D
Daniel Veillard 已提交
11052 11053 11054 11055 11056 11057
/* 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,
11058
                           unsigned long flags,
11059
                           const char *dname,
D
Daniel Veillard 已提交
11060 11061
                           unsigned long resource)
{
11062 11063
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
11064
    virDomainEventPtr event = NULL;
11065
    int ret = -1;
11066
    int resume = 0;
11067
    qemuDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
11068

C
Chris Lalancette 已提交
11069 11070 11071 11072 11073 11074 11075 11076 11077
    virCheckFlags(VIR_MIGRATE_LIVE |
                  VIR_MIGRATE_PEER2PEER |
                  VIR_MIGRATE_TUNNELLED |
                  VIR_MIGRATE_PERSIST_DEST |
                  VIR_MIGRATE_UNDEFINE_SOURCE |
                  VIR_MIGRATE_PAUSED |
                  VIR_MIGRATE_NON_SHARED_DISK |
                  VIR_MIGRATE_NON_SHARED_INC, -1);

11078
    qemuDriverLock(driver);
11079
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
11080
    if (!vm) {
11081 11082
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
11083 11084
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
11085
        goto cleanup;
D
Daniel Veillard 已提交
11086
    }
11087
    priv = vm->privateData;
D
Daniel Veillard 已提交
11088

11089 11090
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
11091
    priv->jobActive = QEMU_JOB_MIGRATION_OUT;
11092

D
Daniel P. Berrange 已提交
11093
    if (!virDomainObjIsActive(vm)) {
11094 11095
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
11096
        goto endjob;
D
Daniel Veillard 已提交
11097 11098
    }

11099 11100 11101
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

11102
    resume = vm->state == VIR_DOMAIN_RUNNING;
11103
    if (!(flags & VIR_MIGRATE_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
11104
        if (qemuDomainMigrateOffline(driver, vm) < 0)
11105
            goto endjob;
11106 11107
    }

11108
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
11109
        if (doPeer2PeerMigrate(dom, driver, vm, uri, flags, dname, resource) < 0)
11110
            /* doPeer2PeerMigrate already set the error, so just get out */
11111
            goto endjob;
11112
    } else {
11113
        if (doNativeMigrate(driver, vm, uri, flags, dname, resource) < 0)
11114
            goto endjob;
11115 11116
    }

D
Daniel Veillard 已提交
11117
    /* Clean up the source domain. */
11118
    qemudShutdownVMDaemon(driver, vm, 1);
11119
    resume = 0;
11120 11121 11122 11123

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
C
Chris Lalancette 已提交
11124
    if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
11125
        virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm);
11126 11127
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains, vm);
11128 11129
        vm = NULL;
    }
11130
    ret = 0;
D
Daniel Veillard 已提交
11131

11132
endjob:
11133
    if (resume && vm->state == VIR_DOMAIN_PAUSED) {
11134
        /* we got here through some sort of failure; start the domain again */
11135
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
11136
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
11137 11138 11139 11140
            /* 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
             */
11141
            VIR_ERROR(_("Failed to resume guest %s after failure"),
11142
                      vm->def->name);
11143
        }
11144
        qemuDomainObjExitMonitorWithDriver(driver, vm);
11145

11146
        vm->state = VIR_DOMAIN_RUNNING;
11147 11148 11149 11150
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }
11151 11152 11153
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
11154

11155
cleanup:
11156 11157
    if (vm)
        virDomainObjUnlock(vm);
11158 11159
    if (event)
        qemuDomainEventQueue(driver, event);
11160
    qemuDriverUnlock(driver);
11161
    return ret;
D
Daniel Veillard 已提交
11162 11163 11164 11165 11166 11167 11168 11169 11170
}

/* 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 已提交
11171
                           unsigned long flags,
D
Daniel Veillard 已提交
11172 11173
                           int retcode)
{
11174 11175 11176
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
11177
    virDomainEventPtr event = NULL;
11178
    virErrorPtr orig_err;
C
Chris Lalancette 已提交
11179
    int newVM = 1;
11180
    qemuDomainObjPrivatePtr priv = NULL;
D
Daniel Veillard 已提交
11181

C
Chris Lalancette 已提交
11182 11183 11184 11185 11186 11187 11188 11189 11190
    virCheckFlags(VIR_MIGRATE_LIVE |
                  VIR_MIGRATE_PEER2PEER |
                  VIR_MIGRATE_TUNNELLED |
                  VIR_MIGRATE_PERSIST_DEST |
                  VIR_MIGRATE_UNDEFINE_SOURCE |
                  VIR_MIGRATE_PAUSED |
                  VIR_MIGRATE_NON_SHARED_DISK |
                  VIR_MIGRATE_NON_SHARED_INC, NULL);

11191 11192 11193
    /* Migration failed. Save the current error so nothing squashes it */
    orig_err = virSaveLastError();

11194
    qemuDriverLock(driver);
11195
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
11196
    if (!vm) {
11197 11198
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
11199
        goto cleanup;
D
Daniel Veillard 已提交
11200 11201
    }

11202 11203 11204 11205 11206 11207 11208 11209 11210
    priv = vm->privateData;
    if (priv->jobActive != QEMU_JOB_MIGRATION_IN) {
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("domain '%s' is not processing incoming migration"), dname);
        goto cleanup;
    }
    priv->jobActive = QEMU_JOB_NONE;
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));

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

D
Daniel Veillard 已提交
11214 11215 11216 11217
    /* Did the migration go as planned?  If yes, return the domain
     * object, but if no, clean up the empty qemu process.
     */
    if (retcode == 0) {
11218 11219 11220 11221 11222 11223
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto cleanup;
        }

C
Chris Lalancette 已提交
11224 11225 11226 11227 11228
        if (flags & VIR_MIGRATE_PERSIST_DEST) {
            if (vm->persistent)
                newVM = 0;
            vm->persistent = 1;

11229
            if (virDomainSaveConfig(driver->configDir, vm->def) < 0) {
C
Chris Lalancette 已提交
11230 11231 11232 11233 11234 11235 11236 11237 11238 11239
                /* 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;
11240
                goto endjob;
C
Chris Lalancette 已提交
11241 11242 11243 11244 11245 11246 11247 11248 11249
            }

            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_DEFINED,
                                             newVM ?
                                             VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                             VIR_DOMAIN_EVENT_DEFINED_UPDATED);
            if (event)
                qemuDomainEventQueue(driver, event);
11250
            event = NULL;
C
Chris Lalancette 已提交
11251 11252

        }
D
Daniel Veillard 已提交
11253
        dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
11254

11255 11256 11257 11258 11259 11260 11261 11262
        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)
11263 11264
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("resume operation failed"));
11265 11266 11267
                qemuDomainObjExitMonitorWithDriver(driver, vm);
                goto endjob;
            }
11268
            qemuDomainObjExitMonitorWithDriver(driver, vm);
11269 11270

            vm->state = VIR_DOMAIN_RUNNING;
11271 11272
        }

11273 11274 11275
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
11276 11277 11278 11279 11280 11281
        if (vm->state == VIR_DOMAIN_PAUSED) {
            qemuDomainEventQueue(driver, event);
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
        }
11282 11283 11284 11285
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
            goto endjob;
        }
D
Daniel Veillard 已提交
11286
    } else {
11287
        qemudShutdownVMDaemon(driver, vm, 1);
11288 11289 11290
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
11291
        if (!vm->persistent) {
11292 11293
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
11294 11295
            vm = NULL;
        }
D
Daniel Veillard 已提交
11296
    }
11297

11298
endjob:
11299 11300 11301
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
11302

11303
cleanup:
11304 11305 11306 11307
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
11308 11309
    if (vm)
        virDomainObjUnlock(vm);
11310 11311
    if (event)
        qemuDomainEventQueue(driver, event);
11312
    qemuDriverUnlock(driver);
11313
    return dom;
D
Daniel Veillard 已提交
11314 11315
}

11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331
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;

11332
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE);
11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349
    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) {
11350 11351
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("device %s is not a PCI device"), dev->name);
11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
qemudNodeDeviceDettach (virNodeDevicePtr dev)
{
11365
    struct qemud_driver *driver = dev->conn->privateData;
11366 11367 11368 11369 11370 11371 11372
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

11373
    pci = pciGetDevice(domain, bus, slot, function);
11374 11375 11376
    if (!pci)
        return -1;

11377 11378
    qemuDriverLock(driver);
    if (pciDettachDevice(pci, driver->activePciHostdevs) < 0)
11379 11380 11381 11382
        goto out;

    ret = 0;
out:
11383
    qemuDriverUnlock(driver);
11384
    pciFreeDevice(pci);
11385 11386 11387 11388 11389 11390
    return ret;
}

static int
qemudNodeDeviceReAttach (virNodeDevicePtr dev)
{
11391
    struct qemud_driver *driver = dev->conn->privateData;
11392 11393 11394 11395 11396 11397 11398
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

11399
    pci = pciGetDevice(domain, bus, slot, function);
11400 11401 11402
    if (!pci)
        return -1;

11403 11404
    qemuDriverLock(driver);
    if (pciReAttachDevice(pci, driver->activePciHostdevs) < 0)
11405 11406 11407 11408
        goto out;

    ret = 0;
out:
11409
    qemuDriverUnlock(driver);
11410
    pciFreeDevice(pci);
11411 11412 11413 11414 11415 11416
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
11417
    struct qemud_driver *driver = dev->conn->privateData;
11418 11419 11420 11421 11422 11423 11424
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

11425
    pci = pciGetDevice(domain, bus, slot, function);
11426 11427 11428
    if (!pci)
        return -1;

11429 11430
    qemuDriverLock(driver);

11431
    if (pciResetDevice(pci, driver->activePciHostdevs) < 0)
11432 11433 11434 11435
        goto out;

    ret = 0;
out:
11436
    qemuDriverUnlock(driver);
11437
    pciFreeDevice(pci);
11438 11439 11440
    return ret;
}

11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451
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) {
11452 11453
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cannot get host CPU capabilities"));
11454 11455
    }
    else
11456
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
11457 11458 11459 11460 11461 11462

    qemuDriverUnlock(driver);

    return ret;
}

11463

11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476
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;
}

11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499

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) {
11500 11501
            struct timeval now;

11502
            memcpy(info, &priv->jobInfo, sizeof(*info));
11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516

            /* Refresh elapsed time again just to ensure it
             * is fully updated. This is primarily for benefit
             * of incoming migration which we don't currently
             * monitor actively in the background thread
             */
            if (gettimeofday(&now, NULL) < 0) {
                virReportSystemError(errno, "%s",
                                     _("cannot get time of day"));
                goto cleanup;
            }
            info->timeElapsed =
                ((now.tv_sec * 1000ull) + (now.tv_usec / 1000)) -
                priv->jobStart;
11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535
        } 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;
}


11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557
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);
11558
            priv->jobSignals |= QEMU_JOB_SIGNAL_CANCEL;
11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578
        } 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;
}


11579 11580 11581 11582 11583 11584 11585 11586 11587 11588
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;

11589
    virCheckFlags(0, -1);
11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609

    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;

11610
    if (priv->jobActive != QEMU_JOB_MIGRATION_OUT) {
11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627
        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 已提交
11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736
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,
11737 11738
                            _("Disk '%s' does not support snapshotting"),
                            vm->def->disks[i]->src);
C
Chris Lalancette 已提交
11739 11740 11741 11742 11743 11744 11745 11746 11747
            return 0;
        }
    }

    return 1;
}

static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
                                                        const char *xmlDesc,
11748
                                                        unsigned int flags)
C
Chris Lalancette 已提交
11749 11750 11751 11752 11753 11754 11755 11756 11757 11758
{
    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;

11759 11760
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821
    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 {
11822 11823 11824 11825 11826
        qemuDomainObjPrivatePtr priv;
        int ret;

        if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
            goto cleanup;
C
Chris Lalancette 已提交
11827 11828
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
11829
        ret = qemuMonitorCreateSnapshot(priv->mon, def->name);
C
Chris Lalancette 已提交
11830
        qemuDomainObjExitMonitorWithDriver(driver, vm);
11831
        if (qemuDomainObjEndJob(vm) == 0) {
11832
            vm = NULL;
11833 11834
            goto cleanup;
        }
11835 11836
        if (ret < 0)
            goto cleanup;
C
Chris Lalancette 已提交
11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872
    }

    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,
11873
                                       unsigned int flags)
C
Chris Lalancette 已提交
11874 11875 11876 11877 11878
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

11879 11880
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895 11896 11897 11898 11899 11900
    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,
11901
                                 unsigned int flags)
C
Chris Lalancette 已提交
11902 11903 11904 11905 11906
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

11907 11908
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920 11921 11922 11923 11924 11925 11926 11927 11928 11929
    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,
11930
                                                           unsigned int flags)
C
Chris Lalancette 已提交
11931 11932 11933 11934 11935 11936
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

11937 11938
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964 11965
    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,
11966
                                        unsigned int flags)
C
Chris Lalancette 已提交
11967 11968 11969 11970 11971
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

11972 11973
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
11974 11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990 11991 11992 11993
    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,
11994
                                                      unsigned int flags)
C
Chris Lalancette 已提交
11995 11996 11997 11998 11999
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

12000 12001
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
12002 12003 12004 12005 12006 12007 12008 12009 12010 12011 12012 12013 12014 12015 12016 12017 12018 12019 12020 12021 12022 12023 12024 12025 12026 12027
    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,
12028
                                       unsigned int flags)
C
Chris Lalancette 已提交
12029 12030 12031 12032 12033 12034 12035
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

12036 12037
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
12038 12039 12040 12041 12042 12043 12044 12045 12046 12047 12048 12049 12050 12051 12052 12053 12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064
    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,
12065
                                      unsigned int flags)
C
Chris Lalancette 已提交
12066 12067 12068 12069 12070 12071 12072 12073 12074 12075
{
    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;

12076 12077
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
12078 12079 12080 12081 12082 12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108
    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)
12109
                goto endjob;
C
Chris Lalancette 已提交
12110 12111 12112
        }
        else {
            if (qemuDomainSnapshotSetActive(vm, driver->snapshotDir) < 0)
12113
                goto endjob;
C
Chris Lalancette 已提交
12114 12115

            rc = qemudStartVMDaemon(snapshot->domain->conn, driver, vm, NULL,
12116
                                    false, -1, NULL);
C
Chris Lalancette 已提交
12117
            if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
12118
                goto endjob;
C
Chris Lalancette 已提交
12119
            if (rc < 0)
12120
                goto endjob;
C
Chris Lalancette 已提交
12121 12122 12123 12124 12125 12126
        }

        if (snap->def->state == VIR_DOMAIN_PAUSED) {
            /* qemu unconditionally starts the domain running again after
             * loadvm, so let's pause it to keep consistency
             */
12127
            int state = vm->state;
C
Chris Lalancette 已提交
12128
            priv = vm->privateData;
12129
            vm->state = VIR_DOMAIN_PAUSED;
C
Chris Lalancette 已提交
12130 12131 12132
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorStopCPUs(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
12133 12134
            if (rc < 0) {
                vm->state = state;
12135
                goto endjob;
12136
            }
C
Chris Lalancette 已提交
12137 12138 12139 12140 12141 12142 12143 12144 12145 12146 12147 12148 12149 12150 12151 12152 12153 12154
        }

        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)) {
12155
            qemudShutdownVMDaemon(driver, vm, 0);
C
Chris Lalancette 已提交
12156 12157 12158
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
                                             VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
12159 12160 12161 12162
            if (!vm->persistent) {
                if (qemuDomainObjEndJob(vm) > 0)
                    virDomainRemoveInactive(&driver->domains, vm);
                vm = NULL;
12163
                goto cleanup;
12164
            }
C
Chris Lalancette 已提交
12165 12166 12167
        }

        if (qemuDomainSnapshotSetActive(vm, driver->snapshotDir) < 0)
12168
            goto endjob;
C
Chris Lalancette 已提交
12169 12170 12171 12172 12173 12174
    }

    vm->state = snap->def->state;

    ret = 0;

12175
endjob:
C
Chris Lalancette 已提交
12176 12177 12178
    if (vm && qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

12179
cleanup:
C
Chris Lalancette 已提交
12180 12181 12182 12183 12184 12185 12186 12187 12188 12189 12190 12191 12192 12193 12194 12195 12196 12197 12198 12199 12200 12201 12202 12203 12204 12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313
    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;

12314 12315
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);

C
Chris Lalancette 已提交
12316 12317 12318 12319 12320 12321 12322 12323 12324 12325 12326 12327 12328 12329 12330 12331 12332
    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;
    }

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

C
Chris Lalancette 已提交
12336 12337 12338 12339 12340 12341 12342 12343
    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)
12344
            goto endjob;
C
Chris Lalancette 已提交
12345 12346 12347 12348
    }

    ret = qemuDomainSnapshotDiscard(driver, vm, snap);

12349 12350 12351 12352
endjob:
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

C
Chris Lalancette 已提交
12353 12354 12355 12356 12357 12358
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
12359

12360 12361 12362 12363 12364
static virDriver qemuDriver = {
    VIR_DRV_QEMU,
    "QEMU",
    qemudOpen, /* open */
    qemudClose, /* close */
D
Daniel Veillard 已提交
12365
    qemudSupportsFeature, /* supports_feature */
12366 12367
    qemudGetType, /* type */
    qemudGetVersion, /* version */
12368
    NULL, /* libvirtVersion (impl. in libvirt.c) */
12369
    virGetHostname, /* getHostname */
12370
    qemudGetMaxVCPUs, /* getMaxVcpus */
12371
    nodeGetInfo, /* nodeGetInfo */
12372 12373 12374
    qemudGetCapabilities, /* getCapabilities */
    qemudListDomains, /* listDomains */
    qemudNumDomains, /* numOfDomains */
12375
    qemudDomainCreate, /* domainCreateXML */
12376 12377 12378 12379 12380
    qemudDomainLookupByID, /* domainLookupByID */
    qemudDomainLookupByUUID, /* domainLookupByUUID */
    qemudDomainLookupByName, /* domainLookupByName */
    qemudDomainSuspend, /* domainSuspend */
    qemudDomainResume, /* domainResume */
12381
    qemudDomainShutdown, /* domainShutdown */
12382 12383 12384
    NULL, /* domainReboot */
    qemudDomainDestroy, /* domainDestroy */
    qemudDomainGetOSType, /* domainGetOSType */
12385
    qemudDomainGetMaxMemory, /* domainGetMaxMemory */
12386
    NULL, /* domainSetMaxMemory */
12387
    qemudDomainSetMemory, /* domainSetMemory */
12388 12389 12390
    qemudDomainGetInfo, /* domainGetInfo */
    qemudDomainSave, /* domainSave */
    qemudDomainRestore, /* domainRestore */
P
Paolo Bonzini 已提交
12391
    qemudDomainCoreDump, /* domainCoreDump */
12392
    qemudDomainSetVcpus, /* domainSetVcpus */
12393 12394
    qemudDomainPinVcpu, /* domainPinVcpu */
    qemudDomainGetVcpus, /* domainGetVcpus */
12395
    qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
12396 12397
    qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
    qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
12398
    qemudDomainDumpXML, /* domainDumpXML */
12399
    qemuDomainXMLFromNative, /* domainXmlFromNative */
12400
    qemuDomainXMLToNative, /* domainXMLToNative */
12401 12402
    qemudListDefinedDomains, /* listDefinedDomains */
    qemudNumDefinedDomains, /* numOfDefinedDomains */
12403
    qemudDomainStart, /* domainCreate */
12404
    qemudDomainStartWithFlags, /* domainCreateWithFlags */
12405 12406
    qemudDomainDefine, /* domainDefineXML */
    qemudDomainUndefine, /* domainUndefine */
12407
    qemudDomainAttachDevice, /* domainAttachDevice */
12408
    qemudDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
12409
    qemudDomainDetachDevice, /* domainDetachDevice */
12410
    qemudDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
12411
    qemuDomainUpdateDeviceFlags, /* domainUpdateDeviceFlags */
12412 12413
    qemudDomainGetAutostart, /* domainGetAutostart */
    qemudDomainSetAutostart, /* domainSetAutostart */
12414 12415 12416
    qemuGetSchedulerType, /* domainGetSchedulerType */
    qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
    qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
12417 12418
    NULL, /* domainMigratePrepare (v1) */
    qemudDomainMigratePerform, /* domainMigratePerform */
12419
    NULL, /* domainMigrateFinish */
12420
    qemudDomainBlockStats, /* domainBlockStats */
12421
    qemudDomainInterfaceStats, /* domainInterfaceStats */
12422
    qemudDomainMemoryStats, /* domainMemoryStats */
12423
    qemudDomainBlockPeek, /* domainBlockPeek */
R
Richard W.M. Jones 已提交
12424
    qemudDomainMemoryPeek, /* domainMemoryPeek */
12425
    qemuDomainGetBlockInfo, /* domainGetBlockInfo */
12426 12427
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
12428 12429
    qemuDomainEventRegister, /* domainEventRegister */
    qemuDomainEventDeregister, /* domainEventDeregister */
D
Daniel Veillard 已提交
12430 12431
    qemudDomainMigratePrepare2, /* domainMigratePrepare2 */
    qemudDomainMigrateFinish2, /* domainMigrateFinish2 */
12432 12433 12434
    qemudNodeDeviceDettach, /* nodeDeviceDettach */
    qemudNodeDeviceReAttach, /* nodeDeviceReAttach */
    qemudNodeDeviceReset, /* nodeDeviceReset */
C
Chris Lalancette 已提交
12435
    qemudDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
12436 12437 12438 12439
    qemuIsEncrypted, /* isEncrypted */
    qemuIsSecure, /* isSecure */
    qemuDomainIsActive, /* domainIsActive */
    qemuDomainIsPersistent, /* domainIsPersistent */
12440
    qemuCPUCompare, /* cpuCompare */
12441
    qemuCPUBaseline, /* cpuBaseline */
12442
    qemuDomainGetJobInfo, /* domainGetJobInfo */
12443
    qemuDomainAbortJob, /* domainAbortJob */
12444
    qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
12445 12446
    qemuDomainEventRegisterAny, /* domainEventRegisterAny */
    qemuDomainEventDeregisterAny, /* domainEventDeregisterAny */
12447 12448 12449
    qemuDomainManagedSave, /* domainManagedSave */
    qemuDomainHasManagedSaveImage, /* domainHasManagedSaveImage */
    qemuDomainManagedSaveRemove, /* domainManagedSaveRemove */
C
Chris Lalancette 已提交
12450 12451 12452 12453 12454 12455 12456 12457 12458
    qemuDomainSnapshotCreateXML, /* domainSnapshotCreateXML */
    qemuDomainSnapshotDumpXML, /* domainSnapshotDumpXML */
    qemuDomainSnapshotNum, /* domainSnapshotNum */
    qemuDomainSnapshotListNames, /* domainSnapshotListNames */
    qemuDomainSnapshotLookupByName, /* domainSnapshotLookupByName */
    qemuDomainHasCurrentSnapshot, /* domainHasCurrentSnapshot */
    qemuDomainSnapshotCurrent, /* domainSnapshotCurrent */
    qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */
    qemuDomainSnapshotDelete, /* domainSnapshotDelete */
12459 12460 12461
};


12462
static virStateDriver qemuStateDriver = {
12463
    .name = "QEMU",
12464 12465 12466 12467
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
12468
};
12469

S
Stefan Berger 已提交
12470
static int
12471
qemudVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
S
Stefan Berger 已提交
12472 12473
                     virHashIterator iter, void *data)
{
12474 12475 12476
    struct qemud_driver *driver = qemu_driver;

    qemuDriverLock(driver);
S
Stefan Berger 已提交
12477
    virHashForEach(qemu_driver->domains.objs, iter, data);
12478 12479
    qemuDriverUnlock(driver);

S
Stefan Berger 已提交
12480 12481 12482 12483 12484 12485 12486 12487 12488
    return 0;
}


static virNWFilterCallbackDriver qemuCallbackDriver = {
    .name = "QEMU",
    .vmFilterRebuild = qemudVMFilterRebuild,
};

12489
int qemuRegister(void) {
12490 12491
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
S
Stefan Berger 已提交
12492
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
12493 12494
    return 0;
}