qemu_driver.c 413.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
#include <pwd.h>
44
#include <grp.h>
45
#include <stdio.h>
46
#include <sys/wait.h>
47
#include <sys/ioctl.h>
48
#include <sys/un.h>
D
Daniel P. Berrange 已提交
49

50 51
#include <libxml/xpathInternals.h>

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

89 90
#define VIR_FROM_THIS VIR_FROM_QEMU

91 92 93
#define QEMU_VNC_PORT_MIN  5900
#define QEMU_VNC_PORT_MAX  65535

94 95
#define QEMU_NB_MEM_PARAM  3

96 97
#define QEMU_NAMESPACE_HREF "http://libvirt.org/schemas/domain/qemu/1.0"

98 99 100 101 102 103
/* Only 1 job is allowed at any time
 * A job includes *all* monitor commands, even those just querying
 * information, not merely actions */
enum qemuDomainJob {
    QEMU_JOB_NONE = 0,  /* Always set to 0 for easy if (jobActive) conditions */
    QEMU_JOB_UNSPECIFIED,
104 105
    QEMU_JOB_MIGRATION_OUT,
    QEMU_JOB_MIGRATION_IN,
106 107 108 109 110
};

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 */
111 112 113 114 115
    QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME = 1 << 2, /* Request migration downtime change */
};

struct qemuDomainJobSignalsData {
    unsigned long long migrateDowntime; /* Data for QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME */
116 117
};

118 119 120
typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate;
typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr;
struct _qemuDomainObjPrivate {
121
    virCond jobCond; /* Use in conjunction with main virDomainObjPtr lock */
122 123
    enum qemuDomainJob jobActive;   /* Currently running job */
    unsigned int jobSignals;        /* Signals for running job */
124
    struct qemuDomainJobSignalsData jobSignalsData; /* Signal specific data */
125 126
    virDomainJobInfo jobInfo;
    unsigned long long jobStart;
127

128
    qemuMonitorPtr mon;
129
    virDomainChrDefPtr monConfig;
D
Daniel P. Berrange 已提交
130
    int monJSON;
131
    int monitor_warned;
132 133 134

    int nvcpupids;
    int *vcpupids;
135 136

    qemuDomainPCIAddressSetPtr pciaddrs;
137
    int persistentAddrs;
138 139
};

140 141
static int qemudShutdown(void);

142 143
static void qemuDriverLock(struct qemud_driver *driver)
{
144
    virMutexLock(&driver->lock);
145 146 147
}
static void qemuDriverUnlock(struct qemud_driver *driver)
{
148
    virMutexUnlock(&driver->lock);
149 150
}

151 152 153
static void qemuDomainEventFlush(int timer, void *opaque);
static void qemuDomainEventQueue(struct qemud_driver *driver,
                                 virDomainEventPtr event);
154

J
Jiri Denemark 已提交
155 156
static int qemudDomainObjStart(virConnectPtr conn,
                               struct qemud_driver *driver,
157 158
                               virDomainObjPtr vm,
                               bool start_paused);
J
Jiri Denemark 已提交
159

160 161
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
162
                              virDomainObjPtr vm,
163
                              const char *migrateFrom,
164
                              bool start_paused,
165 166
                              int stdin_fd,
                              const char *stdin_path);
167

168
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
169 170
                                  virDomainObjPtr vm,
                                  int migrated);
171

172 173 174
static void qemuDomainStartAudit(virDomainObjPtr vm, const char *reason, bool success);
static void qemuDomainStopAudit(virDomainObjPtr vm, const char *reason);

175
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
176

177
static int qemuDetectVcpuPIDs(struct qemud_driver *driver,
178
                              virDomainObjPtr vm);
179

180 181 182
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                                       virDomainDefPtr def);

183 184 185
static int qemudVMFiltersInstantiate(virConnectPtr conn,
                                     virDomainDefPtr def);

J
Jim Meyering 已提交
186
static struct qemud_driver *qemu_driver = NULL;
187

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

static void *qemuDomainObjPrivateAlloc(void)
{
    qemuDomainObjPrivatePtr priv;

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

    return priv;
}

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

203
    qemuDomainPCIAddressSetFree(priv->pciaddrs);
204 205 206
    virDomainChrDefFree(priv->monConfig);
    VIR_FREE(priv->vcpupids);

207 208
    /* This should never be non-NULL if we get here, but just in case... */
    if (priv->mon) {
209
        VIR_ERROR0(_("Unexpected QEMU monitor still active during domain deletion"));
210 211 212 213 214 215
        qemuMonitorClose(priv->mon);
    }
    VIR_FREE(priv);
}


216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
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 已提交
234 235
        if (priv->monJSON)
            virBufferAddLit(buf, " json='1'");
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
        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) {
262
        virReportOOMError();
263 264 265
        goto error;
    }

266
    if (!(priv->monConfig->info.alias = strdup("monitor"))) {
267
        virReportOOMError();
268 269 270
        goto error;
    }

271
    if (!(monitorpath =
272
          virXPathString("string(./monitor[1]/@path)", ctxt))) {
273 274
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no monitor path"));
275 276 277
        goto error;
    }

278
    tmp = virXPathString("string(./monitor[1]/@type)", ctxt);
279 280 281 282 283 284
    if (tmp)
        priv->monConfig->type = virDomainChrTypeFromString(tmp);
    else
        priv->monConfig->type = VIR_DOMAIN_CHR_TYPE_PTY;
    VIR_FREE(tmp);

285
    if (virXPathBoolean("count(./monitor[@json = '1']) > 0", ctxt)) {
D
Daniel P. Berrange 已提交
286
        priv->monJSON = 1;
287 288 289
    } else {
        priv->monJSON = 0;
    }
D
Daniel P. Berrange 已提交
290

291 292 293 294 295 296 297 298 299
    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);
300 301 302
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unsupported monitor type '%s'"),
                        virDomainChrTypeToString(priv->monConfig->type));
303 304 305
        goto error;
    }

306
    n = virXPathNodeSet("./vcpus/vcpu", ctxt, &nodes);
307 308 309 310 311
    if (n < 0)
        goto error;
    if (n) {
        priv->nvcpupids = n;
        if (VIR_REALLOC_N(priv->vcpupids, priv->nvcpupids) < 0) {
312
            virReportOOMError();
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
            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:
333 334
    virDomainChrDefFree(priv->monConfig);
    priv->monConfig = NULL;
335 336 337 338 339 340
    VIR_FREE(nodes);
    return -1;
}



341 342 343 344 345 346 347 348 349
/*
 * 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
 */
350 351 352 353

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

354 355 356 357
static int qemuDomainObjBeginJob(virDomainObjPtr obj) ATTRIBUTE_RETURN_CHECK;
static int qemuDomainObjBeginJob(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;
358 359 360 361
    struct timeval now;
    unsigned long long then;

    if (gettimeofday(&now, NULL) < 0) {
362
        virReportSystemError(errno, "%s",
363 364 365 366 367
                             _("cannot get time of day"));
        return -1;
    }
    then = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    then += QEMU_JOB_WAIT_TIME;
368 369 370 371

    virDomainObjRef(obj);

    while (priv->jobActive) {
372
        if (virCondWaitUntil(&priv->jobCond, &obj->lock, then) < 0) {
373
            virDomainObjUnref(obj);
374
            if (errno == ETIMEDOUT)
375 376
                qemuReportError(VIR_ERR_OPERATION_TIMEOUT,
                                "%s", _("cannot acquire state change lock"));
377
            else
378
                virReportSystemError(errno,
379
                                     "%s", _("cannot acquire job mutex"));
380 381 382
            return -1;
        }
    }
383 384
    priv->jobActive = QEMU_JOB_UNSPECIFIED;
    priv->jobSignals = 0;
385
    memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData));
386 387
    priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403

    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;
404 405 406 407
    struct timeval now;
    unsigned long long then;

    if (gettimeofday(&now, NULL) < 0) {
408
        virReportSystemError(errno, "%s",
409 410 411 412 413
                             _("cannot get time of day"));
        return -1;
    }
    then = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    then += QEMU_JOB_WAIT_TIME;
414 415 416 417 418

    virDomainObjRef(obj);
    qemuDriverUnlock(driver);

    while (priv->jobActive) {
419
        if (virCondWaitUntil(&priv->jobCond, &obj->lock, then) < 0) {
420
            virDomainObjUnref(obj);
421
            if (errno == ETIMEDOUT)
422 423
                qemuReportError(VIR_ERR_OPERATION_TIMEOUT,
                                "%s", _("cannot acquire state change lock"));
424
            else
425
                virReportSystemError(errno,
426
                                     "%s", _("cannot acquire job mutex"));
M
Matthias Bolte 已提交
427
            qemuDriverLock(driver);
428 429 430
            return -1;
        }
    }
431 432
    priv->jobActive = QEMU_JOB_UNSPECIFIED;
    priv->jobSignals = 0;
433
    memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData));
434 435
    priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000);
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
436 437 438 439 440 441 442 443 444 445 446 447

    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
448
 * earlier qemuDomainBeginJob() call
449 450 451
 *
 * Returns remaining refcount on 'obj', maybe 0 to indicated it
 * was deleted
452
 */
453
static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj)
454 455 456
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

457 458
    priv->jobActive = QEMU_JOB_NONE;
    priv->jobSignals = 0;
459
    memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData));
460 461
    priv->jobStart = 0;
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
462 463
    virCondSignal(&priv->jobCond);

464
    return virDomainObjUnref(obj);
465 466 467 468 469 470 471
}


/*
 * obj must be locked before calling, qemud_driver must be unlocked
 *
 * To be called immediately before any QEMU monitor API call
472 473
 * Must have already called qemuDomainObjBeginJob(), and checked
 * that the VM is still active.
474 475 476
 *
 * To be followed with qemuDomainObjExitMonitor() once complete
 */
477 478 479 480 481
static void qemuDomainObjEnterMonitor(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    qemuMonitorLock(priv->mon);
482
    qemuMonitorRef(priv->mon);
483
    virDomainObjUnlock(obj);
484 485 486
}


487 488
/* obj must NOT be locked before calling, qemud_driver must be unlocked
 *
489
 * Should be paired with an earlier qemuDomainObjEnterMonitor() call
490
 */
491 492 493
static void qemuDomainObjExitMonitor(virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;
494 495 496 497 498 499
    int refs;

    refs = qemuMonitorUnref(priv->mon);

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

501
    virDomainObjLock(obj);
502 503 504 505 506

    if (refs == 0) {
        virDomainObjUnref(obj);
        priv->mon = NULL;
    }
507 508 509 510 511 512 513
}


/*
 * obj must be locked before calling, qemud_driver must be locked
 *
 * To be called immediately before any QEMU monitor API call
514
 * Must have already called qemuDomainObjBeginJob().
515 516 517 518 519 520 521 522
 *
 * To be followed with qemuDomainObjExitMonitorWithDriver() once complete
 */
static void qemuDomainObjEnterMonitorWithDriver(struct qemud_driver *driver, virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;

    qemuMonitorLock(priv->mon);
523
    qemuMonitorRef(priv->mon);
524 525 526 527 528 529 530 531
    virDomainObjUnlock(obj);
    qemuDriverUnlock(driver);
}


/* obj must NOT be locked before calling, qemud_driver must be unlocked,
 * and will be locked after returning
 *
532
 * Should be paired with an earlier qemuDomainObjEnterMonitorWithDriver() call
533 534 535 536
 */
static void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver, virDomainObjPtr obj)
{
    qemuDomainObjPrivatePtr priv = obj->privateData;
537 538 539 540 541 542
    int refs;

    refs = qemuMonitorUnref(priv->mon);

    if (refs > 0)
        qemuMonitorUnlock(priv->mon);
543 544 545

    qemuDriverLock(driver);
    virDomainObjLock(obj);
546 547 548 549 550

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

553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
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);
}
568

569
void qemuDomainDefNamespaceFree(void *nsdata)
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
{
    qemuDomainCmdlineDefPtr cmd = nsdata;
    unsigned int i;

    if (!cmd)
        return;

    for (i = 0; i < cmd->num_args; i++)
        VIR_FREE(cmd->args[i]);
    for (i = 0; i < cmd->num_env; i++) {
        VIR_FREE(cmd->env_name[i]);
        VIR_FREE(cmd->env_value[i]);
    }
    VIR_FREE(cmd->args);
    VIR_FREE(cmd->env_name);
    VIR_FREE(cmd->env_value);
    VIR_FREE(cmd);
}

589 590 591 592
int qemuDomainDefNamespaceParse(xmlDocPtr xml,
                                xmlNodePtr root,
                                xmlXPathContextPtr ctxt,
                                void **data)
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
{
    qemuDomainCmdlineDefPtr cmd = NULL;
    xmlNsPtr ns;
    xmlNodePtr *nodes = NULL;
    int n, i;

    ns = xmlSearchNs(xml, root, BAD_CAST "qemu");
    if (!ns)
        /* this is fine; it just means there was no qemu namespace listed */
        return 0;

    if (STRNEQ((const char *)ns->href, QEMU_NAMESPACE_HREF)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Found namespace '%s' doesn't match expected '%s'"),
                        ns->href, QEMU_NAMESPACE_HREF);
        return -1;
    }

    if (xmlXPathRegisterNs(ctxt, ns->prefix, ns->href) < 0) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Failed to register xml namespace '%s'"), ns->href);
        return -1;
    }

    if (VIR_ALLOC(cmd) < 0) {
        virReportOOMError();
        return -1;
    }

    /* first handle the extra command-line arguments */
    n = virXPathNodeSet("./qemu:commandline/qemu:arg", ctxt, &nodes);
    if (n < 0)
        /* virXPathNodeSet already set the error */
        goto error;

    if (n && VIR_ALLOC_N(cmd->args, n) < 0)
        goto no_memory;

    for (i = 0; i < n; i++) {
        cmd->args[cmd->num_args] = virXMLPropString(nodes[i], "value");
        if (cmd->args[cmd->num_args] == NULL) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("No qemu command-line argument specified"));
            goto error;
        }
        cmd->num_args++;
    }

    VIR_FREE(nodes);

    /* now handle the extra environment variables */
    n = virXPathNodeSet("./qemu:commandline/qemu:env", ctxt, &nodes);
    if (n < 0)
        /* virXPathNodeSet already set the error */
        goto error;

    if (n && VIR_ALLOC_N(cmd->env_name, n) < 0)
        goto no_memory;

    if (n && VIR_ALLOC_N(cmd->env_value, n) < 0)
        goto no_memory;

    for (i = 0; i < n; i++) {
        char *tmp;

        tmp = virXMLPropString(nodes[i], "name");
        if (tmp == NULL) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("No qemu environment name specified"));
            goto error;
        }
        if (tmp[0] == '\0') {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Empty qemu environment name specified"));
            goto error;
        }
        if (!c_isalpha(tmp[0]) && tmp[0] != '_') {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Invalid environment name, it must begin with a letter or underscore"));
            goto error;
        }
        if (strspn(tmp, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_") != strlen(tmp)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Invalid environment name, it must contain only alphanumerics and underscore"));
            goto error;
        }

        cmd->env_name[cmd->num_env] = tmp;

        cmd->env_value[cmd->num_env] = virXMLPropString(nodes[i], "value");
        /* a NULL value for command is allowed, since it might be empty */
        cmd->num_env++;
    }

    VIR_FREE(nodes);

    *data = cmd;

    return 0;

no_memory:
    virReportOOMError();

error:
    VIR_FREE(nodes);
    qemuDomainDefNamespaceFree(cmd);
    return -1;
}

702 703
int qemuDomainDefNamespaceFormatXML(virBufferPtr buf,
                                    void *nsdata)
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
{
    qemuDomainCmdlineDefPtr cmd = nsdata;
    unsigned int i;

    if (!cmd->num_args && !cmd->num_env)
        return 0;

    virBufferAddLit(buf, "  <qemu:commandline>\n");
    for (i = 0; i < cmd->num_args; i++)
        virBufferEscapeString(buf, "    <qemu:arg value='%s'/>\n",
                              cmd->args[i]);
    for (i = 0; i < cmd->num_env; i++) {
        virBufferVSprintf(buf, "    <qemu:env name='%s'", cmd->env_name[i]);
        if (cmd->env_value[i])
            virBufferEscapeString(buf, " value='%s'", cmd->env_value[i]);
        virBufferAddLit(buf, "/>\n");
    }
    virBufferAddLit(buf, "  </qemu:commandline>\n");

    return 0;
}

726
const char *qemuDomainDefNamespaceHref(void)
727 728 729 730
{
    return "xmlns:qemu='" QEMU_NAMESPACE_HREF "'";
}

731 732 733 734 735
static int qemuCgroupControllerActive(struct qemud_driver *driver,
                                      int controller)
{
    if (driver->cgroup == NULL)
        return 0;
L
Lai Jiangshan 已提交
736 737
    if (!virCgroupMounted(driver->cgroup, controller))
        return 0;
738 739 740 741
    if (driver->cgroupControllers & (1 << controller))
        return 1;
    return 0;
}
742

743
static int
744
qemudLogFD(struct qemud_driver *driver, const char* name)
745 746 747
{
    char logfile[PATH_MAX];
    mode_t logmode;
G
Guido Günther 已提交
748
    int ret, fd = -1;
749

750 751
    if ((ret = snprintf(logfile, sizeof(logfile), "%s/%s.log",
                        driver->logDir, name))
G
Guido Günther 已提交
752
        < 0 || ret >= sizeof(logfile)) {
753
        virReportOOMError();
754 755 756 757
        return -1;
    }

    logmode = O_CREAT | O_WRONLY;
758 759
    /* Only logrotate files in /var/log, so only append if running privileged */
    if (driver->privileged)
760
        logmode |= O_APPEND;
761 762 763
    else
        logmode |= O_TRUNC;

764
    if ((fd = open(logfile, logmode, S_IRUSR | S_IWUSR)) < 0) {
765
        virReportSystemError(errno,
766 767
                             _("failed to create logfile %s"),
                             logfile);
768 769
        return -1;
    }
770
    if (virSetCloseExec(fd) < 0) {
771
        virReportSystemError(errno, "%s",
772
                             _("Unable to set VM logfile close-on-exec flag"));
773
        VIR_FORCE_CLOSE(fd);
774 775 776 777 778 779
        return -1;
    }
    return fd;
}


780
static int
781
qemudLogReadFD(const char* logDir, const char* name, off_t pos)
782 783 784 785 786 787 788
{
    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)) {
789 790 791
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("failed to build logfile name %s/%s.log"),
                        logDir, name);
792 793 794 795 796
        return -1;
    }


    if ((fd = open(logfile, logmode)) < 0) {
797
        virReportSystemError(errno,
798 799
                             _("failed to create logfile %s"),
                             logfile);
800 801
        return -1;
    }
802
    if (virSetCloseExec(fd) < 0) {
803
        virReportSystemError(errno, "%s",
804
                             _("Unable to set VM logfile close-on-exec flag"));
805
        VIR_FORCE_CLOSE(fd);
806 807
        return -1;
    }
808
    if (pos < 0 || lseek(fd, pos, SEEK_SET) < 0) {
809
        virReportSystemError(pos < 0 ? 0 : errno,
810 811
                             _("Unable to seek to %lld in %s"),
                             (long long) pos, logfile);
812
        VIR_FORCE_CLOSE(fd);
813 814 815 816 817
    }
    return fd;
}


818 819 820 821 822 823 824 825 826
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;
827
    virErrorPtr err;
828 829

    virDomainObjLock(vm);
830 831 832 833 834 835 836 837 838
    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) &&
839
            qemudDomainObjStart(data->conn, data->driver, vm, false) < 0) {
840
            err = virGetLastError();
841
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
842
                      vm->def->name,
843
                      err ? err->message : _("unknown error"));
844
        }
845 846 847

        if (qemuDomainObjEndJob(vm) == 0)
            vm = NULL;
848
    }
849 850 851

    if (vm)
        virDomainObjUnlock(vm);
852 853
}

854 855
static void
qemudAutostartConfigs(struct qemud_driver *driver) {
856 857 858 859 860
    /* 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
     */
861 862 863
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
864
    /* Ignoring NULL conn which is mostly harmless here */
865
    struct qemuAutostartData data = { driver, conn };
866

867
    qemuDriverLock(driver);
868
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
869
    qemuDriverUnlock(driver);
870

871 872
    if (conn)
        virConnectClose(conn);
873 874
}

875 876 877 878 879 880 881 882 883

/**
 * qemudRemoveDomainStatus
 *
 * remove all state files of a domain from statedir
 *
 * Returns 0 on success
 */
static int
884
qemudRemoveDomainStatus(struct qemud_driver *driver,
885 886
                        virDomainObjPtr vm)
{
887
    char ebuf[1024];
888 889 890
    char *file = NULL;

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

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

900
    if (virFileDeletePid(driver->stateDir, vm->def->name) != 0)
901
        VIR_WARN("Failed to remove PID file for %s: %s",
902
                 vm->def->name, virStrerror(errno, ebuf, sizeof(ebuf)));
903

D
Daniel Veillard 已提交
904

905
    return 0;
906 907
}

908 909 910 911 912 913 914 915 916 917 918 919 920 921

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

922
    VIR_DEBUG("Received EOF on %p '%s'", vm, vm->def->name);
923

924 925 926 927 928 929 930 931
    virDomainObjLock(vm);

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

932
    qemudShutdownVMDaemon(driver, vm, 0);
933 934
    qemuDomainStopAudit(vm, hasError ? "failed" : "shutdown");

935 936 937 938 939 940 941 942 943 944 945 946 947
    if (!vm->persistent)
        virDomainRemoveInactive(&driver->domains, vm);
    else
        virDomainObjUnlock(vm);

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


948 949 950
static virDomainDiskDefPtr
findDomainDiskByPath(virDomainObjPtr vm,
                     const char *path)
951 952 953 954 955 956 957
{
    int i;

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

        disk = vm->def->disks[i];
958 959
        if (disk->src != NULL && STREQ(disk->src, path))
            return disk;
960
    }
961 962 963 964

    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                    _("no disk found with path %s"),
                    path);
965 966 967
    return NULL;
}

968 969 970 971 972 973
static virDomainDiskDefPtr
findDomainDiskByAlias(virDomainObjPtr vm,
                      const char *alias)
{
    int i;

974 975 976
    if (STRPREFIX(alias, QEMU_DRIVE_HOST_PREFIX))
        alias += strlen(QEMU_DRIVE_HOST_PREFIX);

977 978 979 980 981 982 983 984 985 986 987 988 989 990
    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;
}

991
static int
992 993 994 995
getVolumeQcowPassphrase(virConnectPtr conn,
                        virDomainDiskDefPtr disk,
                        char **secretRet,
                        size_t *secretLen)
996 997 998 999 1000
{
    virSecretPtr secret;
    char *passphrase;
    unsigned char *data;
    size_t size;
1001
    int ret = -1;
1002
    virStorageEncryptionPtr enc;
1003

1004 1005 1006 1007 1008 1009 1010
    if (!disk->encryption) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("disk %s does not have any encryption information"),
                        disk->src);
        return -1;
    }
    enc = disk->encryption;
1011 1012

    if (!conn) {
1013
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
1014
                        "%s", _("cannot find secrets without a connection"));
1015
        goto cleanup;
1016 1017 1018 1019 1020
    }

    if (conn->secretDriver == NULL ||
        conn->secretDriver->lookupByUUID == NULL ||
        conn->secretDriver->getValue == NULL) {
1021 1022
        qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
                        _("secret storage not supported"));
1023
        goto cleanup;
1024 1025 1026 1027 1028 1029
    }

    if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW ||
        enc->nsecrets != 1 ||
        enc->secrets[0]->type !=
        VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) {
1030
        qemuReportError(VIR_ERR_INVALID_DOMAIN,
1031
                        _("invalid <encryption> for volume %s"), disk->src);
1032
        goto cleanup;
1033 1034 1035 1036 1037
    }

    secret = conn->secretDriver->lookupByUUID(conn,
                                              enc->secrets[0]->uuid);
    if (secret == NULL)
1038
        goto cleanup;
1039 1040 1041 1042
    data = conn->secretDriver->getValue(secret, &size,
                                        VIR_SECRET_GET_VALUE_INTERNAL_CALL);
    virUnrefSecret(secret);
    if (data == NULL)
1043
        goto cleanup;
1044 1045 1046 1047

    if (memchr(data, '\0', size) != NULL) {
        memset(data, 0, size);
        VIR_FREE(data);
1048 1049
        qemuReportError(VIR_ERR_INVALID_SECRET,
                        _("format='qcow' passphrase for %s must not contain a "
1050
                          "'\\0'"), disk->src);
1051
        goto cleanup;
1052 1053 1054 1055 1056
    }

    if (VIR_ALLOC_N(passphrase, size + 1) < 0) {
        memset(data, 0, size);
        VIR_FREE(data);
1057
        virReportOOMError();
1058
        goto cleanup;
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
    }
    memcpy(passphrase, data, size);
    passphrase[size] = '\0';

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

    *secretRet = passphrase;
    *secretLen = size;

1069 1070 1071
    ret = 0;

cleanup:
1072 1073
    return ret;
}
1074

1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
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);
1096
    return ret;
1097 1098
}

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120

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


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


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


1182 1183 1184 1185 1186 1187
static int
qemuHandleDomainWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                         virDomainObjPtr vm,
                         int action)
{
    struct qemud_driver *driver = qemu_driver;
1188 1189
    virDomainEventPtr watchdogEvent = NULL;
    virDomainEventPtr lifecycleEvent = NULL;
1190 1191

    virDomainObjLock(vm);
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
    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);
    }
1206 1207
    virDomainObjUnlock(vm);

1208
    if (watchdogEvent || lifecycleEvent) {
1209
        qemuDriverLock(driver);
1210 1211 1212 1213
        if (watchdogEvent)
            qemuDomainEventQueue(driver, watchdogEvent);
        if (lifecycleEvent)
            qemuDomainEventQueue(driver, lifecycleEvent);
1214 1215 1216 1217 1218 1219 1220
        qemuDriverUnlock(driver);
    }

    return 0;
}


1221 1222 1223 1224
static int
qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                        virDomainObjPtr vm,
                        const char *diskAlias,
1225 1226
                        int action,
                        const char *reason)
1227 1228
{
    struct qemud_driver *driver = qemu_driver;
1229
    virDomainEventPtr ioErrorEvent = NULL;
1230
    virDomainEventPtr ioErrorEvent2 = NULL;
1231
    virDomainEventPtr lifecycleEvent = NULL;
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
    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 = "";
    }

1247
    ioErrorEvent = virDomainEventIOErrorNewFromObj(vm, srcPath, devAlias, action);
1248
    ioErrorEvent2 = virDomainEventIOErrorReasonNewFromObj(vm, srcPath, devAlias, action, reason);
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261

    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);
    }
1262 1263
    virDomainObjUnlock(vm);

1264
    if (ioErrorEvent || ioErrorEvent2 || lifecycleEvent) {
1265
        qemuDriverLock(driver);
1266 1267
        if (ioErrorEvent)
            qemuDomainEventQueue(driver, ioErrorEvent);
1268 1269
        if (ioErrorEvent2)
            qemuDomainEventQueue(driver, ioErrorEvent2);
1270 1271
        if (lifecycleEvent)
            qemuDomainEventQueue(driver, lifecycleEvent);
1272 1273 1274 1275 1276 1277 1278
        qemuDriverUnlock(driver);
    }

    return 0;
}


1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
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;
}


1371 1372 1373 1374 1375 1376 1377 1378 1379
static void qemuHandleMonitorDestroy(qemuMonitorPtr mon,
                                     virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    if (priv->mon == mon)
        priv->mon = NULL;
    virDomainObjUnref(vm);
}

1380
static qemuMonitorCallbacks monitorCallbacks = {
1381
    .destroy = qemuHandleMonitorDestroy,
1382 1383
    .eofNotify = qemuHandleMonitorEOF,
    .diskSecretLookup = findVolumeQcowPassphrase,
1384
    .domainStop = qemuHandleDomainStop,
1385
    .domainReset = qemuHandleDomainReset,
1386
    .domainRTCChange = qemuHandleDomainRTCChange,
1387
    .domainWatchdog = qemuHandleDomainWatchdog,
1388
    .domainIOError = qemuHandleDomainIOError,
1389
    .domainGraphics = qemuHandleDomainGraphics,
1390 1391
};

1392
static int
1393
qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
1394
{
1395
    qemuDomainObjPrivatePtr priv = vm->privateData;
1396
    int ret = -1;
1397

1398 1399 1400 1401 1402 1403
    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);
1404 1405 1406
        goto error;
    }

1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
    /* 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);
1418

1419 1420 1421 1422 1423 1424
    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);
1425
        goto error;
1426
    }
1427

1428 1429 1430 1431 1432 1433
    if (priv->mon == NULL) {
        VIR_INFO("Failed to connect monitor for %s", vm->def->name);
        goto error;
    }


1434 1435 1436 1437
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorSetCapabilities(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

1438
error:
1439
    if (ret < 0)
1440 1441 1442
        qemuMonitorClose(priv->mon);

    return ret;
1443
}
1444

1445 1446 1447 1448
struct virReconnectDomainData {
    virConnectPtr conn;
    struct qemud_driver *driver;
};
1449 1450 1451
/*
 * Open an existing VM's monitor, re-detect VCPU threads
 * and re-reserve the security labels in use
1452
 */
1453 1454
static void
qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
1455
{
1456
    virDomainObjPtr obj = payload;
1457 1458
    struct virReconnectDomainData *data = opaque;
    struct qemud_driver *driver = data->driver;
1459
    qemuDomainObjPrivatePtr priv;
1460
    unsigned long long qemuCmdFlags;
1461
    virConnectPtr conn = data->conn;
1462 1463

    virDomainObjLock(obj);
1464

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

1467 1468
    priv = obj->privateData;

1469
    /* XXX check PID liveliness & EXE path */
1470
    if (qemuConnectMonitor(driver, obj) < 0)
1471
        goto error;
1472

1473 1474 1475 1476
    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
        goto error;
    }

1477 1478 1479 1480 1481 1482
    /* 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 &&
1483
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
1484 1485
        priv->persistentAddrs = 1;

1486 1487 1488 1489
        if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(obj->def)) ||
            qemuAssignDevicePCISlots(obj->def, priv->pciaddrs) < 0)
            goto error;
    }
1490

1491
    if (driver->securityDriver &&
1492
        driver->securityDriver->domainReserveSecurityLabel &&
1493 1494
        driver->securityDriver->domainReserveSecurityLabel(driver->securityDriver,
                                                           obj) < 0)
1495
        goto error;
1496

1497 1498 1499
    if (qemudVMFiltersInstantiate(conn, obj->def))
        goto error;

1500 1501
    if (obj->def->id >= driver->nextvmid)
        driver->nextvmid = obj->def->id + 1;
1502

1503 1504
    virDomainObjUnlock(obj);
    return;
1505

1506
error:
1507 1508 1509
    /* 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 */
1510
    qemudShutdownVMDaemon(driver, obj, 0);
1511 1512 1513 1514
    if (!obj->persistent)
        virDomainRemoveInactive(&driver->domains, obj);
    else
        virDomainObjUnlock(obj);
1515
}
1516

1517
/**
1518
 * qemudReconnectDomains
1519 1520 1521 1522 1523
 *
 * Try to re-open the resources for live VMs that we care
 * about.
 */
static void
1524
qemuReconnectDomains(virConnectPtr conn, struct qemud_driver *driver)
1525
{
1526 1527
    struct virReconnectDomainData data = {conn, driver};
    virHashForEach(driver->domains.objs, qemuReconnectDomain, &data);
1528 1529
}

1530

1531 1532 1533 1534 1535 1536
static int
qemudSecurityInit(struct qemud_driver *qemud_drv)
{
    int ret;
    virSecurityDriverPtr security_drv;

1537 1538 1539
    qemuSecurityStackedSetDriver(qemud_drv);
    qemuSecurityDACSetDriver(qemud_drv);

1540
    ret = virSecurityDriverStartup(&security_drv,
1541 1542
                                   qemud_drv->securityDriverName,
                                   qemud_drv->allowDiskFormatProbing);
1543 1544 1545 1546
    if (ret == -1) {
        VIR_ERROR0(_("Failed to start security driver"));
        return -1;
    }
1547 1548 1549

    /* No primary security driver wanted to be enabled: just setup
     * the DAC driver on its own */
1550
    if (ret == -2) {
1551
        qemud_drv->securityDriver = &qemuDACSecurityDriver;
1552
        VIR_INFO0(_("No security driver available"));
1553 1554 1555 1556 1557
    } else {
        qemud_drv->securityPrimaryDriver = security_drv;
        qemud_drv->securitySecondaryDriver = &qemuDACSecurityDriver;
        qemud_drv->securityDriver = &qemuStackedSecurityDriver;
        VIR_INFO("Initialized security driver %s", security_drv->name);
1558 1559
    }

1560
    return 0;
1561
}
1562 1563


1564 1565
static virCapsPtr
qemuCreateCapabilities(virCapsPtr oldcaps,
1566
                       struct qemud_driver *driver)
1567 1568 1569 1570 1571
{
    virCapsPtr caps;

    /* Basic host arch / guest machine capabilities */
    if (!(caps = qemudCapsInit(oldcaps))) {
1572
        virReportOOMError();
1573 1574 1575
        return NULL;
    }

1576 1577 1578 1579 1580 1581 1582 1583
    if (driver->allowDiskFormatProbing) {
        caps->defaultDiskDriverName = NULL;
        caps->defaultDiskDriverType = NULL;
    } else {
        caps->defaultDiskDriverName = "qemu";
        caps->defaultDiskDriverType = "raw";
    }

1584 1585 1586 1587 1588 1589
    /* Domain XML parser hooks */
    caps->privateDataAllocFunc = qemuDomainObjPrivateAlloc;
    caps->privateDataFreeFunc = qemuDomainObjPrivateFree;
    caps->privateDataXMLFormat = qemuDomainObjPrivateXMLFormat;
    caps->privateDataXMLParse = qemuDomainObjPrivateXMLParse;

1590 1591 1592 1593 1594
    if (virGetHostUUID(caps->host.host_uuid)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot get the host uuid"));
        goto err_exit;
    }
1595

1596 1597 1598 1599 1600 1601
    /* Domain Namespace XML parser hooks */
    caps->ns.parse = qemuDomainDefNamespaceParse;
    caps->ns.free = qemuDomainDefNamespaceFree;
    caps->ns.format = qemuDomainDefNamespaceFormatXML;
    caps->ns.href = qemuDomainDefNamespaceHref;

1602
    /* Security driver data */
1603
    if (driver->securityPrimaryDriver) {
1604 1605
        const char *doi, *model;

1606 1607
        doi = virSecurityDriverGetDOI(driver->securityPrimaryDriver);
        model = virSecurityDriverGetModel(driver->securityPrimaryDriver);
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620

        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:
1621
    virReportOOMError();
1622
err_exit:
1623 1624 1625
    virCapabilitiesFree(caps);
    return NULL;
}
1626

C
Chris Lalancette 已提交
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
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) {
1644
        VIR_ERROR(_("Failed to allocate memory for snapshot directory for domain %s"),
C
Chris Lalancette 已提交
1645 1646 1647 1648 1649 1650 1651 1652 1653
                   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)
1654
            VIR_ERROR(_("Failed to open snapshot directory %s for domain %s: %s"),
C
Chris Lalancette 已提交
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668
                      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) {
1669
            VIR_ERROR0(_("Failed to allocate memory for path"));
C
Chris Lalancette 已提交
1670 1671 1672 1673 1674 1675
            continue;
        }

        ret = virFileReadAll(fullpath, 1024*1024*1, &xmlStr);
        if (ret < 0) {
            /* Nothing we can do here, skip this one */
1676
            VIR_ERROR(_("Failed to read snapshot file %s: %s"), fullpath,
C
Chris Lalancette 已提交
1677
                      virStrerror(errno, ebuf, sizeof(ebuf)));
1678
            VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1679 1680 1681 1682 1683 1684
            continue;
        }

        def = virDomainSnapshotDefParseString(xmlStr, 0);
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
1685
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"), fullpath);
1686
            VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1687 1688 1689 1690
            VIR_FREE(xmlStr);
            continue;
        }

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

1693
        VIR_FREE(fullpath);
C
Chris Lalancette 已提交
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714
        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);
}

1715 1716 1717 1718 1719 1720
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
1721
qemudStartup(int privileged) {
1722
    char *base = NULL;
D
Daniel P. Berrange 已提交
1723
    char driverConf[PATH_MAX];
1724
    int rc;
1725
    virConnectPtr conn = NULL;
1726

1727
    if (VIR_ALLOC(qemu_driver) < 0)
1728 1729
        return -1;

1730
    if (virMutexInit(&qemu_driver->lock) < 0) {
1731
        VIR_ERROR0(_("cannot initialize mutex"));
1732 1733 1734
        VIR_FREE(qemu_driver);
        return -1;
    }
1735
    qemuDriverLock(qemu_driver);
1736
    qemu_driver->privileged = privileged;
1737

1738 1739 1740
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;

1741 1742 1743
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;

1744
    /* Init callback list */
1745
    if (VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
1746
        goto out_of_memory;
1747 1748 1749 1750 1751 1752
    if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
        goto out_of_memory;

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

1754 1755 1756 1757 1758
    /* Allocate bitmap for vnc port reservation */
    if ((qemu_driver->reservedVNCPorts =
         virBitmapAlloc(QEMU_VNC_PORT_MAX - QEMU_VNC_PORT_MIN)) == NULL)
        goto out_of_memory;

1759 1760 1761 1762
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();

1763
    if (privileged) {
1764
        if (virAsprintf(&qemu_driver->logDir,
1765
                        "%s/log/libvirt/qemu", LOCALSTATEDIR) == -1)
1766
            goto out_of_memory;
1767

1768
        if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL)
1769
            goto out_of_memory;
1770 1771

        if (virAsprintf(&qemu_driver->stateDir,
1772
                      "%s/run/libvirt/qemu", LOCALSTATEDIR) == -1)
1773
            goto out_of_memory;
1774 1775

        if (virAsprintf(&qemu_driver->libDir,
1776
                      "%s/lib/libvirt/qemu", LOCALSTATEDIR) == -1)
1777 1778 1779
            goto out_of_memory;

        if (virAsprintf(&qemu_driver->cacheDir,
1780
                      "%s/cache/libvirt/qemu", LOCALSTATEDIR) == -1)
1781
            goto out_of_memory;
1782
        if (virAsprintf(&qemu_driver->saveDir,
1783
                      "%s/lib/libvirt/qemu/save", LOCALSTATEDIR) == -1)
1784
            goto out_of_memory;
C
Chris Lalancette 已提交
1785
        if (virAsprintf(&qemu_driver->snapshotDir,
1786
                        "%s/lib/libvirt/qemu/snapshot", LOCALSTATEDIR) == -1)
C
Chris Lalancette 已提交
1787
            goto out_of_memory;
1788
    } else {
1789
        uid_t uid = geteuid();
1790
        char *userdir = virGetUserDirectory(uid);
1791
        if (!userdir)
1792
            goto error;
1793

1794
        if (virAsprintf(&qemu_driver->logDir,
1795 1796
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
1797
            goto out_of_memory;
1798
        }
1799

1800 1801
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
1802
            goto out_of_memory;
1803 1804
        }
        VIR_FREE(userdir);
1805 1806 1807

        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", base) == -1)
            goto out_of_memory;
1808 1809 1810 1811
        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;
1812 1813
        if (virAsprintf(&qemu_driver->saveDir, "%s/qemu/save", base) == -1)
            goto out_of_memory;
C
Chris Lalancette 已提交
1814 1815
        if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
            goto out_of_memory;
1816 1817
    }

L
Laine Stump 已提交
1818
    if (virFileMakePath(qemu_driver->stateDir) != 0) {
1819
        char ebuf[1024];
1820
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
1821
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
1822
        goto error;
1823
    }
L
Laine Stump 已提交
1824
    if (virFileMakePath(qemu_driver->libDir) != 0) {
1825
        char ebuf[1024];
1826
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
1827 1828 1829
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
L
Laine Stump 已提交
1830
    if (virFileMakePath(qemu_driver->cacheDir) != 0) {
1831
        char ebuf[1024];
1832
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
1833 1834 1835
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof ebuf));
        goto error;
    }
1836 1837 1838 1839 1840 1841
    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 已提交
1842 1843 1844 1845 1846 1847
    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;
    }
1848 1849 1850 1851

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

1856
    if (virAsprintf(&qemu_driver->configDir, "%s/qemu", base) == -1)
1857 1858
        goto out_of_memory;

1859
    if (virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) == -1)
1860 1861
        goto out_of_memory;

1862
    VIR_FREE(base);
1863

1864 1865 1866 1867 1868 1869 1870
    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)));
    }

1871 1872 1873 1874
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
        goto error;
    }

1875 1876
    if (qemudSecurityInit(qemu_driver) < 0)
        goto error;
D
Daniel P. Berrange 已提交
1877

1878
    if ((qemu_driver->caps = qemuCreateCapabilities(NULL,
1879
                                                    qemu_driver)) == NULL)
1880
        goto error;
1881

1882
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
1883 1884
        goto error;

1885 1886
    if (privileged) {
        if (chown(qemu_driver->libDir, qemu_driver->user, qemu_driver->group) < 0) {
1887
            virReportSystemError(errno,
1888 1889 1890 1891 1892
                                 _("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) {
1893
            virReportSystemError(errno,
1894 1895 1896 1897
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
1898 1899 1900 1901 1902 1903
        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 已提交
1904 1905 1906 1907 1908 1909
        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;
        }
1910 1911
    }

1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925
    /* 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) {
1926
            virReportSystemError(rc,
1927 1928 1929 1930 1931 1932
                                 _("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) {
1933
            virReportSystemError(errno,
1934 1935 1936 1937 1938 1939 1940 1941 1942
                                 _("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;
    }

1943
    /* Get all the running persistent or transient configs first */
1944
    if (virDomainLoadAllConfigs(qemu_driver->caps,
1945 1946 1947 1948 1949 1950
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
                                1, NULL, NULL) < 0)
        goto error;

1951 1952 1953 1954 1955
    conn = virConnectOpen(qemu_driver->privileged ?
                          "qemu:///system" :
                          "qemu:///session");

    qemuReconnectDomains(conn, qemu_driver);
1956 1957

    /* Then inactive persistent configs */
1958
    if (virDomainLoadAllConfigs(qemu_driver->caps,
1959 1960
                                &qemu_driver->domains,
                                qemu_driver->configDir,
1961
                                qemu_driver->autostartDir,
1962
                                0, NULL, NULL) < 0)
1963
        goto error;
C
Chris Lalancette 已提交
1964 1965 1966 1967 1968


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

1969 1970
    qemuDriverUnlock(qemu_driver);

1971 1972
    qemudAutostartConfigs(qemu_driver);

1973 1974
    if (conn)
        virConnectClose(conn);
1975

1976 1977
    return 0;

1978
out_of_memory:
1979
    virReportOOMError();
1980 1981 1982
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
1983 1984
    if (conn)
        virConnectClose(conn);
1985
    VIR_FREE(base);
1986
    qemudShutdown();
1987 1988 1989
    return -1;
}

1990 1991 1992 1993
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;

1994 1995 1996 1997 1998 1999 2000 2001
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
    }
2002 2003
}

2004 2005 2006 2007 2008 2009 2010 2011
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
2012 2013 2014
    if (!qemu_driver)
        return 0;

2015
    qemuDriverLock(qemu_driver);
2016
    virDomainLoadAllConfigs(qemu_driver->caps,
2017 2018
                            &qemu_driver->domains,
                            qemu_driver->configDir,
2019
                            qemu_driver->autostartDir,
2020
                            0, qemudNotifyLoadDomain, qemu_driver);
2021
    qemuDriverUnlock(qemu_driver);
2022

2023
    qemudAutostartConfigs(qemu_driver);
2024 2025

    return 0;
2026 2027
}

2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
/**
 * 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) {
2038
    int active = 0;
2039

2040 2041 2042
    if (!qemu_driver)
        return 0;

2043
    /* XXX having to iterate here is not great because it requires many locks */
2044
    qemuDriverLock(qemu_driver);
2045
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
2046 2047
    qemuDriverUnlock(qemu_driver);
    return active;
2048 2049
}

2050 2051 2052 2053 2054 2055 2056
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
2057
    int i;
2058

2059
    if (!qemu_driver)
2060
        return -1;
2061

2062
    qemuDriverLock(qemu_driver);
2063
    pciDeviceListFree(qemu_driver->activePciHostdevs);
2064 2065
    virCapabilitiesFree(qemu_driver->caps);

2066
    virDomainObjListDeinit(&qemu_driver->domains);
2067
    virBitmapFree(qemu_driver->reservedVNCPorts);
2068

2069 2070
    virSysinfoDefFree(qemu_driver->hostsysinfo);

2071
    VIR_FREE(qemu_driver->securityDriverName);
2072
    VIR_FREE(qemu_driver->logDir);
2073 2074
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
2075
    VIR_FREE(qemu_driver->stateDir);
2076 2077
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
2078
    VIR_FREE(qemu_driver->saveDir);
C
Chris Lalancette 已提交
2079
    VIR_FREE(qemu_driver->snapshotDir);
2080
    VIR_FREE(qemu_driver->vncTLSx509certdir);
J
Jim Meyering 已提交
2081
    VIR_FREE(qemu_driver->vncListen);
2082
    VIR_FREE(qemu_driver->vncPassword);
2083
    VIR_FREE(qemu_driver->vncSASLdir);
2084
    VIR_FREE(qemu_driver->saveImageFormat);
2085 2086
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
D
Daniel P. Berrange 已提交
2087

2088 2089 2090 2091 2092 2093
    if (qemu_driver->cgroupDeviceACL) {
        for (i = 0 ; qemu_driver->cgroupDeviceACL[i] != NULL ; i++)
            VIR_FREE(qemu_driver->cgroupDeviceACL[i]);
        VIR_FREE(qemu_driver->cgroupDeviceACL);
    }

2094 2095
    /* Free domain callback list */
    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
2096 2097 2098 2099
    virDomainEventQueueFree(qemu_driver->domainEventQueue);

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

2101 2102 2103
    if (qemu_driver->brctl)
        brShutdown(qemu_driver->brctl);

2104 2105
    virCgroupFree(&qemu_driver->cgroup);

2106
    qemuDriverUnlock(qemu_driver);
2107
    virMutexDestroy(&qemu_driver->lock);
2108
    VIR_FREE(qemu_driver);
2109 2110

    return 0;
2111 2112
}

2113
typedef int qemuLogHandleOutput(virDomainObjPtr vm,
2114 2115
                                const char *output,
                                int fd);
2116 2117 2118 2119 2120

/*
 * Returns -1 for error, 0 on success
 */
static int
2121
qemudReadLogOutput(virDomainObjPtr vm,
2122 2123
                   int fd,
                   char *buf,
G
Guido Günther 已提交
2124
                   size_t buflen,
2125
                   qemuLogHandleOutput func,
2126 2127 2128
                   const char *what,
                   int timeout)
{
2129
    int retries = (timeout*10);
2130
    int got = 0;
2131 2132 2133
    buf[0] = '\0';

    while (retries) {
2134
        ssize_t func_ret, ret;
2135
        int isdead = 0;
G
Guido Günther 已提交
2136

2137
        func_ret = func(vm, buf, fd);
2138

2139 2140
        if (kill(vm->pid, 0) == -1 && errno == ESRCH)
            isdead = 1;
2141

2142 2143
        /* Any failures should be detected before we read the log, so we
         * always have something useful to report on failure. */
2144 2145
        ret = saferead(fd, buf+got, buflen-got-1);
        if (ret < 0) {
2146
            virReportSystemError(errno,
2147 2148 2149 2150 2151
                                 _("Failure while reading %s log output"),
                                 what);
            return -1;
        }

2152 2153 2154
        got += ret;
        buf[got] = '\0';
        if (got == buflen-1) {
2155
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
2156 2157
                            _("Out of space while reading %s log output: %s"),
                            what, buf);
2158 2159 2160 2161
            return -1;
        }

        if (isdead) {
2162
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
2163 2164
                            _("Process exited while reading %s log output: %s"),
                            what, buf);
2165 2166 2167
            return -1;
        }

2168 2169
        if (func_ret <= 0)
            return func_ret;
2170 2171 2172 2173

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

2175
    qemuReportError(VIR_ERR_INTERNAL_ERROR,
2176 2177
                    _("Timed out while reading %s log output: %s"),
                    what, buf);
2178 2179 2180
    return -1;
}

2181

2182 2183 2184 2185 2186 2187 2188 2189
/*
 * 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
 */
2190
static int
2191
qemudExtractTTYPath(const char *haystack,
2192 2193
                    size_t *offset,
                    char **path)
2194
{
2195
    static const char needle[] = "char device redirected to";
2196
    char *tmp, *dev;
2197

2198
    VIR_FREE(*path);
2199
    /* First look for our magic string */
2200 2201 2202 2203 2204
    if (!(tmp = strstr(haystack + *offset, needle))) {
        return 1;
    }
    tmp += sizeof(needle);
    dev = tmp;
2205

2206 2207 2208 2209 2210
    /*
     * And look for first whitespace character and nul terminate
     * to mark end of the pty path
     */
    while (*tmp) {
2211
        if (c_isspace(*tmp)) {
2212 2213
            *path = strndup(dev, tmp-dev);
            if (*path == NULL) {
2214
                virReportOOMError();
2215 2216
                return -1;
            }
2217

2218
            /* ... now further update offset till we get EOL */
2219
            *offset = tmp - haystack;
2220 2221
            return 0;
        }
2222
        tmp++;
2223 2224 2225 2226 2227
    }

    /*
     * We found a path, but didn't find any whitespace,
     * so it must be still incomplete - we should at
2228 2229
     * least see a \n - indicate that we want to carry
     * on trying again
2230
     */
2231
    return 1;
2232 2233
}

2234
static int
2235
qemudFindCharDevicePTYsMonitor(virDomainObjPtr vm,
2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250
                               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) {                                           \
2251 2252 2253
                if (chr->data.file.path == NULL) {                        \
                    /* neither the log output nor 'info chardev' had a */ \
                    /* pty path for this chardev, report an error */      \
2254 2255 2256
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,               \
                                    _("no assigned pty for device %s"), id); \
                    return -1;                                            \
2257 2258 2259 2260 2261
                } else {                                                  \
                    /* 'info chardev' had no pty path for this chardev, */\
                    /* but the log output had, so we're fine */           \
                    continue;                                             \
                }                                                         \
2262 2263
            }                                                             \
                                                                          \
2264
            VIR_FREE(chr->data.file.path);                                \
2265
            chr->data.file.path = strdup(path);                           \
2266 2267
                                                                          \
            if (chr->data.file.path == NULL) {                            \
2268
                virReportOOMError();                                      \
2269 2270
                return -1;                                                \
            }                                                             \
2271 2272 2273 2274 2275 2276
        }                                                                 \
    }

    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");
C
Cole Robinson 已提交
2277 2278
    if (vm->def->console)
        LOOKUP_PTYS(&vm->def->console, 1,  "console");
2279
#undef LOOKUP_PTYS
2280 2281 2282 2283

    return 0;
}

2284
static int
2285
qemudFindCharDevicePTYs(virDomainObjPtr vm,
2286 2287
                        const char *output,
                        int fd ATTRIBUTE_UNUSED)
2288
{
2289
    size_t offset = 0;
2290
    int ret, i;
2291 2292

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

2296
    /* first comes the serial devices */
2297 2298
    for (i = 0 ; i < vm->def->nserials ; i++) {
        virDomainChrDefPtr chr = vm->def->serials[i];
2299
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
2300
            if ((ret = qemudExtractTTYPath(output, &offset,
2301
                                           &chr->data.file.path)) != 0)
2302
                return ret;
2303 2304 2305
        }
    }

2306
    /* then the parallel devices */
2307 2308
    for (i = 0 ; i < vm->def->nparallels ; i++) {
        virDomainChrDefPtr chr = vm->def->parallels[i];
2309
        if (chr->type == VIR_DOMAIN_CHR_TYPE_PTY) {
2310
            if ((ret = qemudExtractTTYPath(output, &offset,
2311
                                           &chr->data.file.path)) != 0)
2312
                return ret;
2313 2314 2315
        }
    }

2316 2317 2318 2319
    /* 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) {
2320
            if ((ret = qemudExtractTTYPath(output, &offset,
2321 2322 2323 2324 2325
                                           &chr->data.file.path)) != 0)
                return ret;
        }
    }

2326
    return 0;
2327 2328
}

2329 2330 2331 2332 2333
static void qemudFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED)
{
    VIR_FREE(payload);
}

2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347
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';
}

2348
static int
2349
qemudWaitForMonitor(struct qemud_driver* driver,
2350
                    virDomainObjPtr vm, off_t pos)
2351
{
2352
    char buf[4096] = ""; /* Plenty of space to get startup greeting */
2353
    int logfd;
2354
    int ret = -1;
2355
    virHashTablePtr paths = NULL;
2356

2357
    if ((logfd = qemudLogReadFD(driver->logDir, vm->def->name, pos)) < 0)
2358
        return -1;
2359

2360 2361 2362 2363
    if (qemudReadLogOutput(vm, logfd, buf, sizeof(buf),
                           qemudFindCharDevicePTYs,
                           "console", 30) < 0)
        goto closelog;
2364

2365
    VIR_DEBUG("Connect monitor to %p '%s'", vm, vm->def->name);
2366 2367 2368
    if (qemuConnectMonitor(driver, vm) < 0) {
        goto cleanup;
    }
2369

2370 2371 2372 2373
    /* 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. */
2374
    paths = virHashCreate(0);
2375
    if (paths == NULL) {
2376
        virReportOOMError();
2377 2378 2379
        goto cleanup;
    }

2380
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2381 2382
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ret = qemuMonitorGetPtyPaths(priv->mon, paths);
2383
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2384 2385 2386

    VIR_DEBUG("qemuMonitorGetPtyPaths returned %i", ret);
    if (ret == 0) {
2387
        ret = qemudFindCharDevicePTYsMonitor(vm, paths);
2388 2389 2390 2391 2392 2393 2394
    }

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

2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
    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:
2406
    if (VIR_CLOSE(logfd) < 0) {
2407
        char ebuf[4096];
2408
        VIR_WARN("Unable to close logfile: %s",
2409 2410 2411
                 virStrerror(errno, ebuf, sizeof ebuf));
    }

2412
    return ret;
2413 2414
}

2415
static int
2416
qemuDetectVcpuPIDs(struct qemud_driver *driver,
2417 2418 2419
                   virDomainObjPtr vm) {
    pid_t *cpupids = NULL;
    int ncpupids;
2420
    qemuDomainObjPrivatePtr priv = vm->privateData;
2421

2422
    if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
2423 2424
        priv->nvcpupids = 1;
        if (VIR_ALLOC_N(priv->vcpupids, priv->nvcpupids) < 0) {
2425
            virReportOOMError();
2426 2427
            return -1;
        }
2428
        priv->vcpupids[0] = vm->pid;
2429 2430 2431
        return 0;
    }

2432
    /* What follows is now all KVM specific */
2433

2434
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2435
    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) < 0) {
2436
        qemuDomainObjExitMonitorWithDriver(driver, vm);
2437
        return -1;
2438
    }
2439
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2440

2441 2442 2443
    /* Treat failure to get VCPU<->PID mapping as non-fatal */
    if (ncpupids == 0)
        return 0;
2444

2445
    if (ncpupids != vm->def->vcpus) {
2446
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
2447 2448 2449
                        _("got wrong number of vCPU pids from QEMU monitor. "
                          "got %d, wanted %d"),
                        ncpupids, vm->def->vcpus);
2450 2451 2452
        VIR_FREE(cpupids);
        return -1;
    }
2453

2454 2455
    priv->nvcpupids = ncpupids;
    priv->vcpupids = cpupids;
2456 2457 2458
    return 0;
}

2459 2460 2461
/*
 * To be run between fork/exec of QEMU only
 */
2462
static int
2463 2464
qemudInitCpuAffinity(virDomainObjPtr vm)
{
2465
    int i, hostcpus, maxcpu = QEMUD_CPUMASK_LEN;
2466
    virNodeInfo nodeinfo;
2467 2468
    unsigned char *cpumap;
    int cpumaplen;
2469 2470

    DEBUG0("Setting CPU affinity");
2471

2472
    if (nodeGetInfo(NULL, &nodeinfo) < 0)
2473 2474 2475 2476
        return -1;

    /* setaffinity fails if you set bits for CPUs which
     * aren't present, so we have to limit ourselves */
2477 2478 2479
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
2480

2481 2482
    cpumaplen = VIR_CPU_MAPLEN(maxcpu);
    if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) {
2483
        virReportOOMError();
2484 2485 2486
        return -1;
    }

D
Daniel P. Berrange 已提交
2487
    if (vm->def->cpumask) {
2488 2489 2490
        /* 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 已提交
2491
            if (vm->def->cpumask[i])
2492
                VIR_USE_CPU(cpumap, i);
D
Daniel P. Berrange 已提交
2493
    } else {
2494 2495 2496 2497
        /* 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 已提交
2498
        for (i = 0 ; i < maxcpu ; i++)
2499
            VIR_USE_CPU(cpumap, i);
D
Daniel P. Berrange 已提交
2500
    }
2501

2502 2503 2504 2505 2506 2507 2508 2509
    /* 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;
2510
    }
2511
    VIR_FREE(cpumap);
2512 2513 2514 2515 2516

    return 0;
}


2517
static int
2518 2519 2520 2521
qemuInitPasswords(virConnectPtr conn,
                  struct qemud_driver *driver,
                  virDomainObjPtr vm,
                  unsigned long long qemuCmdFlags) {
2522
    int ret = 0;
2523
    qemuDomainObjPrivatePtr priv = vm->privateData;
2524

2525 2526
    if ((vm->def->ngraphics == 1) &&
        vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
2527
        (vm->def->graphics[0]->data.vnc.auth.passwd || driver->vncPassword)) {
2528

2529
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
2530
        ret = qemuMonitorSetVNCPassword(priv->mon,
2531 2532
                                        vm->def->graphics[0]->data.vnc.auth.passwd ?
                                        vm->def->graphics[0]->data.vnc.auth.passwd :
2533
                                        driver->vncPassword);
2534
        qemuDomainObjExitMonitorWithDriver(driver, vm);
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
    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);
2560
            VIR_FREE(secret);
2561 2562 2563 2564 2565 2566 2567
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            if (ret < 0)
                goto cleanup;
        }
    }

cleanup:
2568
    return ret;
2569 2570 2571
}


2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583
#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

2584 2585
#define QEMU_PCI_PRODUCT_BALLOON_VIRTIO 0x1002

2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 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 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793
#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;
}


2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812
static int
qemuGetPCIMemballoonVendorProduct(virDomainMemballoonDefPtr def,
                                  unsigned *vendor,
                                  unsigned *product)
{
    switch (def->model) {
    case VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO:
        *vendor = QEMU_PCI_VENDOR_REDHAT;
        *product = QEMU_PCI_PRODUCT_BALLOON_VIRTIO;
        break;

    default:
        return -1;
    }

    return 0;
}


2813 2814 2815 2816 2817 2818 2819 2820 2821
/*
 * 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
2822
qemuDetectPCIAddresses(virDomainObjPtr vm,
2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839
                       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) {
2840 2841 2842
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for VirtIO disk %s"),
                            vm->def->disks[i]->dst);
2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853
            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) {
2854 2855 2856
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for %s NIC"),
                            vm->def->nets[i]->model);
2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867
            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) {
2868 2869 2870
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for controller %s"),
                            virDomainControllerTypeToString(vm->def->controllers[i]->type));
2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881
            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) {
2882 2883 2884
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for video adapter %s"),
                            virDomainVideoTypeToString(vm->def->videos[i]->type));
2885 2886 2887 2888 2889 2890 2891 2892 2893
            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),
2894
                                    vendor, product,
2895
                                     addrs,  naddrs) < 0) {
2896 2897 2898
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for sound adapter %s"),
                            virDomainSoundModelTypeToString(vm->def->sounds[i]->model));
2899 2900 2901 2902 2903 2904 2905 2906 2907 2908
            return -1;
        }
    }


    if (vm->def->watchdog &&
        qemuGetPCIWatchdogVendorProduct(vm->def->watchdog, &vendor, &product) == 0) {
        if (qemuAssignNextPCIAddress(&(vm->def->watchdog->info),
                                     vendor, product,
                                     addrs,  naddrs) < 0) {
2909 2910 2911
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for watchdog %s"),
                            virDomainWatchdogModelTypeToString(vm->def->watchdog->model));
2912 2913 2914 2915
            return -1;
        }
    }

2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927
    if (vm->def->memballoon &&
        qemuGetPCIMemballoonVendorProduct(vm->def->memballoon, &vendor, &product) == 0) {
        if (qemuAssignNextPCIAddress(&(vm->def->memballoon->info),
                                     vendor, product,
                                     addrs, naddrs) < 0) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("cannot find PCI address for balloon %s"),
                            virDomainMemballoonModelTypeToString(vm->def->memballoon->model));
            return -1;
        }
    }

2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953
    /* XXX console (virtio) */


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

    /* XXX USB controller ? */

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

2954
    ret = qemuDetectPCIAddresses(vm, addrs, naddrs);
2955 2956 2957 2958 2959 2960

    VIR_FREE(addrs);

    return ret;
}

2961 2962 2963

static int qemudNextFreePort(struct qemud_driver *driver,
                             int startPort) {
2964 2965
    int i;

2966
    for (i = startPort ; i < 65535 ; i++) {
2967 2968 2969
        int fd;
        int reuse = 1;
        struct sockaddr_in addr;
2970 2971 2972 2973 2974 2975 2976 2977 2978
        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;

2979 2980 2981 2982 2983 2984 2985 2986
        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) {
2987
            VIR_FORCE_CLOSE(fd);
2988 2989 2990 2991 2992
            break;
        }

        if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
            /* Not in use, lets grab it */
2993
            VIR_FORCE_CLOSE(fd);
2994 2995 2996 2997 2998 2999
            /* 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);
            }
3000 3001
            return i;
        }
3002
        VIR_FORCE_CLOSE(fd);
3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013

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

3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051

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


3052
static pciDeviceList *
3053
qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
3054 3055
{
    pciDeviceList *list;
3056 3057
    int i;

3058
    if (!(list = pciDeviceListNew()))
3059
        return NULL;
3060

3061 3062
    for (i = 0 ; i < nhostdevs ; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
3063 3064 3065 3066 3067 3068 3069
        pciDevice *dev;

        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;
        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
            continue;

3070
        dev = pciGetDevice(hostdev->source.subsys.u.pci.domain,
3071 3072 3073
                           hostdev->source.subsys.u.pci.bus,
                           hostdev->source.subsys.u.pci.slot,
                           hostdev->source.subsys.u.pci.function);
3074
        if (!dev) {
3075
            pciDeviceListFree(list);
3076 3077
            return NULL;
        }
3078

3079 3080 3081
        if (pciDeviceListAdd(list, dev) < 0) {
            pciFreeDevice(dev);
            pciDeviceListFree(list);
3082
            return NULL;
3083 3084
        }

3085
        pciDeviceSetManaged(dev, hostdev->managed);
3086 3087
    }

3088 3089 3090 3091
    return list;
}

static int
3092 3093 3094 3095
qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
                            virDomainDefPtr def)
{
    pciDeviceList *pcidevs;
3096
    int i;
3097
    int ret = -1;
3098 3099 3100 3101

    if (!def->nhostdevs)
        return 0;

3102
    if (!(pcidevs = qemuGetPciHostDeviceList(def->hostdevs, def->nhostdevs)))
3103 3104
        return -1;

3105 3106
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3107 3108 3109
        pciDeviceListSteal(pcidevs, dev);
        if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            pciFreeDevice(dev);
3110
            goto cleanup;
3111 3112 3113
        }
    }

3114 3115 3116
    ret = 0;

cleanup:
3117
    pciDeviceListFree(pcidevs);
3118 3119 3120
    return ret;
}

3121

3122
static int
3123 3124 3125
qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
                             virDomainHostdevDefPtr *hostdevs,
                             int nhostdevs)
3126 3127 3128
{
    pciDeviceList *pcidevs;
    int i;
3129
    int ret = -1;
3130

3131
    if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
3132 3133
        return -1;

3134
    /* We have to use 3 loops here. *All* devices must
3135 3136
     * be detached before we reset any of them, because
     * in some cases you have to reset the whole PCI,
3137 3138
     * which impacts all devices on it. Also, all devices
     * must be reset before being marked as active.
3139 3140 3141 3142 3143 3144 3145
     */

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

3146 3147
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3148
        if (!pciDeviceIsAssignable(dev, !driver->relaxedACS))
3149 3150
            goto cleanup;

3151
        if (pciDeviceGetManaged(dev) &&
3152
            pciDettachDevice(dev, driver->activePciHostdevs) < 0)
3153 3154
            goto cleanup;
    }
3155 3156 3157

    /* Now that all the PCI hostdevs have be dettached, we can safely
     * reset them */
3158 3159
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3160
        if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0)
3161 3162
            goto cleanup;
    }
3163

3164
    /* Now mark all the devices as active */
3165 3166
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3167 3168 3169
        pciDeviceListSteal(pcidevs, dev);
        if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            pciFreeDevice(dev);
3170 3171
            goto cleanup;
        }
3172 3173
    }

3174
    ret = 0;
3175

3176
cleanup:
3177
    pciDeviceListFree(pcidevs);
3178
    return ret;
3179 3180
}

3181 3182 3183 3184 3185 3186 3187
static int
qemuPrepareHostPCIDevices(struct qemud_driver *driver,
                          virDomainDefPtr def)
{
    return qemuPrepareHostdevPCIDevices(driver, def->hostdevs, def->nhostdevs);
}

3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198

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;
3199
        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237
            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;
}


3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253
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;
    }

3254
    VIR_FORCE_CLOSE(fd);
3255 3256 3257 3258 3259

    return 0;
}


3260
static void
3261
qemudReattachPciDevice(pciDevice *dev, struct qemud_driver *driver)
3262 3263 3264
{
    int retries = 100;

3265 3266 3267 3268 3269 3270
    while (pciWaitForDeviceCleanup(dev, "kvm_assigned_device")
           && retries) {
        usleep(100*1000);
        retries--;
    }

3271
    if (pciDeviceGetManaged(dev)) {
3272
        if (pciReAttachDevice(dev, driver->activePciHostdevs) < 0) {
3273 3274
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to re-attach PCI device: %s"),
3275
                      err ? err->message : _("unknown error"));
3276 3277 3278 3279 3280
            virResetError(err);
        }
    }
}

3281
static void
3282 3283 3284
qemuDomainReAttachHostdevDevices(struct qemud_driver *driver,
                              virDomainHostdevDefPtr *hostdevs,
                              int nhostdevs)
3285
{
3286
    pciDeviceList *pcidevs;
3287 3288
    int i;

3289
    if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs))) {
3290
        virErrorPtr err = virGetLastError();
3291
        VIR_ERROR(_("Failed to allocate pciDeviceList: %s"),
3292
                  err ? err->message : _("unknown error"));
3293 3294
        virResetError(err);
        return;
3295 3296
    }

3297 3298
    /* Again 3 loops; mark all devices as inactive before reset
     * them and reset all the devices before re-attach */
3299

3300 3301
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3302
        pciDeviceListDel(driver->activePciHostdevs, dev);
3303
    }
3304

3305 3306
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3307
        if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0) {
3308
            virErrorPtr err = virGetLastError();
3309
            VIR_ERROR(_("Failed to reset PCI device: %s"),
3310
                      err ? err->message : _("unknown error"));
3311 3312
            virResetError(err);
        }
3313
    }
3314

3315 3316
    for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
        pciDevice *dev = pciDeviceListGet(pcidevs, i);
3317
        qemudReattachPciDevice(dev, driver);
3318
    }
3319

3320
    pciDeviceListFree(pcidevs);
3321 3322
}

3323 3324 3325 3326 3327 3328 3329 3330 3331 3332
static void
qemuDomainReAttachHostDevices(struct qemud_driver *driver,
                              virDomainDefPtr def)
{
    if (!def->nhostdevs)
        return;

    qemuDomainReAttachHostdevDevices(driver, def->hostdevs, def->nhostdevs);
}

3333 3334 3335 3336 3337 3338 3339 3340 3341 3342
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

3343

3344 3345 3346 3347 3348 3349 3350
static int qemuSetupDiskPathAllow(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
                                  const char *path,
                                  size_t depth ATTRIBUTE_UNUSED,
                                  void *opaque)
{
    virCgroupPtr cgroup = opaque;
    int rc;
3351

3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365
    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;
3366
        }
3367
    }
3368 3369
    return 0;
}
3370 3371


3372 3373
static int qemuSetupDiskCgroup(struct qemud_driver *driver,
                               virCgroupPtr cgroup,
3374 3375 3376
                               virDomainDiskDefPtr disk)
{
    return virDomainDiskDefForeachPath(disk,
3377
                                       driver->allowDiskFormatProbing,
3378 3379 3380
                                       true,
                                       qemuSetupDiskPathAllow,
                                       cgroup);
3381 3382 3383
}


3384 3385 3386 3387
static int qemuTeardownDiskPathDeny(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
                                    const char *path,
                                    size_t depth ATTRIBUTE_UNUSED,
                                    void *opaque)
3388
{
3389 3390
    virCgroupPtr cgroup = opaque;
    int rc;
3391

3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405
    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;
3406
        }
3407
    }
3408 3409
    return 0;
}
3410 3411


3412 3413
static int qemuTeardownDiskCgroup(struct qemud_driver *driver,
                                  virCgroupPtr cgroup,
3414 3415 3416
                                  virDomainDiskDefPtr disk)
{
    return virDomainDiskDefForeachPath(disk,
3417
                                       driver->allowDiskFormatProbing,
3418 3419 3420
                                       true,
                                       qemuTeardownDiskPathDeny,
                                       cgroup);
3421 3422 3423
}


3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447
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;
}


3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466
static int qemuSetupHostUsbDeviceCgroup(usbDevice *dev ATTRIBUTE_UNUSED,
                                        const char *path,
                                        void *opaque)
{
    virCgroupPtr cgroup = opaque;
    int rc;

    VIR_DEBUG("Process path '%s' for USB device", path);
    rc = virCgroupAllowDevicePath(cgroup, path);
    if (rc != 0) {
        virReportSystemError(-rc,
                             _("Unable to allow device %s"),
                             path);
        return -1;
    }

    return 0;
}

3467
static int qemuSetupCgroup(struct qemud_driver *driver,
3468 3469 3470 3471
                           virDomainObjPtr vm)
{
    virCgroupPtr cgroup = NULL;
    int rc;
3472
    unsigned int i;
3473 3474 3475 3476
    const char *const *deviceACL =
        driver->cgroupDeviceACL ?
        (const char *const *)driver->cgroupDeviceACL :
        defaultDeviceACL;
3477 3478 3479 3480 3481 3482

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

    rc = virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 1);
    if (rc != 0) {
3483
        virReportSystemError(-rc,
3484 3485 3486 3487 3488
                             _("Unable to create cgroup for %s"),
                             vm->def->name);
        goto cleanup;
    }

3489 3490
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        rc = virCgroupDenyAllDevices(cgroup);
3491
        if (rc != 0) {
3492 3493 3494 3495 3496
            if (rc == -EPERM) {
                VIR_WARN0("Group devices ACL is not accessible, disabling whitelisting");
                goto done;
            }

3497
            virReportSystemError(-rc,
3498
                                 _("Unable to deny all devices for %s"), vm->def->name);
3499 3500 3501
            goto cleanup;
        }

3502
        for (i = 0; i < vm->def->ndisks ; i++) {
3503
            if (qemuSetupDiskCgroup(driver, cgroup, vm->def->disks[i]) < 0)
3504 3505
                goto cleanup;
        }
3506

3507
        rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_PTY_MAJOR);
3508
        if (rc != 0) {
3509
            virReportSystemError(-rc, "%s",
3510
                                 _("unable to allow /dev/pts/ devices"));
3511 3512 3513
            goto cleanup;
        }

3514 3515 3516
        if (vm->def->nsounds) {
            rc = virCgroupAllowDeviceMajor(cgroup, 'c', DEVICE_SND_MAJOR);
            if (rc != 0) {
3517
                virReportSystemError(-rc, "%s",
3518 3519 3520 3521 3522 3523 3524 3525 3526 3527
                                     _("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) {
3528
                virReportSystemError(-rc,
3529 3530 3531 3532
                                     _("unable to allow device %s"),
                                     deviceACL[i]);
                goto cleanup;
            }
3533
        }
3534 3535 3536 3537 3538 3539

        if (virDomainChrDefForeach(vm->def,
                                   true,
                                   qemuSetupChardevCgroup,
                                   cgroup) < 0)
            goto cleanup;
3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556

        for (i = 0; i < vm->def->nhostdevs; i++) {
            virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i];
            usbDevice *usb;

            if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
                continue;
            if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
                continue;

            if ((usb = usbGetDevice(hostdev->source.subsys.u.usb.bus,
                                    hostdev->source.subsys.u.usb.device)) == NULL)
                goto cleanup;

            if (usbDeviceFileIterate(usb, qemuSetupHostUsbDeviceCgroup, cgroup) < 0 )
                goto cleanup;
        }
3557 3558
    }

3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592
    if ((rc = qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY))) {
        if (vm->def->mem.hard_limit != 0) {
            rc = virCgroupSetMemoryHardLimit(cgroup, vm->def->mem.hard_limit);
            if (rc != 0) {
                virReportSystemError(-rc,
                                     _("Unable to set memory hard limit for domain %s"),
                                     vm->def->name);
                goto cleanup;
            }
        }
        if (vm->def->mem.soft_limit != 0) {
            rc = virCgroupSetMemorySoftLimit(cgroup, vm->def->mem.soft_limit);
            if (rc != 0) {
                virReportSystemError(-rc,
                                     _("Unable to set memory soft limit for domain %s"),
                                     vm->def->name);
                goto cleanup;
            }
        }

        if (vm->def->mem.swap_hard_limit != 0) {
            rc = virCgroupSetSwapHardLimit(cgroup, vm->def->mem.swap_hard_limit);
            if (rc != 0) {
                virReportSystemError(-rc,
                                     _("Unable to set swap hard limit for domain %s"),
                                     vm->def->name);
                goto cleanup;
            }
        }
    } else {
        VIR_WARN("Memory cgroup is disabled in qemu configuration file: %s",
                 vm->def->name);
    }

3593
done:
3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605
    virCgroupFree(&cgroup);
    return 0;

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


3606
static int qemuRemoveCgroup(struct qemud_driver *driver,
3607 3608
                            virDomainObjPtr vm,
                            int quiet)
3609 3610 3611 3612 3613 3614 3615 3616 3617
{
    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) {
3618
        if (!quiet)
3619 3620 3621
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Unable to find cgroup for %s\n"),
                            vm->def->name);
3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641
        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) {
3642
        virReportSystemError(-rc,
3643 3644 3645 3646 3647 3648 3649
                             _("unable to find cgroup for domain %s"),
                             def->name);
        goto cleanup;
    }

    rc = virCgroupAddTask(cgroup, getpid());
    if (rc != 0) {
3650
        virReportSystemError(-rc,
3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667
                             _("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;
3668 3669 3670
};

static int qemudSecurityHook(void *data) {
3671 3672
    struct qemudHookData *h = data;

3673 3674 3675
    /* This must take place before exec(), so that all QEMU
     * memory allocation is on the correct NUMA node
     */
3676
    if (qemuAddToCgroup(h->driver, h->vm->def) < 0)
3677 3678
        return -1;

3679 3680 3681
    /* This must be done after cgroup placement to avoid resetting CPU
     * affinity */
    if (qemudInitCpuAffinity(h->vm) < 0)
3682
        return -1;
3683

3684 3685
    if (h->driver->securityDriver &&
        h->driver->securityDriver->domainSetSecurityProcessLabel &&
3686
        h->driver->securityDriver->domainSetSecurityProcessLabel(h->driver->securityDriver, h->vm) < 0)
3687 3688 3689
        return -1;

    return 0;
3690 3691
}

3692
static int
3693
qemuPrepareMonitorChr(struct qemud_driver *driver,
3694
                      virDomainChrDefPtr monConfig,
3695 3696
                      const char *vm)
{
3697
    monConfig->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_MONITOR;
3698

3699 3700
    monConfig->type = VIR_DOMAIN_CHR_TYPE_UNIX;
    monConfig->data.nix.listen = 1;
3701

D
Daniel P. Berrange 已提交
3702
    if (!(monConfig->info.alias = strdup("monitor"))) {
3703
        virReportOOMError();
D
Daniel P. Berrange 已提交
3704 3705 3706
        return -1;
    }

3707
    if (virAsprintf(&monConfig->data.nix.path, "%s/%s.monitor",
3708
                    driver->libDir, vm) < 0) {
3709
        virReportOOMError();
3710 3711 3712 3713 3714 3715
        return -1;
    }

    return 0;
}

C
Chris Lalancette 已提交
3716 3717 3718 3719 3720
static int qemuDomainSnapshotSetActive(virDomainObjPtr vm,
                                       char *snapshotDir);
static int qemuDomainSnapshotSetInactive(virDomainObjPtr vm,
                                         char *snapshotDir);

3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793
static void qemuDomainDiskAudit(virDomainObjPtr vm,
                                virDomainDiskDefPtr oldDef,
                                virDomainDiskDefPtr newDef,
                                const char *reason,
                                bool success)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    char *vmname;
    char *oldsrc = NULL;
    char *newsrc = NULL;

    virUUIDFormat(vm->def->uuid, uuidstr);
    if (!(vmname = virAuditEncode("vm", vm->def->name))) {
        VIR_WARN0("OOM while encoding audit message");
        return;
    }

    if (!(oldsrc = virAuditEncode("old-disk",
                                  oldDef && oldDef->src ?
                                  oldDef->src : "?"))) {
        VIR_WARN0("OOM while encoding audit message");
        goto cleanup;
    }
    if (!(newsrc = virAuditEncode("new-disk",
                                  newDef && newDef->src ?
                                  newDef->src : "?"))) {
        VIR_WARN0("OOM while encoding audit message");
        goto cleanup;
    }

    VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
              "resrc=disk reason=%s %s uuid=%s %s %s",
              reason, vmname, uuidstr,
              oldsrc, newsrc);

cleanup:
    VIR_FREE(vmname);
    VIR_FREE(oldsrc);
    VIR_FREE(newsrc);
}


static void qemuDomainNetAudit(virDomainObjPtr vm,
                               virDomainNetDefPtr oldDef,
                               virDomainNetDefPtr newDef,
                               const char *reason,
                               bool success)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    char newMacstr[VIR_MAC_STRING_BUFLEN];
    char oldMacstr[VIR_MAC_STRING_BUFLEN];
    char *vmname;

    virUUIDFormat(vm->def->uuid, uuidstr);
    if (oldDef)
        virFormatMacAddr(oldDef->mac, oldMacstr);
    if (newDef)
        virFormatMacAddr(newDef->mac, newMacstr);
    if (!(vmname = virAuditEncode("vm", vm->def->name))) {
        VIR_WARN0("OOM while encoding audit message");
        return;
    }

    VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
              "resrc=net reason=%s %s uuid=%s old-net='%s' new-net='%s'",
              reason, vmname, uuidstr,
              oldDef ? oldMacstr : "?",
              newDef ? newMacstr : "?");

    VIR_FREE(vmname);
}


3794 3795 3796 3797 3798 3799 3800 3801 3802
static void qemuDomainLifecycleAudit(virDomainObjPtr vm,
                                     const char *op,
                                     const char *reason,
                                     bool success)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    char *vmname;

    virUUIDFormat(vm->def->uuid, uuidstr);
3803

3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816
    if (!(vmname = virAuditEncode("vm", vm->def->name))) {
        VIR_WARN0("OOM while encoding audit message");
        return;
    }

    VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_CONTROL, success,
              "op=%s reason=%s %s uuid=%s", op, reason, vmname, uuidstr);

    VIR_FREE(vmname);
}

static void qemuDomainStartAudit(virDomainObjPtr vm, const char *reason, bool success)
{
3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829
    int i;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        virDomainDiskDefPtr disk = vm->def->disks[i];
        if (disk->src) /* Skips CDROM without media initially inserted */
            qemuDomainDiskAudit(vm, NULL, disk, "start", true);
    }

    for (i = 0 ; i < vm->def->nnets ; i++) {
        virDomainNetDefPtr net = vm->def->nets[i];
        qemuDomainNetAudit(vm, NULL, net, "start", true);
    }

3830 3831 3832 3833 3834 3835 3836 3837
    qemuDomainLifecycleAudit(vm, "start", reason, success);
}

static void qemuDomainStopAudit(virDomainObjPtr vm, const char *reason)
{
    qemuDomainLifecycleAudit(vm, "stop", reason, true);
}

3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857
static void qemuDomainSecurityLabelAudit(virDomainObjPtr vm, bool success)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    char *vmname;

    virUUIDFormat(vm->def->uuid, uuidstr);
    if (!(vmname = virAuditEncode("vm", vm->def->name))) {
        VIR_WARN0("OOM while encoding audit message");
        return;
    }

    VIR_AUDIT(VIR_AUDIT_RECORD_MACHINE_ID, success,
              "%s uuid=%s vm-ctx=%s img-ctx=%s",
              vmname, uuidstr,
              VIR_AUDIT_STR(vm->def->seclabel.label),
              VIR_AUDIT_STR(vm->def->seclabel.imagelabel));

    VIR_FREE(vmname);
}

3858 3859
#define START_POSTFIX ": starting up\n"
#define SHUTDOWN_POSTFIX ": shutting down\n"
3860

3861 3862
static int qemudStartVMDaemon(virConnectPtr conn,
                              struct qemud_driver *driver,
3863
                              virDomainObjPtr vm,
3864
                              const char *migrateFrom,
3865
                              bool start_paused,
3866 3867
                              int stdin_fd,
                              const char *stdin_path) {
3868
    const char **argv = NULL, **tmp;
3869
    const char **progenv = NULL;
3870
    int i, ret, runflags;
3871
    struct stat sb;
3872 3873
    int *vmfds = NULL;
    int nvmfds = 0;
3874
    unsigned long long qemuCmdFlags;
3875
    fd_set keepfd;
3876
    const char *emulator;
G
Guido Günther 已提交
3877
    pid_t child;
3878
    int pos = -1;
3879
    char ebuf[1024];
3880
    char *pidfile = NULL;
3881
    int logfile = -1;
3882
    char *timestamp;
3883
    qemuDomainObjPrivatePtr priv = vm->privateData;
3884

3885
    struct qemudHookData hookData;
3886 3887 3888 3889
    hookData.conn = conn;
    hookData.vm = vm;
    hookData.driver = driver;

3890
    FD_ZERO(&keepfd);
3891

3892 3893
    DEBUG0("Beginning VM startup process");

D
Daniel P. Berrange 已提交
3894
    if (virDomainObjIsActive(vm)) {
3895 3896
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("VM is already active"));
3897 3898 3899
        return -1;
    }

3900 3901 3902 3903 3904
    /* Must be run before security labelling */
    DEBUG0("Preparing host devices");
    if (qemuPrepareHostDevices(driver, vm->def) < 0)
        goto cleanup;

3905 3906 3907 3908 3909 3910 3911
    DEBUG0("Preparing chr devices");
    if (virDomainChrDefForeach(vm->def,
                               true,
                               qemuPrepareChardevDevice,
                               NULL) < 0)
        goto cleanup;

3912 3913
    /* If you are using a SecurityDriver with dynamic labelling,
       then generate a security label for isolation */
3914
    DEBUG0("Generating domain security label (if required)");
3915
    if (driver->securityDriver &&
3916 3917 3918 3919 3920 3921 3922
        driver->securityDriver->domainGenSecurityLabel) {
        ret = driver->securityDriver->domainGenSecurityLabel(driver->securityDriver,
                                                             vm);
        qemuDomainSecurityLabelAudit(vm, ret >= 0);
        if (ret < 0)
            goto cleanup;
    }
3923

3924
    DEBUG0("Generating setting domain security labels (if required)");
3925 3926
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityAllLabel &&
3927 3928
        driver->securityDriver->domainSetSecurityAllLabel(driver->securityDriver,
                                                          vm, stdin_path) < 0) {
3929
        goto cleanup;
3930
    }
3931

3932 3933 3934
    /* Ensure no historical cgroup for this VM is lying around bogus
     * settings */
    DEBUG0("Ensuring no historical cgroup is lying around");
3935
    qemuRemoveCgroup(driver, vm, 1);
3936

3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949
    if (vm->def->ngraphics == 1) {
        if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
            vm->def->graphics[0]->data.vnc.autoport) {
            int port = qemudNextFreePort(driver, 5900);
            if (port < 0) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Unable to find an unused VNC port"));
                goto cleanup;
            }
            vm->def->graphics[0]->data.vnc.port = port;
        } else if (vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE &&
                   vm->def->graphics[0]->data.spice.autoport) {
            int port = qemudNextFreePort(driver, 5900);
3950 3951
            int tlsPort = -1;
            if (port < 0) {
3952
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
3953
                                "%s", _("Unable to find an unused SPICE port"));
3954 3955 3956
                goto cleanup;
            }

3957 3958 3959 3960 3961 3962 3963 3964 3965
            if (driver->spiceTLS) {
                tlsPort = qemudNextFreePort(driver, port + 1);
                if (tlsPort < 0) {
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("Unable to find an unused SPICE TLS port"));
                    goto cleanup;
                }
            }

3966 3967
            vm->def->graphics[0]->data.spice.port = port;
            vm->def->graphics[0]->data.spice.tlsPort = tlsPort;
3968
        }
3969
    }
3970

L
Laine Stump 已提交
3971
    if (virFileMakePath(driver->logDir) != 0) {
3972
        virReportSystemError(errno,
3973 3974
                             _("cannot create log directory %s"),
                             driver->logDir);
3975
        goto cleanup;
3976 3977
    }

3978
    DEBUG0("Creating domain log file");
3979
    if ((logfile = qemudLogFD(driver, vm->def->name)) < 0)
3980
        goto cleanup;
3981

3982 3983
    emulator = vm->def->emulator;

3984 3985 3986 3987
    /* 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
     */
3988
    if (stat(emulator, &sb) < 0) {
3989
        virReportSystemError(errno,
3990 3991
                             _("Cannot find QEMU binary %s"),
                             emulator);
3992
        goto cleanup;
3993 3994
    }

3995
    DEBUG0("Determing emulator version");
3996
    if (qemudExtractVersionInfo(emulator,
3997
                                NULL,
3998
                                &qemuCmdFlags) < 0)
3999
        goto cleanup;
4000

4001
    DEBUG0("Setting up domain cgroup (if required)");
4002
    if (qemuSetupCgroup(driver, vm) < 0)
4003 4004
        goto cleanup;

4005
    if (VIR_ALLOC(priv->monConfig) < 0) {
4006
        virReportOOMError();
4007 4008 4009
        goto cleanup;
    }

4010
    DEBUG0("Preparing monitor state");
4011
    if (qemuPrepareMonitorChr(driver, priv->monConfig, vm->def->name) < 0)
4012
        goto cleanup;
4013

D
Daniel P. Berrange 已提交
4014 4015 4016
#if HAVE_YAJL
    if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON)
        priv->monJSON = 1;
4017
    else
D
Daniel P. Berrange 已提交
4018
#endif
4019
        priv->monJSON = 0;
D
Daniel P. Berrange 已提交
4020

4021 4022
    priv->monitor_warned = 0;

D
Daniel P. Berrange 已提交
4023
    if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) {
4024
        virReportSystemError(ret,
D
Daniel P. Berrange 已提交
4025 4026 4027 4028 4029
                             _("Cannot remove stale PID file for %s"),
                             vm->def->name);
        goto cleanup;
    }

4030
    if (!(pidfile = virFilePid(driver->stateDir, vm->def->name))) {
4031
        virReportSystemError(errno,
4032 4033 4034
                             "%s", _("Failed to build pidfile path."));
        goto cleanup;
    }
D
Daniel P. Berrange 已提交
4035

4036
    /*
M
Matthew Booth 已提交
4037
     * Normally PCI addresses are assigned in the virDomainCreate
4038 4039 4040 4041 4042
     * 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
     */
4043
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
4044
        DEBUG0("Assigning domain PCI addresses");
4045
        /* Populate cache with current addresses */
4046 4047 4048 4049 4050 4051 4052
        if (priv->pciaddrs) {
            qemuDomainPCIAddressSetFree(priv->pciaddrs);
            priv->pciaddrs = NULL;
        }
        if (!(priv->pciaddrs = qemuDomainPCIAddressSetCreate(vm->def)))
            goto cleanup;

4053 4054

        /* Assign any remaining addresses */
4055 4056
        if (qemuAssignDevicePCISlots(vm->def, priv->pciaddrs) < 0)
            goto cleanup;
4057 4058 4059 4060

        priv->persistentAddrs = 1;
    } else {
        priv->persistentAddrs = 0;
4061 4062
    }

4063
    DEBUG0("Building emulator command line");
4064
    vm->def->id = driver->nextvmid++;
4065
    if (qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
D
Daniel P. Berrange 已提交
4066
                              priv->monJSON, qemuCmdFlags, &argv, &progenv,
4067
                              &vmfds, &nvmfds, migrateFrom,
C
Chris Lalancette 已提交
4068 4069 4070 4071
                              vm->current_snapshot) < 0)
        goto cleanup;

    if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
4072
        goto cleanup;
4073

4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089
    /* 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;
    }

4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102
    if ((timestamp = virTimestamp()) == NULL) {
        virReportOOMError();
        goto cleanup;
    } else {
        if (safewrite(logfile, timestamp, strlen(timestamp)) < 0 ||
            safewrite(logfile, START_POSTFIX, strlen(START_POSTFIX)) < 0) {
            VIR_WARN("Unable to write timestamp to logfile: %s",
                     virStrerror(errno, ebuf, sizeof ebuf));
        }

        VIR_FREE(timestamp);
    }

4103
    tmp = progenv;
4104

4105
    while (*tmp) {
4106
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
4107
            VIR_WARN("Unable to write envv to logfile: %s",
4108
                     virStrerror(errno, ebuf, sizeof ebuf));
4109
        if (safewrite(logfile, " ", 1) < 0)
4110
            VIR_WARN("Unable to write envv to logfile: %s",
4111
                     virStrerror(errno, ebuf, sizeof ebuf));
4112 4113
        tmp++;
    }
4114 4115
    tmp = argv;
    while (*tmp) {
4116
        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
4117
            VIR_WARN("Unable to write argv to logfile: %s",
4118
                     virStrerror(errno, ebuf, sizeof ebuf));
4119
        if (safewrite(logfile, " ", 1) < 0)
4120
            VIR_WARN("Unable to write argv to logfile: %s",
4121
                     virStrerror(errno, ebuf, sizeof ebuf));
4122 4123
        tmp++;
    }
4124
    if (safewrite(logfile, "\n", 1) < 0)
4125
        VIR_WARN("Unable to write argv to logfile: %s",
4126
                 virStrerror(errno, ebuf, sizeof ebuf));
4127

4128
    if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
4129
        VIR_WARN("Unable to seek to end of logfile: %s",
4130
                 virStrerror(errno, ebuf, sizeof ebuf));
4131

4132 4133
    for (i = 0 ; i < nvmfds ; i++)
        FD_SET(vmfds[i], &keepfd);
4134

4135 4136 4137 4138 4139 4140 4141
    VIR_DEBUG("Clear emulator capabilities: %d",
              driver->clearEmulatorCapabilities);
    runflags = VIR_EXEC_NONBLOCK;
    if (driver->clearEmulatorCapabilities) {
        runflags |= VIR_EXEC_CLEAR_CAPS;
    }

4142
    ret = virExecDaemonize(argv, progenv, &keepfd, &child,
4143
                           stdin_fd, &logfile, &logfile,
4144
                           runflags,
4145 4146 4147
                           qemudSecurityHook, &hookData,
                           pidfile);
    VIR_FREE(pidfile);
G
Guido Günther 已提交
4148 4149 4150

    /* wait for qemu process to to show up */
    if (ret == 0) {
4151
        if (virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) {
4152 4153
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Domain %s didn't show up\n"), vm->def->name);
4154
            ret = -1;
G
Guido Günther 已提交
4155
        }
4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166
    } 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;
    }
4167

4168 4169 4170
    if (migrateFrom)
        start_paused = true;
    vm->state = start_paused ? VIR_DOMAIN_PAUSED : VIR_DOMAIN_RUNNING;
4171

4172
    for (i = 0 ; argv[i] ; i++)
4173 4174
        VIR_FREE(argv[i]);
    VIR_FREE(argv);
4175

4176 4177 4178 4179
    for (i = 0 ; progenv[i] ; i++)
        VIR_FREE(progenv[i]);
    VIR_FREE(progenv);

4180
    if (ret == -1) /* The VM failed to start; tear filters before taps */
4181
        virDomainConfVMNWFilterTeardown(vm);
4182

4183 4184
    if (vmfds) {
        for (i = 0 ; i < nvmfds ; i++) {
4185
            VIR_FORCE_CLOSE(vmfds[i]);
4186
        }
4187
        VIR_FREE(vmfds);
4188 4189
    }

4190
    if (ret == -1) /* The VM failed to start */
4191 4192
        goto cleanup;

4193
    DEBUG0("Waiting for monitor to show up");
4194
    if (qemudWaitForMonitor(driver, vm, pos) < 0)
4195
        goto cleanup;
4196

4197
    DEBUG0("Detecting VCPU PIDs");
4198
    if (qemuDetectVcpuPIDs(driver, vm) < 0)
4199
        goto cleanup;
4200

4201
    DEBUG0("Setting any required VM passwords");
4202
    if (qemuInitPasswords(conn, driver, vm, qemuCmdFlags) < 0)
4203
        goto cleanup;
4204

D
Daniel P. Berrange 已提交
4205 4206 4207
    /* 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)) {
4208
        DEBUG0("Determining domain device PCI addresses");
D
Daniel P. Berrange 已提交
4209
        if (qemuInitPCIAddresses(driver, vm) < 0)
4210
            goto cleanup;
D
Daniel P. Berrange 已提交
4211
    }
4212

4213
    DEBUG0("Setting initial memory amount");
4214
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
4215
    if (qemuMonitorSetBalloon(priv->mon, vm->def->mem.cur_balloon) < 0) {
4216
        qemuDomainObjExitMonitorWithDriver(driver, vm);
4217
        goto cleanup;
4218
    }
4219

4220
    if (!start_paused) {
4221
        DEBUG0("Starting domain CPUs");
4222 4223 4224
        /* Allow the CPUS to start executing */
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
            if (virGetLastError() == NULL)
4225 4226
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("resume operation failed"));
4227
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4228
            goto cleanup;
4229 4230
        }
    }
4231
    qemuDomainObjExitMonitorWithDriver(driver, vm);
4232

4233

4234
    DEBUG0("Writing domain status to disk");
4235
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
4236
        goto cleanup;
4237

4238 4239 4240 4241 4242
    /* Do this last, since it depends on domain being active */
    DEBUG0("Setting running domain def as transient");
    if (virDomainObjSetDefTransient(driver->caps, vm) < 0)
        goto cleanup;

4243
    VIR_FORCE_CLOSE(logfile);
4244

4245
    return 0;
4246 4247

cleanup:
4248 4249 4250
    /* 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 */
4251
    qemudShutdownVMDaemon(driver, vm, 0);
4252

4253
    VIR_FORCE_CLOSE(logfile);
4254 4255

    return -1;
4256 4257
}

4258
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
4259 4260
                                  virDomainObjPtr vm,
                                  int migrated) {
D
Daniel P. Berrange 已提交
4261
    int ret;
4262
    int retries = 0;
4263
    qemuDomainObjPrivatePtr priv = vm->privateData;
4264
    virErrorPtr orig_err;
4265 4266
    virDomainDefPtr def;
    int i;
4267 4268 4269
    int logfile = -1;
    char *timestamp;
    char ebuf[1024];
D
Daniel P. Berrange 已提交
4270

4271 4272
    VIR_DEBUG("Shutting down VM '%s' pid=%d migrated=%d",
              vm->def->name, vm->pid, migrated);
4273

4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297
    if ((logfile = qemudLogFD(driver, vm->def->name)) < 0) {
        /* To not break the normal domain shutdown process, skip the
         * timestamp log writing if failed on opening log file. */
        VIR_WARN("Unable to open logfile: %s",
                  virStrerror(errno, ebuf, sizeof ebuf));
    } else {
        if ((timestamp = virTimestamp()) == NULL) {
            virReportOOMError();
        } else {
            if (safewrite(logfile, timestamp, strlen(timestamp)) < 0 ||
                safewrite(logfile, SHUTDOWN_POSTFIX,
                          strlen(SHUTDOWN_POSTFIX)) < 0) {
                VIR_WARN("Unable to write timestamp to logfile: %s",
                         virStrerror(errno, ebuf, sizeof ebuf));
            }

            VIR_FREE(timestamp);
        }

        if (VIR_CLOSE(logfile) < 0)
             VIR_WARN("Unable to close logfile: %s",
                      virStrerror(errno, ebuf, sizeof ebuf));
    }

4298 4299 4300 4301
    /* This method is routinely used in clean up paths. Disable error
     * reporting so we don't squash a legit error. */
    orig_err = virSaveLastError();

4302
    virDomainConfVMNWFilterTeardown(vm);
S
Stefan Berger 已提交
4303

4304
    if (driver->macFilter) {
4305
        def = vm->def;
4306 4307 4308 4309
        for (i = 0 ; i < def->nnets ; i++) {
            virDomainNetDefPtr net = def->nets[i];
            if (net->ifname == NULL)
                continue;
4310
            if ((errno = networkDisallowMacOnPort(driver, net->ifname,
4311
                                                  net->mac))) {
4312
                virReportSystemError(errno,
4313 4314 4315 4316 4317 4318
             _("failed to remove ebtables rule to allow MAC address on  '%s'"),
                                     net->ifname);
            }
        }
    }

4319
    /* This will safely handle a non-running guest with pid=0 or pid=-1*/
G
Guido Günther 已提交
4320 4321
    if (virKillProcess(vm->pid, 0) == 0 &&
        virKillProcess(vm->pid, SIGTERM) < 0)
4322
        virReportSystemError(errno,
4323 4324
                             _("Failed to send SIGTERM to %s (%d)"),
                             vm->def->name, vm->pid);
4325

4326 4327
    if (priv->mon)
        qemuMonitorClose(priv->mon);
4328

4329 4330 4331 4332 4333
    if (priv->monConfig) {
        if (priv->monConfig->type == VIR_DOMAIN_CHR_TYPE_UNIX)
            unlink(priv->monConfig->data.nix.path);
        virDomainChrDefFree(priv->monConfig);
        priv->monConfig = NULL;
4334 4335
    }

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

4339 4340 4341 4342 4343 4344 4345 4346 4347 4348
    /* 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);
    }

4349
    /* Reset Security Labels */
4350
    if (driver->securityDriver &&
4351
        driver->securityDriver->domainRestoreSecurityAllLabel)
4352 4353
        driver->securityDriver->domainRestoreSecurityAllLabel(driver->securityDriver,
                                                              vm, migrated);
4354 4355
    if (driver->securityDriver &&
        driver->securityDriver->domainReleaseSecurityLabel)
4356 4357
        driver->securityDriver->domainReleaseSecurityLabel(driver->securityDriver,
                                                           vm);
4358

4359 4360 4361 4362 4363 4364 4365
    /* 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 已提交
4366
    virDomainDefClearDeviceAliases(vm->def);
4367 4368 4369 4370 4371
    if (!priv->persistentAddrs) {
        virDomainDefClearPCIAddresses(vm->def);
        qemuDomainPCIAddressSetFree(priv->pciaddrs);
        priv->pciaddrs = NULL;
    }
4372

4373
    qemuDomainReAttachHostDevices(driver, vm->def);
4374

S
Stefan Berger 已提交
4375 4376 4377 4378
#if WITH_MACVTAP
    def = vm->def;
    for (i = 0; i < def->nnets; i++) {
        virDomainNetDefPtr net = def->nets[i];
4379
        if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
4380
            delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
4381
                       &net->data.direct.virtPortProfile);
4382 4383
            VIR_FREE(net->ifname);
        }
S
Stefan Berger 已提交
4384 4385 4386
    }
#endif

4387
retry:
4388
    if ((ret = qemuRemoveCgroup(driver, vm, 0)) < 0) {
4389 4390 4391 4392 4393 4394 4395 4396
        if (ret == -EBUSY && (retries++ < 5)) {
            usleep(200*1000);
            goto retry;
        }
        VIR_WARN("Failed to remove cgroup for %s",
                 vm->def->name);
    }

4397
    qemudRemoveDomainStatus(driver, vm);
D
Daniel P. Berrange 已提交
4398

4399 4400 4401 4402 4403 4404
    /* 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 &&
4405
        vm->def->graphics[0]->data.vnc.port >= QEMU_VNC_PORT_MIN) {
4406 4407 4408 4409 4410 4411 4412 4413
        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);
       }
    }

4414
    vm->pid = -1;
4415
    vm->def->id = -1;
4416
    vm->state = VIR_DOMAIN_SHUTOFF;
4417 4418
    VIR_FREE(priv->vcpupids);
    priv->nvcpupids = 0;
4419 4420

    if (vm->newDef) {
4421
        virDomainDefFree(vm->def);
4422
        vm->def = vm->newDef;
4423
        vm->def->id = -1;
4424 4425
        vm->newDef = NULL;
    }
4426 4427 4428 4429 4430

    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
4431 4432
}

4433
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
4434
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
4435
                                  int flags ATTRIBUTE_UNUSED) {
4436
    if (conn->uri == NULL) {
4437 4438 4439
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

4440
        conn->uri = xmlParseURI(qemu_driver->privileged ?
4441 4442
                                "qemu:///system" :
                                "qemu:///session");
4443
        if (!conn->uri) {
4444
            virReportOOMError();
4445 4446
            return VIR_DRV_OPEN_ERROR;
        }
4447 4448 4449 4450 4451 4452 4453 4454 4455 4456
    } 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;

4457
        if (qemu_driver == NULL) {
4458 4459
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("qemu state driver is not active"));
4460 4461 4462
            return VIR_DRV_OPEN_ERROR;
        }

4463
        if (conn->uri->path == NULL) {
4464 4465 4466 4467 4468
            qemuReportError(VIR_ERR_INTERNAL_ERROR,
                            _("no QEMU URI path given, try %s"),
                            qemu_driver->privileged
                            ? "qemu:///system"
                            : "qemu:///session");
4469 4470 4471
                return VIR_DRV_OPEN_ERROR;
        }

4472
        if (qemu_driver->privileged) {
4473 4474
            if (STRNEQ (conn->uri->path, "/system") &&
                STRNEQ (conn->uri->path, "/session")) {
4475 4476 4477
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///system"),
                                conn->uri->path);
4478 4479 4480 4481
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
4482 4483 4484
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected QEMU URI path '%s', try qemu:///session"),
                                conn->uri->path);
4485 4486 4487
                return VIR_DRV_OPEN_ERROR;
            }
        }
4488 4489 4490 4491 4492 4493 4494
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
4495
    struct qemud_driver *driver = conn->privateData;
4496 4497

    /* Get rid of callbacks registered for this conn */
4498
    qemuDriverLock(driver);
4499
    virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
4500
    qemuDriverUnlock(driver);
4501 4502 4503 4504 4505 4506

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
4507 4508 4509 4510 4511
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
4512 4513 4514 4515 4516
    case VIR_DRV_FEATURE_MIGRATION_V2:
    case VIR_DRV_FEATURE_MIGRATION_P2P:
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
4517 4518 4519
    }
}

4520
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
4521
    return "QEMU";
4522 4523
}

4524

4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537
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;
}


4538 4539 4540 4541
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
4542

4543 4544
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
4545
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
4546
        return -1;
4547 4548 4549 4550 4551 4552
    }

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

4553
    VIR_FORCE_CLOSE(fd);
4554 4555 4556 4557
    return maxvcpus;
}


4558
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
4559 4560 4561
    if (!type)
        return 16;

4562
    if (STRCASEEQ(type, "qemu"))
4563 4564
        return 16;

4565
    if (STRCASEEQ(type, "kvm"))
4566
        return kvmGetMaxVCPUs();
4567

4568
    if (STRCASEEQ(type, "kqemu"))
4569
        return 1;
4570

4571 4572
    qemuReportError(VIR_ERR_INVALID_ARG,
                    _("unknown type '%s'"), type);
4573 4574 4575
    return -1;
}

4576

4577
static char *qemudGetCapabilities(virConnectPtr conn) {
4578
    struct qemud_driver *driver = conn->privateData;
4579
    virCapsPtr caps = NULL;
4580
    char *xml = NULL;
4581

4582
    qemuDriverLock(driver);
4583

4584
    if ((caps = qemuCreateCapabilities(qemu_driver->caps,
4585
                                       qemu_driver)) == NULL) {
4586 4587 4588
        virCapabilitiesFree(caps);
        goto cleanup;
    }
4589

4590
    virCapabilitiesFree(qemu_driver->caps);
4591 4592 4593
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
4594
        virReportOOMError();
4595 4596

cleanup:
4597
    qemuDriverUnlock(driver);
4598

4599
    return xml;
4600 4601 4602
}


4603
static int qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, int pid, int tid) {
D
Daniel P. Berrange 已提交
4604 4605
    char proc[PATH_MAX];
    FILE *pidinfo;
4606
    unsigned long long usertime, systime;
4607 4608
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
4609

4610 4611 4612 4613 4614 4615
    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 已提交
4616 4617 4618 4619 4620
        return -1;
    }

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
4621 4622 4623 4624
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
D
Daniel P. Berrange 已提交
4625 4626 4627
        return 0;
    }

4628 4629 4630 4631 4632 4633 4634 4635 4636 4637
    /* 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) {
4638
        VIR_FORCE_FCLOSE(pidinfo);
4639 4640
        VIR_WARN0("cannot parse process status data");
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
4641 4642 4643 4644 4645 4646 4647 4648
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
4649 4650 4651 4652 4653
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

D
Daniel P. Berrange 已提交
4654

4655 4656
    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d",
              pid, tid, usertime, systime, cpu);
D
Daniel P. Berrange 已提交
4657

4658
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
4659 4660 4661 4662 4663

    return 0;
}


4664
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
4665
                                          int id) {
4666 4667 4668 4669
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

4670
    qemuDriverLock(driver);
4671
    vm  = virDomainFindByID(&driver->domains, id);
4672
    qemuDriverUnlock(driver);
4673 4674

    if (!vm) {
4675 4676
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching id %d"), id);
4677
        goto cleanup;
4678 4679
    }

4680
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4681
    if (dom) dom->id = vm->def->id;
4682 4683

cleanup:
4684 4685
    if (vm)
        virDomainObjUnlock(vm);
4686 4687
    return dom;
}
4688

4689
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
4690
                                            const unsigned char *uuid) {
4691 4692 4693
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
4694

4695
    qemuDriverLock(driver);
4696
    vm = virDomainFindByUUID(&driver->domains, uuid);
4697 4698
    qemuDriverUnlock(driver);

4699
    if (!vm) {
4700 4701
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
4702 4703
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4704
        goto cleanup;
4705 4706
    }

4707
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4708
    if (dom) dom->id = vm->def->id;
4709 4710

cleanup:
4711 4712
    if (vm)
        virDomainObjUnlock(vm);
4713 4714
    return dom;
}
4715

4716
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
4717
                                            const char *name) {
4718 4719 4720
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
4721

4722
    qemuDriverLock(driver);
4723
    vm = virDomainFindByName(&driver->domains, name);
4724 4725
    qemuDriverUnlock(driver);

4726
    if (!vm) {
4727 4728
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), name);
4729
        goto cleanup;
4730 4731
    }

4732
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4733
    if (dom) dom->id = vm->def->id;
4734 4735

cleanup:
4736 4737
    if (vm)
        virDomainObjUnlock(vm);
4738 4739 4740
    return dom;
}

4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751

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) {
4752
        qemuReportError(VIR_ERR_NO_DOMAIN, NULL);
4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772
        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) {
4773
        qemuReportError(VIR_ERR_NO_DOMAIN, NULL);
4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784
        goto cleanup;
    }
    ret = obj->persistent;

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


4785
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
4786 4787 4788
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

4789
    qemuDriverLock(driver);
4790
    if (qemudExtractVersion(driver) < 0)
4791
        goto cleanup;
4792

4793
    *version = qemu_driver->qemuVersion;
4794 4795 4796
    ret = 0;

cleanup:
4797
    qemuDriverUnlock(driver);
4798
    return ret;
D
Daniel P. Berrange 已提交
4799 4800
}

4801
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
4802
    struct qemud_driver *driver = conn->privateData;
4803
    int n;
4804

4805
    qemuDriverLock(driver);
4806
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
4807
    qemuDriverUnlock(driver);
4808

4809
    return n;
D
Daniel P. Berrange 已提交
4810
}
4811

4812
static int qemudNumDomains(virConnectPtr conn) {
4813
    struct qemud_driver *driver = conn->privateData;
4814
    int n;
4815

4816
    qemuDriverLock(driver);
4817
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
4818
    qemuDriverUnlock(driver);
4819

4820
    return n;
D
Daniel P. Berrange 已提交
4821
}
4822

4823
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
4824
                                      unsigned int flags) {
4825
    struct qemud_driver *driver = conn->privateData;
4826
    virDomainDefPtr def;
4827
    virDomainObjPtr vm = NULL;
4828
    virDomainPtr dom = NULL;
4829
    virDomainEventPtr event = NULL;
D
Daniel P. Berrange 已提交
4830

4831
    virCheckFlags(VIR_DOMAIN_START_PAUSED, NULL);
4832

4833
    qemuDriverLock(driver);
4834
    if (!(def = virDomainDefParseString(driver->caps, xml,
4835
                                        VIR_DOMAIN_XML_INACTIVE)))
4836
        goto cleanup;
4837

4838
    if (virSecurityDriverVerify(def) < 0)
4839 4840
        goto cleanup;

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

4844 4845 4846 4847 4848 4849
    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

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

4850
    if (!(vm = virDomainAssignDef(driver->caps,
4851
                                  &driver->domains,
4852
                                  def, false)))
4853 4854 4855
        goto cleanup;

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

4857 4858 4859
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup; /* XXXX free the 'vm' we created ? */

4860 4861 4862
    if (qemudStartVMDaemon(conn, driver, vm, NULL,
                           (flags & VIR_DOMAIN_START_PAUSED) != 0,
                           -1, NULL) < 0) {
4863
        qemuDomainStartAudit(vm, "booted", false);
4864 4865 4866
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
4867
        vm = NULL;
4868
        goto cleanup;
D
Daniel P. Berrange 已提交
4869
    }
4870 4871 4872 4873

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
4874
    qemuDomainStartAudit(vm, "booted", true);
D
Daniel P. Berrange 已提交
4875

4876
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
4877
    if (dom) dom->id = vm->def->id;
4878

4879 4880 4881
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4882

4883 4884
cleanup:
    virDomainDefFree(def);
4885 4886
    if (vm)
        virDomainObjUnlock(vm);
4887 4888
    if (event)
        qemuDomainEventQueue(driver, event);
4889
    qemuDriverUnlock(driver);
4890
    return dom;
D
Daniel P. Berrange 已提交
4891 4892 4893
}


4894
static int qemudDomainSuspend(virDomainPtr dom) {
4895 4896 4897
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4898
    virDomainEventPtr event = NULL;
4899
    qemuDomainObjPrivatePtr priv;
4900

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

D
Daniel P. Berrange 已提交
4904
    if (!vm) {
4905 4906
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4907 4908
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4909
        goto cleanup;
D
Daniel P. Berrange 已提交
4910
    }
D
Daniel P. Berrange 已提交
4911
    if (!virDomainObjIsActive(vm)) {
4912 4913
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4914
        goto cleanup;
D
Daniel P. Berrange 已提交
4915
    }
4916 4917 4918

    priv = vm->privateData;

4919
    if (priv->jobActive == QEMU_JOB_MIGRATION_OUT) {
4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933
        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"));
4934
            goto endjob;
4935
        }
4936 4937
        if (vm->state != VIR_DOMAIN_PAUSED) {
            int rc;
4938
            int state = vm->state;
4939

4940
            vm->state = VIR_DOMAIN_PAUSED;
4941 4942 4943
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorStopCPUs(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
4944 4945
            if (rc < 0) {
                vm->state = state;
4946
                goto endjob;
4947
            }
4948 4949 4950 4951 4952 4953 4954
            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 已提交
4955
    }
4956

4957
endjob:
4958 4959
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
4960

4961
cleanup:
4962 4963
    if (vm)
        virDomainObjUnlock(vm);
4964

4965
    if (event)
4966
        qemuDomainEventQueue(driver, event);
4967
    qemuDriverUnlock(driver);
4968
    return ret;
D
Daniel P. Berrange 已提交
4969 4970 4971
}


4972
static int qemudDomainResume(virDomainPtr dom) {
4973 4974 4975
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
4976
    virDomainEventPtr event = NULL;
4977

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

D
Daniel P. Berrange 已提交
4981
    if (!vm) {
4982 4983
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4984 4985
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
4986
        goto cleanup;
D
Daniel P. Berrange 已提交
4987
    }
4988 4989 4990 4991

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

D
Daniel P. Berrange 已提交
4992
    if (!virDomainObjIsActive(vm)) {
4993 4994
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
4995
        goto endjob;
D
Daniel P. Berrange 已提交
4996
    }
4997
    if (vm->state == VIR_DOMAIN_PAUSED) {
4998
        qemuDomainObjPrivatePtr priv = vm->privateData;
4999
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5000
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
5001
            qemuDomainObjExitMonitorWithDriver(driver, vm);
5002
            if (virGetLastError() == NULL)
5003 5004
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resume operation failed"));
5005
            goto endjob;
5006
        }
5007
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5008
        vm->state = VIR_DOMAIN_RUNNING;
5009 5010 5011
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
5012
    }
5013
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
5014
        goto endjob;
5015 5016
    ret = 0;

5017
endjob:
5018 5019
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5020

5021
cleanup:
5022 5023
    if (vm)
        virDomainObjUnlock(vm);
5024
    if (event)
5025
        qemuDomainEventQueue(driver, event);
5026
    qemuDriverUnlock(driver);
5027
    return ret;
D
Daniel P. Berrange 已提交
5028 5029 5030
}


5031
static int qemudDomainShutdown(virDomainPtr dom) {
5032 5033 5034
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5035

5036
    qemuDriverLock(driver);
5037
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5038 5039
    qemuDriverUnlock(driver);

5040
    if (!vm) {
5041 5042
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5043 5044
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5045
        goto cleanup;
5046 5047
    }

5048 5049 5050
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
5051
    if (!virDomainObjIsActive(vm)) {
5052 5053
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
5054
        goto endjob;
5055 5056
    }

5057
    qemuDomainObjPrivatePtr priv = vm->privateData;
5058 5059 5060
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorSystemPowerdown(priv->mon);
    qemuDomainObjExitMonitor(vm);
5061

5062
endjob:
5063 5064
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5065

5066
cleanup:
5067 5068
    if (vm)
        virDomainObjUnlock(vm);
5069
    return ret;
5070 5071 5072
}


5073
static int qemudDomainDestroy(virDomainPtr dom) {
5074 5075 5076
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5077
    virDomainEventPtr event = NULL;
5078

5079
    qemuDriverLock(driver);
5080
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
5081
    if (!vm) {
5082 5083
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5084 5085
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5086
        goto cleanup;
D
Daniel P. Berrange 已提交
5087
    }
5088 5089 5090 5091

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

D
Daniel P. Berrange 已提交
5092
    if (!virDomainObjIsActive(vm)) {
5093 5094
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
5095
        goto endjob;
5096
    }
5097

5098
    qemudShutdownVMDaemon(driver, vm, 0);
5099 5100 5101
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
5102 5103
    qemuDomainStopAudit(vm, "destroyed");

5104
    if (!vm->persistent) {
5105 5106 5107
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
5108 5109
        vm = NULL;
    }
5110 5111
    ret = 0;

5112
endjob:
5113 5114 5115
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5116

5117
cleanup:
5118 5119
    if (vm)
        virDomainObjUnlock(vm);
5120 5121
    if (event)
        qemuDomainEventQueue(driver, event);
5122
    qemuDriverUnlock(driver);
5123
    return ret;
D
Daniel P. Berrange 已提交
5124 5125 5126
}


5127
static char *qemudDomainGetOSType(virDomainPtr dom) {
5128 5129 5130
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
5131

5132
    qemuDriverLock(driver);
5133
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5134
    qemuDriverUnlock(driver);
5135
    if (!vm) {
5136 5137
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5138 5139
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5140
        goto cleanup;
5141 5142
    }

5143
    if (!(type = strdup(vm->def->os.type)))
5144
        virReportOOMError();
5145 5146

cleanup:
5147 5148
    if (vm)
        virDomainObjUnlock(vm);
5149 5150 5151
    return type;
}

5152 5153
/* Returns max memory in kb, 0 if error */
static unsigned long qemudDomainGetMaxMemory(virDomainPtr dom) {
5154 5155 5156
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;
5157

5158
    qemuDriverLock(driver);
5159
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5160 5161
    qemuDriverUnlock(driver);

5162
    if (!vm) {
5163 5164
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5165 5166
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5167
        goto cleanup;
5168 5169
    }

5170
    ret = vm->def->mem.max_balloon;
5171 5172

cleanup:
5173 5174
    if (vm)
        virDomainObjUnlock(vm);
5175
    return ret;
5176 5177 5178
}

static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
5179
    struct qemud_driver *driver = dom->conn->privateData;
5180
    qemuDomainObjPrivatePtr priv;
5181
    virDomainObjPtr vm;
5182
    int ret = -1, r;
5183

5184
    qemuDriverLock(driver);
5185
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5186
    qemuDriverUnlock(driver);
5187
    if (!vm) {
5188 5189
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5190 5191
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5192
        goto cleanup;
5193 5194
    }

5195
    if (newmem > vm->def->mem.max_balloon) {
5196 5197
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("cannot set memory higher than max memory"));
5198
        goto cleanup;
5199 5200
    }

5201 5202 5203
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

5204 5205 5206 5207 5208 5209
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
        goto endjob;
    }

5210 5211 5212 5213 5214 5215
    priv = vm->privateData;
    qemuDomainObjEnterMonitor(vm);
    r = qemuMonitorSetBalloon(priv->mon, newmem);
    qemuDomainObjExitMonitor(vm);
    if (r < 0)
        goto endjob;
5216

5217 5218 5219 5220 5221
    /* 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;
5222
    }
5223

5224
    ret = 0;
5225
endjob:
5226 5227
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
5228

5229
cleanup:
5230 5231
    if (vm)
        virDomainObjUnlock(vm);
5232
    return ret;
5233 5234
}

5235
static int qemudDomainGetInfo(virDomainPtr dom,
5236
                              virDomainInfoPtr info) {
5237 5238 5239
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5240 5241
    int err;
    unsigned long balloon;
5242

5243
    qemuDriverLock(driver);
5244
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5245
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
5246
    if (!vm) {
5247 5248
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5249 5250
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
5251
        goto cleanup;
D
Daniel P. Berrange 已提交
5252 5253
    }

5254
    info->state = vm->state;
D
Daniel P. Berrange 已提交
5255

D
Daniel P. Berrange 已提交
5256
    if (!virDomainObjIsActive(vm)) {
5257
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
5258
    } else {
5259
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, vm->pid, 0) < 0) {
5260
            qemuReportError(VIR_ERR_OPERATION_FAILED, ("cannot read cputime for domain"));
5261
            goto cleanup;
D
Daniel P. Berrange 已提交
5262 5263 5264
        }
    }

5265
    info->maxMem = vm->def->mem.max_balloon;
5266

D
Daniel P. Berrange 已提交
5267
    if (virDomainObjIsActive(vm)) {
5268
        qemuDomainObjPrivatePtr priv = vm->privateData;
5269 5270 5271

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
5272
            info->memory = vm->def->mem.max_balloon;
5273
        } else if (!priv->jobActive) {
5274 5275
            if (qemuDomainObjBeginJob(vm) < 0)
                goto cleanup;
5276 5277 5278 5279 5280 5281 5282 5283 5284
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
                qemuDomainObjEnterMonitor(vm);
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
                qemuDomainObjExitMonitor(vm);
            }
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
5285 5286 5287
                goto cleanup;
            }

5288 5289
            if (err < 0)
                goto cleanup;
5290 5291
            if (err == 0)
                /* Balloon not supported, so maxmem is always the allocation */
5292
                info->memory = vm->def->mem.max_balloon;
5293 5294 5295
            else
                info->memory = balloon;
        } else {
5296
            info->memory = vm->def->mem.cur_balloon;
5297
        }
5298
    } else {
5299
        info->memory = vm->def->mem.cur_balloon;
5300 5301
    }

5302
    info->nrVirtCpu = vm->def->vcpus;
5303 5304 5305
    ret = 0;

cleanup:
5306 5307
    if (vm)
        virDomainObjUnlock(vm);
5308
    return ret;
D
Daniel P. Berrange 已提交
5309 5310 5311
}


5312 5313 5314 5315 5316 5317 5318 5319
/** qemuDomainMigrateOffline:
 * Pause domain for non-live migration.
 */
static int
qemuDomainMigrateOffline(struct qemud_driver *driver,
                         virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
5320
    int state = vm->state;
5321 5322
    int ret;

5323
    vm->state = VIR_DOMAIN_PAUSED;
5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335
    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);
5336 5337
    } else
        vm->state = state;
5338 5339 5340 5341 5342

    return ret;
}


5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356
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 */
5357
        struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
5358 5359 5360
        struct timeval now;
        int rc;

5361 5362 5363 5364 5365 5366
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit during migration"));
            goto cleanup;
        }

5367 5368
        if (priv->jobSignals & QEMU_JOB_SIGNAL_CANCEL) {
            priv->jobSignals ^= QEMU_JOB_SIGNAL_CANCEL;
5369 5370 5371 5372 5373 5374 5375
            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");
            }
5376 5377 5378 5379 5380
        } 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");
5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391
        } 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");
5392 5393
        }

5394 5395 5396 5397 5398 5399 5400 5401 5402
        /* 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;
        }

5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474
        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;
}


5475
#define QEMUD_SAVE_MAGIC "LibvirtQemudSave"
5476 5477 5478
#define QEMUD_SAVE_VERSION 2

enum qemud_save_formats {
5479 5480 5481
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
5482 5483
    /*
     * Deprecated by xz and never used as part of a release
5484
     * QEMUD_SAVE_FORMAT_LZMA
5485 5486
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
5487
    QEMUD_SAVE_FORMAT_LZOP = 4,
5488 5489 5490
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
5491 5492

    QEMUD_SAVE_FORMAT_LAST
5493
};
5494

5495 5496 5497 5498 5499
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
5500 5501
              "xz",
              "lzop")
5502

5503 5504 5505 5506 5507
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
    int version;
    int xml_len;
    int was_running;
5508 5509
    int compressed;
    int unused[15];
5510 5511
};

5512 5513 5514 5515 5516 5517 5518
struct fileOpHookData {
    virDomainPtr dom;
    const char *path;
    char *xml;
    struct qemud_save_header *header;
};

5519
/* return -errno on failure, or 0 on success */
5520 5521 5522 5523 5524
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)) {
5525
        ret = -errno;
5526
        qemuReportError(VIR_ERR_OPERATION_FAILED,
5527 5528
                        _("failed to write header to domain save file '%s'"),
                        hdata->path);
5529 5530 5531 5532
        goto endjob;
    }

    if (safewrite(fd, hdata->xml, hdata->header->xml_len) != hdata->header->xml_len) {
5533
        ret = -errno;
5534 5535 5536 5537 5538 5539 5540 5541
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                         _("failed to write xml to '%s'"), hdata->path);
        goto endjob;
    }
endjob:
    return ret;
}

5542 5543 5544
/* this internal function expects the driver lock to already be held on entry */
static int qemudDomainSaveFlag(struct qemud_driver *driver, virDomainPtr dom,
                               virDomainObjPtr vm, const char *path,
5545
                               int compressed)
5546
{
5547
    char *xml = NULL;
5548
    struct qemud_save_header header;
5549 5550
    struct fileOpHookData hdata;
    int bypassSecurityDriver = 0;
5551
    int ret = -1;
5552
    int rc;
5553
    virDomainEventPtr event = NULL;
5554
    qemuDomainObjPrivatePtr priv;
5555 5556
    struct stat sb;
    int is_reg = 0;
5557
    unsigned long long offset;
5558
    virCgroupPtr cgroup = NULL;
5559 5560 5561 5562 5563

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

5564
    header.compressed = compressed;
5565

5566
    priv = vm->privateData;
5567

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

D
Daniel P. Berrange 已提交
5571
    if (!virDomainObjIsActive(vm)) {
5572 5573
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
5574
        goto endjob;
D
Daniel P. Berrange 已提交
5575
    }
5576

5577 5578 5579
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

5580 5581 5582
    /* Pause */
    if (vm->state == VIR_DOMAIN_RUNNING) {
        header.was_running = 1;
5583
        vm->state = VIR_DOMAIN_PAUSED;
5584
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5585
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
5586
            qemuDomainObjExitMonitorWithDriver(driver, vm);
5587
            vm->state = VIR_DOMAIN_RUNNING;
5588
            goto endjob;
5589
        }
5590
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5591 5592 5593 5594 5595 5596

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto endjob;
        }
5597 5598 5599
    }

    /* Get XML for the domain */
5600
    xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
5601
    if (!xml) {
5602 5603
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
5604
        goto endjob;
5605 5606 5607
    }
    header.xml_len = strlen(xml) + 1;

5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620
    /* 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);
    }

5621 5622 5623 5624 5625
    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
5626 5627
     * it by padding the XML string with NULLs.
     */
5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640
    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;
    }
5641

5642 5643 5644 5645 5646 5647
    /* Setup hook data needed by virFileOperation hook function */
    hdata.dom = dom;
    hdata.path = path;
    hdata.xml = xml;
    hdata.header = &header;

5648 5649
    /* Write header to file, followed by XML */

5650
    /* First try creating the file as root */
5651 5652 5653 5654
    if (!is_reg) {
        int fd = open(path, O_WRONLY | O_TRUNC);
        if (fd < 0) {
            virReportSystemError(errno, _("unable to open %s"), path);
5655 5656
            goto endjob;
        }
5657
        if (qemudDomainSaveFileOpHook(fd, &hdata) < 0) {
5658
            VIR_FORCE_CLOSE(fd);
5659 5660
            goto endjob;
        }
5661
        if (VIR_CLOSE(fd) < 0) {
5662
            virReportSystemError(errno, _("unable to close %s"), path);
5663 5664
            goto endjob;
        }
5665 5666 5667 5668 5669
    } else {
        if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
                                  S_IRUSR|S_IWUSR,
                                  getuid(), getgid(),
                                  qemudDomainSaveFileOpHook, &hdata,
5670
                                  0)) < 0) {
5671
            /* If we failed as root, and the error was permission-denied
5672 5673
               (EACCES or EPERM), assume it's on a network-connected share
               where root access is restricted (eg, root-squashed NFS). If the
5674 5675 5676 5677
               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 */

5678
            if (((rc != -EACCES) && (rc != -EPERM)) ||
5679
                driver->user == getuid()) {
5680
                virReportSystemError(-rc, _("Failed to create domain save file '%s'"),
5681 5682 5683
                                     path);
                goto endjob;
            }
5684

5685
            /* On Linux we can also verify the FS-type of the directory. */
5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703
            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 */
5704
                   virReportSystemError(-rc,
5705 5706 5707 5708
                                        _("Failed to create domain save file '%s'"),
                                        path);
                   goto endjob;
                   break;
5709 5710 5711

            }

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

5714 5715 5716 5717
            if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
                                       S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
                                       driver->user, driver->group,
                                       qemudDomainSaveFileOpHook, &hdata,
5718 5719
                                       VIR_FILE_OP_AS_UID)) < 0) {
                virReportSystemError(-rc, _("Error from child process creating '%s'"),
5720
                                 path);
5721 5722
                goto endjob;
            }
5723

5724 5725 5726
            /* 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 */
5727

5728 5729
            bypassSecurityDriver = 1;
        }
5730
    }
5731

5732

5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749
    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;
        }
    }

5750 5751
    if ((!bypassSecurityDriver) &&
        driver->securityDriver &&
5752
        driver->securityDriver->domainSetSavedStateLabel &&
5753 5754
        driver->securityDriver->domainSetSavedStateLabel(driver->securityDriver,
                                                         vm, path) == -1)
5755 5756
        goto endjob;

5757 5758
    if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = { "cat", NULL };
M
Matthias Bolte 已提交
5759
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5760 5761 5762
        rc = qemuMonitorMigrateToFile(priv->mon,
                                      QEMU_MONITOR_MIGRATE_BACKGROUND,
                                      args, path, offset);
M
Matthias Bolte 已提交
5763
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5764
    } else {
5765
        const char *prog = qemudSaveCompressionTypeToString(header.compressed);
5766 5767 5768 5769 5770
        const char *args[] = {
            prog,
            "-c",
            NULL
        };
M
Matthias Bolte 已提交
5771
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
5772 5773 5774
        rc = qemuMonitorMigrateToFile(priv->mon,
                                      QEMU_MONITOR_MIGRATE_BACKGROUND,
                                      args, path, offset);
M
Matthias Bolte 已提交
5775
        qemuDomainObjExitMonitorWithDriver(driver, vm);
5776 5777
    }

5778 5779 5780 5781 5782
    if (rc < 0)
        goto endjob;

    rc = qemuDomainWaitForMigrationComplete(driver, vm);

5783
    if (rc < 0)
5784
        goto endjob;
5785

5786 5787
    if ((!bypassSecurityDriver) &&
        driver->securityDriver &&
5788
        driver->securityDriver->domainRestoreSavedStateLabel &&
5789 5790
        driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver,
                                                             vm, path) == -1)
5791
        VIR_WARN("failed to restore save state label on %s", path);
5792

5793 5794
    if (cgroup != NULL) {
        rc = virCgroupDenyDevicePath(cgroup, path);
5795 5796 5797
        if (rc != 0)
            VIR_WARN("Unable to deny device %s for %s %d",
                     path, vm->def->name, rc);
5798 5799
    }

5800 5801
    ret = 0;

5802
    /* Shut it down */
5803
    qemudShutdownVMDaemon(driver, vm, 0);
5804
    qemuDomainStopAudit(vm, "saved");
5805 5806 5807
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
5808
    if (!vm->persistent) {
5809 5810 5811
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains,
                                    vm);
5812 5813
        vm = NULL;
    }
5814

5815
endjob:
5816
    if (vm) {
5817
        if (ret != 0) {
5818
            if (header.was_running && virDomainObjIsActive(vm)) {
5819 5820 5821 5822 5823 5824 5825 5826
                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;
            }
5827

5828 5829 5830 5831 5832
            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);
5833
            }
5834 5835 5836 5837

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

5843
        if (qemuDomainObjEndJob(vm) == 0)
5844
            vm = NULL;
5845
    }
5846

5847 5848
cleanup:
    VIR_FREE(xml);
5849
    if (ret != 0 && is_reg)
5850
        unlink(path);
5851 5852
    if (event)
        qemuDomainEventQueue(driver, event);
5853
    virCgroupFree(&cgroup);
5854
    return ret;
D
Daniel P. Berrange 已提交
5855 5856
}

5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872
/* Returns true if a compression program is available in PATH */
static bool qemudCompressProgramAvailable(enum qemud_save_formats compress)
{
    const char *prog;
    char *c;

    if (compress == QEMUD_SAVE_FORMAT_RAW)
        return true;
    prog = qemudSaveCompressionTypeToString(compress);
    c = virFindFileInPath(prog);
    if (!c)
        return false;
    VIR_FREE(c);
    return true;
}

5873 5874 5875 5876
static int qemudDomainSave(virDomainPtr dom, const char *path)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int compressed;
5877 5878 5879 5880
    int ret = -1;
    virDomainObjPtr vm = NULL;

    qemuDriverLock(driver);
5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891

    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;
        }
5892 5893 5894 5895 5896 5897
        if (!qemudCompressProgramAvailable(compressed)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Compression program for image format "
                                    "in configuration file isn't available"));
            return -1;
        }
5898 5899
    }

5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916
    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;
    }

    ret = qemudDomainSaveFlag(driver, dom, vm, path, compressed);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    return ret;
5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939
}

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;

5940
    virCheckFlags(0, -1);
5941 5942 5943 5944 5945 5946 5947 5948

    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);
5949
        goto cleanup;
5950 5951 5952 5953
    }

    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
5954
        goto cleanup;
5955 5956 5957 5958

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

    compressed = QEMUD_SAVE_FORMAT_RAW;
5959
    ret = qemudDomainSaveFlag(driver, dom, vm, name, compressed);
5960 5961 5962 5963 5964

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
5965 5966 5967
    VIR_FREE(name);

    return ret;
5968 5969 5970 5971 5972 5973 5974 5975 5976 5977
}

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

5978
    virCheckFlags(0, -1);
5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011

    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;

6012
    virCheckFlags(0, -1);
6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036

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

P
Paolo Bonzini 已提交
6038 6039 6040 6041 6042 6043
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;
6044
    int ret = -1, fd = -1;
6045
    virDomainEventPtr event = NULL;
6046
    int compress;
6047
    qemuDomainObjPrivatePtr priv;
6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060
    /*
     * We reuse "save" flag for "dump" here. Then, we can support the same
     * format in "save" and "dump".
     */
    compress = QEMUD_SAVE_FORMAT_RAW;
    if (driver->dumpImageFormat) {
        compress = qemudSaveCompressionTypeFromString(driver->dumpImageFormat);
        if (compress < 0) {
           qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Invalid dump image format specified in "
                             "configuration file"));
           return -1;
        }
6061 6062 6063 6064 6065 6066
        if (!qemudCompressProgramAvailable(compress)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("Compression program for dump image format "
                                    "in configuration file isn't available"));
            return -1;
        }
6067
    }
P
Paolo Bonzini 已提交
6068 6069 6070 6071 6072 6073 6074

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

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6075 6076
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
6077 6078
        goto cleanup;
    }
6079
    priv = vm->privateData;
P
Paolo Bonzini 已提交
6080

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

D
Daniel P. Berrange 已提交
6084
    if (!virDomainObjIsActive(vm)) {
6085 6086
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
6087
        goto endjob;
P
Paolo Bonzini 已提交
6088 6089
    }

6090 6091
    /* Create an empty file with appropriate ownership.  */
    if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
6092 6093
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("failed to create '%s'"), path);
6094 6095 6096
        goto endjob;
    }

6097
    if (VIR_CLOSE(fd) < 0) {
6098
        virReportSystemError(errno,
6099 6100 6101 6102 6103 6104 6105
                             _("unable to save file %s"),
                             path);
        goto endjob;
    }

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSavedStateLabel &&
6106 6107
        driver->securityDriver->domainSetSavedStateLabel(driver->securityDriver,
                                                         vm, path) == -1)
6108 6109
        goto endjob;

P
Paolo Bonzini 已提交
6110 6111
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
P
Paolo Bonzini 已提交
6112 6113 6114
    resume = (vm->state == VIR_DOMAIN_RUNNING);

    /* Pause domain for non-live dump */
P
Paolo Bonzini 已提交
6115
    if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
6116
        vm->state = VIR_DOMAIN_PAUSED;
6117
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
6118
        if (qemuMonitorStopCPUs(priv->mon) < 0) {
6119
            qemuDomainObjExitMonitorWithDriver(driver, vm);
6120
            vm->state = VIR_DOMAIN_RUNNING;
6121
            goto endjob;
6122
        }
6123
        qemuDomainObjExitMonitorWithDriver(driver, vm);
P
Paolo Bonzini 已提交
6124
        paused = 1;
6125 6126 6127 6128 6129 6130

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

6133
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152
    if (compress == QEMUD_SAVE_FORMAT_RAW) {
        const char *args[] = {
            "cat",
            NULL,
        };
        ret = qemuMonitorMigrateToFile(priv->mon,
                                       QEMU_MONITOR_MIGRATE_BACKGROUND,
                                       args, path, 0);
    } else {
        const char *prog = qemudSaveCompressionTypeToString(compress);
        const char *args[] = {
            prog,
            "-c",
            NULL,
        };
        ret = qemuMonitorMigrateToFile(priv->mon,
                                       QEMU_MONITOR_MIGRATE_BACKGROUND,
                                       args, path, 0);
    }
6153
    qemuDomainObjExitMonitorWithDriver(driver, vm);
6154 6155 6156 6157 6158 6159 6160 6161 6162
    if (ret < 0)
        goto endjob;

    ret = qemuDomainWaitForMigrationComplete(driver, vm);

    if (ret < 0)
        goto endjob;

    paused = 1;
6163 6164 6165

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSavedStateLabel &&
6166 6167
        driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver,
                                                             vm, path) == -1)
6168 6169 6170
        goto endjob;

endjob:
6171
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
6172
        qemudShutdownVMDaemon(driver, vm, 0);
6173
        qemuDomainStopAudit(vm, "crashed");
6174 6175 6176 6177 6178
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
6179 6180 6181
    /* 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.  */
6182
    else if (resume && paused && virDomainObjIsActive(vm)) {
6183
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
6184
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
6185
            if (virGetLastError() == NULL)
6186 6187
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
6188
        }
6189
        qemuDomainObjExitMonitorWithDriver(driver, vm);
6190
        vm->state = VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
6191
    }
6192

6193 6194
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
6195
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
6196 6197 6198 6199
        virDomainRemoveInactive(&driver->domains,
                                vm);
        vm = NULL;
    }
6200 6201

cleanup:
6202 6203
    if (ret != 0)
        unlink(path);
P
Paolo Bonzini 已提交
6204 6205
    if (vm)
        virDomainObjUnlock(vm);
6206 6207
    if (event)
        qemuDomainEventQueue(driver, event);
6208
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
6209 6210 6211 6212
    return ret;
}


6213 6214 6215 6216 6217 6218
static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int i, rc;
    int ret = -1;

6219 6220
    qemuDomainObjEnterMonitor(vm);

6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250
    /* 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:
6251
    qemuDomainObjExitMonitor(vm);
6252 6253 6254 6255 6256 6257 6258 6259 6260
    return ret;

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


6261 6262 6263 6264
static int
qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                         unsigned int flags)
{
6265 6266
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6267
    virDomainDefPtr persistentDef;
6268 6269
    const char * type;
    int max;
6270
    int ret = -1;
6271

6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    /* At least one of LIVE or CONFIG must be set.  MAXIMUM cannot be
     * mixed with LIVE.  */
    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 ||
        (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
         (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid flag combination: (0x%x)"), flags);
        return -1;
    }
    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("argument out of range: %d"), nvcpus);
6288 6289 6290
        return -1;
    }

6291
    qemuDriverLock(driver);
6292
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
6293 6294
    qemuDriverUnlock(driver);

6295
    if (!vm) {
6296 6297
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6298 6299
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6300
        goto cleanup;
6301 6302
    }

6303 6304 6305
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

6306
    if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_LIVE)) {
6307 6308
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("domain is not running"));
6309
        goto endjob;
6310 6311
    }

6312 6313 6314 6315 6316 6317
    if (!vm->persistent && (flags & VIR_DOMAIN_VCPU_CONFIG)) {
        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot change persistent config of a transient domain"));
        goto endjob;
    }

6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330
    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;
    }

C
Cole Robinson 已提交
6331
    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM) && vm->def->maxvcpus < max) {
6332 6333 6334
        max = vm->def->maxvcpus;
    }

6335 6336 6337 6338 6339 6340 6341
    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;
    }

6342 6343 6344
    if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
        goto endjob;

6345 6346
    switch (flags) {
    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG:
6347 6348 6349
        persistentDef->maxvcpus = nvcpus;
        if (nvcpus < persistentDef->vcpus)
            persistentDef->vcpus = nvcpus;
6350 6351 6352 6353
        ret = 0;
        break;

    case VIR_DOMAIN_VCPU_CONFIG:
6354
        persistentDef->vcpus = nvcpus;
6355 6356 6357 6358 6359 6360 6361 6362 6363
        ret = 0;
        break;

    case VIR_DOMAIN_VCPU_LIVE:
        ret = qemudDomainHotplugVcpus(vm, nvcpus);
        break;

    case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG:
        ret = qemudDomainHotplugVcpus(vm, nvcpus);
6364 6365 6366
        if (ret == 0) {
            persistentDef->vcpus = nvcpus;
        }
6367 6368
        break;
    }
6369

6370 6371 6372 6373
    /* Save the persistent config to disk */
    if (flags & VIR_DOMAIN_VCPU_CONFIG)
        ret = virDomainSaveConfig(driver->configDir, persistentDef);

6374 6375 6376
endjob:
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
6377

6378
cleanup:
6379 6380
    if (vm)
        virDomainObjUnlock(vm);
6381
    return ret;
6382 6383
}

6384 6385 6386 6387 6388 6389
static int
qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
    return qemudDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

6390 6391 6392 6393 6394 6395

static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
6396 6397
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6398
    int maxcpu, hostcpus;
6399
    virNodeInfo nodeinfo;
6400
    int ret = -1;
6401
    qemuDomainObjPrivatePtr priv;
6402

6403
    qemuDriverLock(driver);
6404
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
6405 6406
    qemuDriverUnlock(driver);

6407 6408 6409
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6410 6411
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6412 6413 6414
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
6415
    if (!virDomainObjIsActive(vm)) {
6416 6417
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",_("cannot pin vcpus on an inactive domain"));
6418
        goto cleanup;
6419 6420
    }

6421 6422 6423
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
6424 6425 6426
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("vcpu number out of range %d > %d"),
                        vcpu, priv->nvcpupids);
6427
        goto cleanup;
6428 6429
    }

6430
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
6431
        goto cleanup;
6432

6433
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
6434
    maxcpu = maplen * 8;
6435 6436
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
6437

6438 6439
    if (priv->vcpupids != NULL) {
        if (virProcessInfoSetAffinity(priv->vcpupids[vcpu],
6440
                                      cpumap, maplen, maxcpu) < 0)
6441
            goto cleanup;
6442
    } else {
6443 6444
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cpu affinity is not supported"));
6445
        goto cleanup;
6446
    }
6447
    ret = 0;
6448

6449
cleanup:
6450 6451
    if (vm)
        virDomainObjUnlock(vm);
6452
    return ret;
6453 6454 6455 6456 6457 6458 6459 6460
}

static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
6461 6462
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6463
    virNodeInfo nodeinfo;
6464
    int i, v, maxcpu, hostcpus;
6465
    int ret = -1;
6466
    qemuDomainObjPrivatePtr priv;
6467

6468
    qemuDriverLock(driver);
6469
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
6470 6471
    qemuDriverUnlock(driver);

6472 6473 6474
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6475 6476
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6477 6478 6479
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
6480
    if (!virDomainObjIsActive(vm)) {
6481 6482 6483
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s",
                        _("cannot list vcpu pinning for an inactive domain"));
6484
        goto cleanup;
6485 6486
    }

6487 6488
    priv = vm->privateData;

6489
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
6490
        goto cleanup;
6491

6492
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
6493
    maxcpu = maplen * 8;
6494 6495
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
6496 6497

    /* Clamp to actual number of vcpus */
6498 6499
    if (maxinfo > priv->nvcpupids)
        maxinfo = priv->nvcpupids;
6500

6501 6502 6503 6504 6505 6506
    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;
6507

6508
                if (priv->vcpupids != NULL &&
6509 6510 6511
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
                                        vm->pid,
6512
                                        priv->vcpupids[i]) < 0) {
6513
                    virReportSystemError(errno, "%s",
6514 6515 6516
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
6517
            }
6518 6519
        }

6520 6521
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
6522
            if (priv->vcpupids != NULL) {
6523 6524 6525
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);

6526
                    if (virProcessInfoGetAffinity(priv->vcpupids[v],
6527
                                                  cpumap, maplen, maxcpu) < 0)
6528
                        goto cleanup;
6529
                }
6530
            } else {
6531 6532
                qemuReportError(VIR_ERR_NO_SUPPORT,
                                "%s", _("cpu affinity is not available"));
6533
                goto cleanup;
6534 6535 6536
            }
        }
    }
6537
    ret = maxinfo;
6538

6539
cleanup:
6540 6541
    if (vm)
        virDomainObjUnlock(vm);
6542
    return ret;
6543 6544 6545
}


6546 6547 6548
static int
qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
6549 6550
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6551
    virDomainDefPtr def;
6552
    int ret = -1;
6553

6554 6555 6556 6557 6558 6559 6560 6561
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    /* Exactly one of LIVE or CONFIG must be set.  */
    if (!(flags & VIR_DOMAIN_VCPU_LIVE) == !(flags & VIR_DOMAIN_VCPU_CONFIG)) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid flag combination: (0x%x)"), flags);
6562 6563 6564
        return -1;
    }

6565
    qemuDriverLock(driver);
6566
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
6567 6568
    qemuDriverUnlock(driver);

6569
    if (!vm) {
6570 6571
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6572 6573
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
6574
        goto cleanup;
6575 6576
    }

6577 6578 6579 6580 6581 6582 6583 6584 6585
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                            _("domain not active"));
            goto cleanup;
        }
        def = vm->def;
    } else {
        def = vm->newDef ? vm->newDef : vm->def;
6586 6587
    }

6588
    ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
6589

6590
cleanup:
6591 6592
    if (vm)
        virDomainObjUnlock(vm);
6593 6594 6595
    return ret;
}

6596 6597 6598 6599 6600 6601 6602
static int
qemudDomainGetMaxVcpus(virDomainPtr dom)
{
    return qemudDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                          VIR_DOMAIN_VCPU_MAXIMUM));
}

6603 6604 6605 6606 6607 6608 6609 6610 6611
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);

6612 6613
    memset(seclabel, 0, sizeof(*seclabel));

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

6622
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
6623 6624 6625
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unknown virt type in domain definition '%d'"),
                        vm->def->virtType);
6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642
        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 已提交
6643
    if (virDomainObjIsActive(vm)) {
6644 6645 6646 6647 6648 6649 6650
        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;
6651 6652 6653 6654 6655 6656 6657 6658
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
6659
    qemuDriverUnlock(driver);
6660 6661 6662
    return ret;
}

6663 6664
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
6665 6666 6667
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
6668
    int ret = 0;
6669

6670
    qemuDriverLock(driver);
6671
    if (!driver->securityPrimaryDriver) {
6672
        memset(secmodel, 0, sizeof (*secmodel));
6673 6674
        goto cleanup;
    }
6675

6676 6677
    p = driver->caps->host.secModel.model;
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
6678 6679 6680
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security model string exceeds max %d bytes"),
                        VIR_SECURITY_MODEL_BUFLEN-1);
6681 6682
        ret = -1;
        goto cleanup;
6683 6684 6685 6686 6687
    }
    strcpy(secmodel->model, p);

    p = driver->caps->host.secModel.doi;
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
6688 6689 6690
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("security DOI string exceeds max %d bytes"),
                        VIR_SECURITY_DOI_BUFLEN-1);
6691 6692
        ret = -1;
        goto cleanup;
6693 6694
    }
    strcpy(secmodel->doi, p);
6695 6696 6697 6698

cleanup:
    qemuDriverUnlock(driver);
    return ret;
6699 6700
}

6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734
/* 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 */
6735
        VIR_FORCE_CLOSE(pipefd[1]);
6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746

        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:
6747 6748
        VIR_FORCE_CLOSE(pipefd[0]);
        VIR_FORCE_CLOSE(pipefd[1]);
6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770
        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;
6771
    struct passwd pwd, *pwd_result;
6772 6773

    /* child doesn't need the read side of the pipe */
6774
    VIR_FORCE_CLOSE(pipefd[0]);
6775 6776 6777 6778 6779 6780 6781 6782 6783

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

6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803
    if (VIR_ALLOC_N(buf, bufsize) < 0) {
        exit_code = ENOMEM;
        virReportOOMError();
        goto child_cleanup;
    }

    exit_code = getpwuid_r(uid, &pwd, buf, bufsize, &pwd_result);
    if (pwd_result == NULL) {
        virReportSystemError(errno,
                             _("cannot getpwuid_r(%d) to read '%s'"),
                             uid, path);
        goto child_cleanup;
    }
    if (initgroups(pwd.pw_name, pwd.pw_gid) != 0) {
        exit_code = errno;
        virReportSystemError(errno,
                             _("cannot initgroups(\"%s\", %d) to read '%s'"),
                             pwd.pw_name, pwd.pw_gid, path);
        goto child_cleanup;
    }
6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838
    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;
    }

    /* 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);
6839 6840
    VIR_FORCE_CLOSE(fd);
    VIR_FORCE_CLOSE(pipefd[1]);
6841 6842 6843
    _exit(exit_code);
}

J
Jiri Denemark 已提交
6844 6845 6846 6847
static int qemudDomainSaveImageClose(int fd, pid_t read_pid, int *status)
{
    int ret = 0;

6848 6849 6850 6851
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, "%s",
                             _("cannot close file"));
    }
J
Jiri Denemark 已提交
6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873

    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;
6874
    pid_t read_pid = -1;
6875
    struct qemud_save_header header;
J
Jiri Denemark 已提交
6876 6877
    char *xml = NULL;
    virDomainDefPtr def = NULL;
6878 6879

    if ((fd = open(path, O_RDONLY)) < 0) {
6880 6881 6882
        if ((driver->user == 0) || (getuid() != 0)) {
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("cannot read domain image"));
J
Jiri Denemark 已提交
6883
            goto error;
6884 6885 6886 6887 6888 6889 6890 6891
        }

        /* 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 已提交
6892
            goto error;
6893
        }
6894 6895 6896
    }

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
6897 6898
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
6899
        goto error;
6900 6901 6902
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
6903 6904
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("image magic is incorrect"));
J
Jiri Denemark 已提交
6905
        goto error;
6906 6907 6908
    }

    if (header.version > QEMUD_SAVE_VERSION) {
6909 6910 6911
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("image version is not supported (%d > %d)"),
                        header.version, QEMUD_SAVE_VERSION);
J
Jiri Denemark 已提交
6912
        goto error;
6913 6914
    }

6915 6916 6917
    if (header.xml_len <= 0) {
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
6918
        goto error;
6919 6920
    }

6921 6922
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
J
Jiri Denemark 已提交
6923
        goto error;
6924 6925 6926
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
6927 6928
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
6929
        goto error;
6930 6931 6932
    }

    /* Create a domain from this XML */
6933
    if (!(def = virDomainDefParseString(driver->caps, xml,
6934
                                        VIR_DOMAIN_XML_INACTIVE))) {
6935 6936
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
J
Jiri Denemark 已提交
6937
        goto error;
6938 6939
    }

J
Jiri Denemark 已提交
6940
    VIR_FREE(xml);
6941

J
Jiri Denemark 已提交
6942 6943 6944
    *ret_def = def;
    *ret_header = header;
    *ret_read_pid = read_pid;
6945

J
Jiri Denemark 已提交
6946
    return fd;
6947

J
Jiri Denemark 已提交
6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973
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) {
6974
        const char *intermediate_argv[3] = { NULL, "-dc", NULL };
J
Jiri Denemark 已提交
6975
        const char *prog = qemudSaveCompressionTypeToString(header->compressed);
6976
        if (prog == NULL) {
6977 6978
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("Invalid compressed save format %d"),
J
Jiri Denemark 已提交
6979 6980
                            header->compressed);
            goto out;
6981
        }
6982

J
Jiri Denemark 已提交
6983
        if (header->compressed != QEMUD_SAVE_FORMAT_RAW) {
6984
            intermediate_argv[0] = prog;
6985 6986
            intermediatefd = fd;
            fd = -1;
6987
            if (virExec(intermediate_argv, NULL, NULL,
6988
                        &intermediate_pid, intermediatefd, &fd, NULL, 0) < 0) {
6989 6990 6991
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Failed to start decompression binary %s"),
                                intermediate_argv[0]);
J
Jiri Denemark 已提交
6992
                goto out;
6993 6994 6995
            }
        }
    }
J
Jiri Denemark 已提交
6996

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

7000 7001 7002
    if (intermediate_pid != -1) {
        /* Wait for intermediate process to exit */
        while (waitpid(intermediate_pid, &childstat, 0) == -1 &&
J
Jiri Denemark 已提交
7003 7004 7005
               errno == EINTR) {
            /* empty */
        }
7006
    }
7007
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
7008 7009

    wait_ret = qemudDomainSaveImageClose(fd, read_pid, &status);
7010
    fd = -1;
7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031
    if (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 已提交
7032

7033 7034
    if (ret < 0) {
        qemuDomainStartAudit(vm, "restored", false);
J
Jiri Denemark 已提交
7035
        goto out;
7036
    }
7037

7038 7039 7040
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
7041
    qemuDomainStartAudit(vm, "restored", true);
J
Jiri Denemark 已提交
7042 7043 7044
    if (event)
        qemuDomainEventQueue(driver, event);

7045

7046
    /* If it was running before, resume it now. */
J
Jiri Denemark 已提交
7047
    if (header->was_running) {
7048
        qemuDomainObjPrivatePtr priv = vm->privateData;
7049
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
7050
        if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
7051
            if (virGetLastError() == NULL)
7052 7053
                qemuReportError(VIR_ERR_OPERATION_FAILED,
                                "%s", _("failed to resume domain"));
7054
            qemuDomainObjExitMonitorWithDriver(driver,vm);
J
Jiri Denemark 已提交
7055
            goto out;
7056
        }
7057
        qemuDomainObjExitMonitorWithDriver(driver, vm);
7058
        vm->state = VIR_DOMAIN_RUNNING;
7059 7060
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
J
Jiri Denemark 已提交
7061
            goto out;
7062
        }
7063
    }
J
Jiri Denemark 已提交
7064

7065
    ret = 0;
7066

J
Jiri Denemark 已提交
7067
out:
7068 7069
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSavedStateLabel &&
7070 7071
        driver->securityDriver->domainRestoreSavedStateLabel(driver->securityDriver,
                                                             vm, path) == -1)
7072 7073
        VIR_WARN("failed to restore save state label on %s", path);

J
Jiri Denemark 已提交
7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098
    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))) {
7099
        /* virDomainAssignDef already set the error */
J
Jiri Denemark 已提交
7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110
        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)
7111
        vm = NULL;
J
Jiri Denemark 已提交
7112 7113 7114 7115
    else if (ret < 0 && !vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
7116

7117 7118
cleanup:
    virDomainDefFree(def);
J
Jiri Denemark 已提交
7119
    qemudDomainSaveImageClose(fd, read_pid, NULL);
7120 7121 7122
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
7123
    return ret;
D
Daniel P. Berrange 已提交
7124 7125
}

J
Jiri Denemark 已提交
7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166
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 已提交
7167

7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205
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;
}


7206
static char *qemudDomainDumpXML(virDomainPtr dom,
7207
                                int flags) {
7208 7209 7210
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
7211 7212
    unsigned long balloon;
    int err;
7213

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

D
Daniel P. Berrange 已提交
7217
    if (!vm) {
7218 7219
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7220 7221
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7222
        goto cleanup;
D
Daniel P. Berrange 已提交
7223 7224
    }

7225 7226 7227 7228
    /* Refresh current memory based on balloon info if supported */
    if ((vm->def->memballoon != NULL) &&
        (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
        (virDomainObjIsActive(vm))) {
7229
        qemuDomainObjPrivatePtr priv = vm->privateData;
7230 7231 7232
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
        if (!priv->jobActive) {
7233
            if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
7234 7235
                goto cleanup;

7236
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
7237
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
7238
            qemuDomainObjExitMonitorWithDriver(driver, vm);
7239 7240 7241 7242
            if (qemuDomainObjEndJob(vm) == 0) {
                vm = NULL;
                goto cleanup;
            }
7243 7244 7245
            if (err < 0)
                goto cleanup;
            if (err > 0)
7246
                vm->def->mem.cur_balloon = balloon;
7247 7248
            /* err == 0 indicates no balloon support, so ignore it */
        }
7249
    }
7250

7251
    ret = qemudVMDumpXML(driver, vm, flags);
7252 7253

cleanup:
7254 7255
    if (vm)
        virDomainObjUnlock(vm);
7256
    qemuDriverUnlock(driver);
7257
    return ret;
D
Daniel P. Berrange 已提交
7258 7259 7260
}


7261 7262 7263 7264
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
                                     unsigned int flags ATTRIBUTE_UNUSED) {
7265
    struct qemud_driver *driver = conn->privateData;
7266 7267 7268 7269
    virDomainDefPtr def = NULL;
    char *xml = NULL;

    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
7270 7271
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
7272 7273 7274
        goto cleanup;
    }

7275
    qemuDriverLock(driver);
7276
    def = qemuParseCommandLineString(driver->caps, config);
7277
    qemuDriverUnlock(driver);
7278 7279 7280
    if (!def)
        goto cleanup;

7281
    xml = virDomainDefFormat(def, VIR_DOMAIN_XML_INACTIVE);
7282 7283 7284 7285 7286 7287

cleanup:
    virDomainDefFree(def);
    return xml;
}

7288 7289 7290 7291 7292 7293
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;
7294
    virDomainChrDef monConfig;
7295
    const char *emulator;
7296
    unsigned long long qemuCmdFlags;
7297 7298 7299 7300 7301 7302 7303 7304
    struct stat sb;
    const char **retargv = NULL;
    const char **retenv = NULL;
    const char **tmp;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *ret = NULL;
    int i;

7305 7306
    qemuDriverLock(driver);

7307
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
7308 7309
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("unsupported config type %s"), format);
7310 7311 7312
        goto cleanup;
    }

7313
    def = virDomainDefParseString(driver->caps, xmlData, 0);
7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357
    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) {
7358
        virReportSystemError(errno,
7359 7360 7361 7362 7363 7364 7365 7366
                             _("Cannot find QEMU binary %s"),
                             emulator);
        goto cleanup;
    }

    if (qemudExtractVersionInfo(emulator,
                                NULL,
                                &qemuCmdFlags) < 0) {
7367 7368 7369
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot determine QEMU argv syntax %s"),
                        emulator);
7370 7371 7372
        goto cleanup;
    }

7373
    if (qemuPrepareMonitorChr(driver, &monConfig, def->name) < 0)
7374
        goto cleanup;
7375 7376

    if (qemudBuildCommandLine(conn, driver, def,
D
Daniel P. Berrange 已提交
7377
                              &monConfig, 0, qemuCmdFlags,
7378 7379
                              &retargv, &retenv,
                              NULL, NULL, /* Don't want it to create TAP devices */
C
Chris Lalancette 已提交
7380
                              NULL, NULL) < 0) {
7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396
        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++;
    }

7397 7398
    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
7399
        virReportOOMError();
7400
        goto cleanup;
7401
    }
7402 7403 7404 7405

    ret = virBufferContentAndReset(&buf);

cleanup:
7406
    qemuDriverUnlock(driver);
7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419
    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;
}


7420
static int qemudListDefinedDomains(virConnectPtr conn,
7421
                            char **const names, int nnames) {
7422
    struct qemud_driver *driver = conn->privateData;
7423
    int n;
7424

7425
    qemuDriverLock(driver);
7426
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
7427
    qemuDriverUnlock(driver);
7428
    return n;
D
Daniel P. Berrange 已提交
7429 7430
}

7431
static int qemudNumDefinedDomains(virConnectPtr conn) {
7432
    struct qemud_driver *driver = conn->privateData;
7433
    int n;
7434

7435
    qemuDriverLock(driver);
7436
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
7437
    qemuDriverUnlock(driver);
7438

7439
    return n;
D
Daniel P. Berrange 已提交
7440 7441 7442
}


J
Jiri Denemark 已提交
7443 7444
static int qemudDomainObjStart(virConnectPtr conn,
                               struct qemud_driver *driver,
7445 7446
                               virDomainObjPtr vm,
                               bool start_paused)
J
Jiri Denemark 已提交
7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466
{
    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;
    }

7467
    ret = qemudStartVMDaemon(conn, driver, vm, NULL, start_paused, -1, NULL);
7468 7469
    qemuDomainStartAudit(vm, "booted", ret >= 0);
    if (ret >= 0) {
J
Jiri Denemark 已提交
7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482
        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;
}

7483 7484 7485
static int
qemudDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
{
7486 7487 7488
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
7489

7490
    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);
7491

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

7495
    if (!vm) {
7496 7497
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7498 7499
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7500
        goto cleanup;
7501 7502
    }

7503 7504 7505 7506
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
7507 7508
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is already running"));
7509 7510 7511
        goto endjob;
    }

7512 7513
    ret = qemudDomainObjStart(dom->conn, driver, vm,
                              (flags & VIR_DOMAIN_START_PAUSED) != 0);
7514

7515
endjob:
7516 7517
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
7518

7519
cleanup:
7520 7521
    if (vm)
        virDomainObjUnlock(vm);
7522
    qemuDriverUnlock(driver);
7523
    return ret;
D
Daniel P. Berrange 已提交
7524 7525
}

7526 7527 7528 7529 7530 7531
static int
qemudDomainStart(virDomainPtr dom)
{
    return qemudDomainStartWithFlags(dom, 0);
}

7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546
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;

7547
        if (STRNEQ(def->os.machine, machine->name))
7548 7549 7550
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
7551
            virReportOOMError();
7552 7553 7554 7555 7556 7557 7558 7559 7560
            return -1;
        }

        break;
    }

    return 0;
}

7561 7562 7563 7564 7565 7566 7567
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
    int i, nmachines = 0;

    if (qemudProbeMachineTypes(def->emulator, &machines, &nmachines) < 0) {
7568
        virReportOOMError();
7569 7570 7571 7572 7573 7574 7575
        return -1;
    }

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

7576
        if (STRNEQ(def->os.machine, machines[i]->name))
7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588
            continue;

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

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

7589 7590
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
7591 7592 7593 7594 7595 7596
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
7597
        virCapsGuestDomainInfoPtr info;
7598 7599 7600
        int j;

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

7603 7604 7605 7606 7607 7608 7609 7610 7611
            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;
7612 7613
        }

7614 7615 7616 7617
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
7618 7619 7620 7621
                return -1;
            goto out;
        }
    }
7622 7623 7624 7625

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

7626 7627 7628 7629 7630 7631 7632
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
7633

7634
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
7635
    struct qemud_driver *driver = conn->privateData;
7636
    virDomainDefPtr def;
7637
    virDomainObjPtr vm = NULL;
7638
    virDomainPtr dom = NULL;
7639
    virDomainEventPtr event = NULL;
7640
    int dupVM;
7641

7642
    qemuDriverLock(driver);
7643
    if (!(def = virDomainDefParseString(driver->caps, xml,
7644
                                        VIR_DOMAIN_XML_INACTIVE)))
7645
        goto cleanup;
7646

7647
    if (virSecurityDriverVerify(def) < 0)
7648 7649
        goto cleanup;

7650 7651
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
7652

7653
    if (qemudCanonicalizeMachine(driver, def) < 0)
7654 7655
        goto cleanup;

7656 7657 7658
    if (qemuAssignPCIAddresses(def) < 0)
        goto cleanup;

7659
    if (!(vm = virDomainAssignDef(driver->caps,
7660
                                  &driver->domains,
7661
                                  def, false))) {
7662
        goto cleanup;
7663
    }
7664
    def = NULL;
7665
    vm->persistent = 1;
7666

7667
    if (virDomainSaveConfig(driver->configDir,
7668
                            vm->newDef ? vm->newDef : vm->def) < 0) {
7669 7670
        virDomainRemoveInactive(&driver->domains,
                                vm);
7671
        vm = NULL;
7672
        goto cleanup;
7673 7674
    }

7675 7676
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
7677
                                     !dupVM ?
7678 7679
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
7680

7681
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
7682
    if (dom) dom->id = vm->def->id;
7683 7684

cleanup:
7685
    virDomainDefFree(def);
7686 7687
    if (vm)
        virDomainObjUnlock(vm);
7688 7689
    if (event)
        qemuDomainEventQueue(driver, event);
7690
    qemuDriverUnlock(driver);
7691
    return dom;
D
Daniel P. Berrange 已提交
7692 7693
}

7694
static int qemudDomainUndefine(virDomainPtr dom) {
7695 7696
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
7697
    virDomainEventPtr event = NULL;
7698
    int ret = -1;
D
Daniel P. Berrange 已提交
7699

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

D
Daniel P. Berrange 已提交
7703
    if (!vm) {
7704 7705
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
7706 7707
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
7708
        goto cleanup;
D
Daniel P. Berrange 已提交
7709 7710
    }

D
Daniel P. Berrange 已提交
7711
    if (virDomainObjIsActive(vm)) {
7712 7713
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot delete active domain"));
7714
        goto cleanup;
D
Daniel P. Berrange 已提交
7715 7716
    }

7717
    if (!vm->persistent) {
7718 7719
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot undefine transient domain"));
7720
        goto cleanup;
7721 7722
    }

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

7726 7727 7728
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
7729

7730 7731
    virDomainRemoveInactive(&driver->domains,
                            vm);
7732
    vm = NULL;
7733
    ret = 0;
D
Daniel P. Berrange 已提交
7734

7735
cleanup:
7736 7737
    if (vm)
        virDomainObjUnlock(vm);
7738 7739
    if (event)
        qemuDomainEventQueue(driver, event);
7740
    qemuDriverUnlock(driver);
7741
    return ret;
D
Daniel P. Berrange 已提交
7742 7743
}

7744

7745
static int qemudDomainChangeEjectableMedia(struct qemud_driver *driver,
7746
                                           virDomainObjPtr vm,
7747
                                           virDomainDiskDefPtr disk,
7748 7749
                                           unsigned long long qemuCmdFlags,
                                           bool force)
7750
{
7751
    virDomainDiskDefPtr origdisk = NULL;
7752
    int i;
7753
    int ret;
7754
    char *driveAlias = NULL;
7755

7756
    origdisk = NULL;
7757
    for (i = 0 ; i < vm->def->ndisks ; i++) {
7758 7759
        if (vm->def->disks[i]->bus == disk->bus &&
            STREQ(vm->def->disks[i]->dst, disk->dst)) {
7760
            origdisk = vm->def->disks[i];
7761
            break;
7762
        }
7763 7764 7765
    }

    if (!origdisk) {
7766 7767 7768 7769
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No device with bus '%s' and target '%s'"),
                        virDomainDiskBusTypeToString(disk->bus),
                        disk->dst);
7770 7771 7772
        return -1;
    }

7773
    if (!origdisk->info.alias) {
7774 7775
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), origdisk->dst);
7776 7777
        return -1;
    }
7778

7779 7780
    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
7781 7782 7783
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Removable media not supported for %s device"),
                        virDomainDiskDeviceTypeToString(disk->device));
7784
        return -1;
7785
    }
7786

7787 7788
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
7789 7790
        driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver,
                                                            vm, disk) < 0)
7791 7792
        return -1;

7793 7794 7795
    if (!(driveAlias = qemuDeviceDriveHostAlias(origdisk, qemuCmdFlags)))
        goto error;

7796
    qemuDomainObjPrivatePtr priv = vm->privateData;
7797
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7798
    if (disk->src) {
7799
        const char *format = NULL;
7800 7801 7802
        if (disk->type != VIR_DOMAIN_DISK_TYPE_DIR) {
            if (disk->driverType)
                format = disk->driverType;
7803 7804 7805
            else if (origdisk->driverType)
                format = origdisk->driverType;
        }
7806
        ret = qemuMonitorChangeMedia(priv->mon,
7807
                                     driveAlias,
7808
                                     disk->src, format);
7809
    } else {
7810
        ret = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
7811
    }
7812
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7813

7814 7815
    qemuDomainDiskAudit(vm, origdisk, disk, "update", ret >= 0);

7816 7817 7818 7819 7820
    if (ret < 0)
        goto error;

    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7821 7822
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, origdisk) < 0)
7823 7824 7825
        VIR_WARN("Unable to restore security label on ejected image %s", origdisk->src);

    VIR_FREE(origdisk->src);
7826 7827 7828 7829
    origdisk->src = disk->src;
    disk->src = NULL;
    origdisk->type = disk->type;

7830 7831
    VIR_FREE(driveAlias);

7832
    virDomainDiskDefFree(disk);
7833

7834
    return ret;
7835 7836

error:
7837
    VIR_FREE(driveAlias);
7838 7839
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7840 7841
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, disk) < 0)
7842
        VIR_WARN("Unable to restore security label on new media %s", disk->src);
7843
    return -1;
7844 7845
}

7846

7847
static int qemudDomainAttachPciDiskDevice(struct qemud_driver *driver,
7848
                                          virDomainObjPtr vm,
7849
                                          virDomainDiskDefPtr disk,
7850
                                          unsigned long long qemuCmdFlags)
7851
{
7852
    int i, ret;
7853
    const char* type = virDomainDiskBusTypeToString(disk->bus);
7854
    qemuDomainObjPrivatePtr priv = vm->privateData;
7855 7856
    char *devstr = NULL;
    char *drivestr = NULL;
7857 7858

    for (i = 0 ; i < vm->def->ndisks ; i++) {
7859
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
7860 7861
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
7862 7863 7864 7865
            return -1;
        }
    }

7866 7867
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
7868 7869
        driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver,
                                                            vm, disk) < 0)
7870 7871
        return -1;

7872
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
7873 7874
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
            goto error;
7875 7876
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
7877

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

7881
        if (!(devstr = qemuBuildDriveDevStr(disk)))
7882 7883 7884
            goto error;
    }

7885
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
7886
        virReportOOMError();
7887
        goto error;
7888 7889
    }

7890
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7891 7892
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDrive(priv->mon, drivestr);
7893 7894 7895
        if (ret == 0) {
            ret = qemuMonitorAddDevice(priv->mon, devstr);
            if (ret < 0) {
7896
                VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
7897 7898 7899 7900 7901
                         drivestr, devstr);
                /* XXX should call 'drive_del' on error but this does not
                   exist yet */
            }
        }
7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912
    } 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));
        }
    }
7913
    qemuDomainObjExitMonitorWithDriver(driver, vm);
7914

7915 7916
    qemuDomainDiskAudit(vm, NULL, disk, "attach", ret >= 0);

7917 7918
    if (ret < 0)
        goto error;
7919

7920
    virDomainDiskInsertPreAlloced(vm->def, disk);
7921

7922 7923 7924
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7925 7926 7927
    return 0;

error:
7928 7929 7930
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

7931 7932 7933 7934 7935
    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);

7936 7937
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
7938 7939
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, disk) < 0)
7940
        VIR_WARN("Unable to restore security label on %s", disk->src);
7941 7942

    return -1;
7943
}
7944

7945

7946
static int qemudDomainAttachPciControllerDevice(struct qemud_driver *driver,
7947
                                                virDomainObjPtr vm,
7948
                                                virDomainControllerDefPtr controller,
7949
                                                unsigned long long qemuCmdFlags)
7950
{
7951 7952
    int i;
    int ret = -1;
7953
    const char* type = virDomainControllerTypeToString(controller->type);
7954
    char *devstr = NULL;
7955 7956 7957
    qemuDomainObjPrivatePtr priv = vm->privateData;

    for (i = 0 ; i < vm->def->ncontrollers ; i++) {
7958 7959
        if ((vm->def->controllers[i]->type == controller->type) &&
            (vm->def->controllers[i]->idx == controller->idx)) {
7960 7961 7962
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s:%d already exists"),
                            type, controller->idx);
7963 7964 7965 7966
            return -1;
        }
    }

7967 7968 7969 7970 7971 7972
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
            goto cleanup;
        if (qemuAssignDeviceControllerAlias(controller) < 0)
            goto cleanup;
    }
7973

7974
    if (!(devstr = qemuBuildControllerDevStr(controller))) {
7975
        virReportOOMError();
7976 7977 7978
        goto cleanup;
    }

7979
    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) {
7980
        virReportOOMError();
7981
        goto cleanup;
7982 7983 7984
    }

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
7985 7986 7987 7988 7989 7990 7991
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    } else {
        ret = qemuMonitorAttachPCIDiskController(priv->mon,
                                                 type,
                                                 &controller->info.addr.pci);
    }
7992 7993 7994
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (ret == 0) {
7995 7996
        controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
        virDomainControllerInsertPreAlloced(vm->def, controller);
7997 7998
    }

7999
cleanup:
8000 8001 8002 8003 8004 8005
    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");

8006
    VIR_FREE(devstr);
8007 8008 8009
    return ret;
}

8010

8011
static virDomainControllerDefPtr
8012
qemuDomainFindOrCreateSCSIDiskController(struct qemud_driver *driver,
8013
                                         virDomainObjPtr vm,
8014
                                         int controller,
8015
                                         unsigned long long qemuCmdFlags)
8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028
{
    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 已提交
8029
    /* No SCSI controller present, for backward compatibility we
8030 8031
     * now hotplug a controller */
    if (VIR_ALLOC(cont) < 0) {
8032
        virReportOOMError();
8033 8034 8035 8036
        return NULL;
    }
    cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
    cont->idx = 0;
8037
    cont->model = -1;
8038 8039

    VIR_INFO0("No SCSI controller present, hotplugging one");
8040
    if (qemudDomainAttachPciControllerDevice(driver,
8041
                                             vm, cont, qemuCmdFlags) < 0) {
8042 8043 8044
        VIR_FREE(cont);
        return NULL;
    }
8045 8046 8047 8048 8049 8050 8051 8052 8053

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

8054 8055 8056
    return cont;
}

8057

8058
static int qemudDomainAttachSCSIDisk(struct qemud_driver *driver,
8059
                                     virDomainObjPtr vm,
8060
                                     virDomainDiskDefPtr disk,
8061
                                     unsigned long long qemuCmdFlags)
8062 8063 8064
{
    int i;
    qemuDomainObjPrivatePtr priv = vm->privateData;
8065
    virDomainControllerDefPtr cont = NULL;
8066
    char *drivestr = NULL;
8067
    char *devstr = NULL;
8068 8069 8070
    int ret = -1;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
8071
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
8072 8073
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
8074
            return -1;
8075 8076 8077
        }
    }

8078 8079 8080

    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
8081 8082
        driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver,
                                                            vm, disk) < 0)
8083 8084
        return -1;

8085
    /* We should have an address already, so make sure */
8086
    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
8087 8088 8089
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected disk address type %s"),
                        virDomainDeviceAddressTypeToString(disk->info.type));
8090
        goto error;
8091 8092
    }

8093 8094 8095
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
8096
        if (!(devstr = qemuBuildDriveDevStr(disk)))
8097 8098 8099 8100 8101 8102
            goto error;
    }

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

8103
    for (i = 0 ; i <= disk->info.addr.drive.controller ; i++) {
8104
        cont = qemuDomainFindOrCreateSCSIDiskController(driver, vm, i, qemuCmdFlags);
8105
        if (!cont)
8106
            goto error;
8107 8108
    }

8109 8110 8111 8112 8113
    /* 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);

8114
    if (cont->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
8115 8116
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("SCSI controller %d was missing its PCI address"), cont->idx);
8117
        goto error;
8118 8119 8120
    }

    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
8121
        virReportOOMError();
8122
        goto error;
8123 8124 8125
    }

    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8126
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
8127 8128 8129 8130
        ret = qemuMonitorAddDrive(priv->mon, drivestr);
        if (ret == 0) {
            ret = qemuMonitorAddDevice(priv->mon, devstr);
            if (ret < 0) {
8131
                VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
8132 8133 8134 8135 8136
                         drivestr, devstr);
                /* XXX should call 'drive_del' on error but this does not
                   exist yet */
            }
        }
8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149
    } 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));
        }
    }
8150 8151
    qemuDomainObjExitMonitorWithDriver(driver, vm);

8152 8153
    qemuDomainDiskAudit(vm, NULL, disk, "attach", ret >= 0);

8154 8155
    if (ret < 0)
        goto error;
8156

8157
    virDomainDiskInsertPreAlloced(vm->def, disk);
8158 8159

    VIR_FREE(devstr);
8160
    VIR_FREE(drivestr);
8161 8162 8163 8164

    return 0;

error:
8165
    VIR_FREE(devstr);
8166
    VIR_FREE(drivestr);
8167

8168 8169
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
8170 8171
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, disk) < 0)
8172
        VIR_WARN("Unable to restore security label on %s", disk->src);
8173 8174

    return -1;
8175 8176
}

8177

8178
static int qemudDomainAttachUsbMassstorageDevice(struct qemud_driver *driver,
8179
                                                 virDomainObjPtr vm,
8180
                                                 virDomainDiskDefPtr disk,
8181
                                                 unsigned long long qemuCmdFlags)
8182
{
8183
    qemuDomainObjPrivatePtr priv = vm->privateData;
8184
    int i, ret;
8185 8186
    char *drivestr = NULL;
    char *devstr = NULL;
8187

8188
    for (i = 0 ; i < vm->def->ndisks ; i++) {
8189
        if (STREQ(vm->def->disks[i]->dst, disk->dst)) {
8190 8191
            qemuReportError(VIR_ERR_OPERATION_FAILED,
                            _("target %s already exists"), disk->dst);
8192 8193 8194 8195
            return -1;
        }
    }

8196 8197
    if (driver->securityDriver &&
        driver->securityDriver->domainSetSecurityImageLabel &&
8198 8199
        driver->securityDriver->domainSetSecurityImageLabel(driver->securityDriver,
                                                            vm, disk) < 0)
8200 8201
        return -1;

8202
    if (!disk->src) {
8203 8204
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("disk source path is missing"));
8205
        goto error;
8206 8207
    }

8208
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
8209 8210
        if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
            goto error;
8211 8212
        if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
            goto error;
8213
        if (!(devstr = qemuBuildDriveDevStr(disk)))
8214 8215 8216
            goto error;
    }

8217
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0) {
8218
        virReportOOMError();
8219
        goto error;
8220 8221
    }

8222
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8223
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
8224 8225 8226 8227
        ret = qemuMonitorAddDrive(priv->mon, drivestr);
        if (ret == 0) {
            ret = qemuMonitorAddDevice(priv->mon, devstr);
            if (ret < 0) {
8228
                VIR_WARN("qemuMonitorAddDevice failed on %s (%s)",
8229 8230 8231 8232 8233
                         drivestr, devstr);
                /* XXX should call 'drive_del' on error but this does not
                   exist yet */
            }
        }
8234 8235 8236
    } else {
        ret = qemuMonitorAddUSBDisk(priv->mon, disk->src);
    }
8237
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8238

8239 8240
    qemuDomainDiskAudit(vm, NULL, disk, "attach", ret >= 0);

8241 8242 8243
    if (ret < 0)
        goto error;

8244
    virDomainDiskInsertPreAlloced(vm->def, disk);
8245

8246 8247 8248
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

8249 8250 8251
    return 0;

error:
8252 8253 8254
    VIR_FREE(devstr);
    VIR_FREE(drivestr);

8255 8256
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
8257 8258
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, disk) < 0)
8259
        VIR_WARN("Unable to restore security label on %s", disk->src);
8260 8261

    return -1;
8262 8263
}

8264

8265
/* XXX conn required for network -> bridge resolution */
M
Mark McLoughlin 已提交
8266
static int qemudDomainAttachNetDevice(virConnectPtr conn,
8267
                                      struct qemud_driver *driver,
M
Mark McLoughlin 已提交
8268
                                      virDomainObjPtr vm,
8269
                                      virDomainNetDefPtr net,
8270
                                      unsigned long long qemuCmdFlags)
M
Mark McLoughlin 已提交
8271
{
8272
    qemuDomainObjPrivatePtr priv = vm->privateData;
8273
    char *tapfd_name = NULL;
8274
    int tapfd = -1;
8275
    char *nicstr = NULL;
8276
    char *netstr = NULL;
8277
    int ret = -1;
8278
    virDomainDevicePCIAddress guestAddr;
8279
    int vlan;
M
Mark McLoughlin 已提交
8280 8281

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HOST_NET_ADD)) {
8282
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
8283
                        _("installed qemu version does not support host_net_add"));
M
Mark McLoughlin 已提交
8284 8285 8286 8287 8288
        return -1;
    }

    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
        net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
8289
        if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
8290
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8291 8292 8293
                            _("network device type '%s' cannot be attached: "
                              "qemu is not using a unix socket monitor"),
                            virDomainNetTypeToString(net->type));
8294 8295 8296 8297 8298
            return -1;
        }

        if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
            return -1;
8299 8300
    } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
        if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
8301
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8302 8303 8304 8305 8306 8307
                            _("network device type '%s' cannot be attached: "
                            "qemu is not using a unix socket monitor"),
                            virDomainNetTypeToString(net->type));
            return -1;
        }

S
Stefan Berger 已提交
8308
        if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
8309 8310
                                           qemuCmdFlags,
                                           vm->def->uuid)) < 0)
8311
            return -1;
M
Mark McLoughlin 已提交
8312 8313
    }

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

8317 8318 8319 8320 8321
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
            goto cleanup;
    }
M
Mark McLoughlin 已提交
8322

8323 8324 8325 8326
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
        goto cleanup;

8327 8328 8329 8330 8331
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        vlan = -1;
    } else {
        vlan = qemuDomainNetVLAN(net);
M
Mark McLoughlin 已提交
8332

8333
        if (vlan < 0) {
8334
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
8335 8336 8337
                            _("Unable to attach network devices without vlan"));
            goto cleanup;
        }
8338 8339
    }

8340
    if (tapfd != -1) {
8341
        if (virAsprintf(&tapfd_name, "fd-%s", net->info.alias) < 0)
8342 8343
            goto no_memory;

8344
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
8345
        if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0) {
8346
            qemuDomainObjExitMonitorWithDriver(driver, vm);
8347
            goto cleanup;
8348
        }
8349
        qemuDomainObjExitMonitorWithDriver(driver, vm);
8350 8351 8352 8353 8354 8355

        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto cleanup;
        }
8356 8357
    }

8358
    /* FIXME - need to support vhost-net here (5th arg) */
8359 8360 8361 8362 8363 8364 8365 8366 8367 8368
    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 已提交
8369

8370
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8371 8372 8373 8374
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (qemuMonitorAddNetdev(priv->mon, netstr) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
8375
            qemuDomainNetAudit(vm, NULL, net, "attach", false);
8376 8377 8378 8379 8380
            goto try_tapfd_close;
        }
    } else {
        if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
8381
            qemuDomainNetAudit(vm, NULL, net, "attach", false);
8382 8383
            goto try_tapfd_close;
        }
8384
    }
8385
    qemuDomainObjExitMonitorWithDriver(driver, vm);
M
Mark McLoughlin 已提交
8386

8387
    VIR_FORCE_CLOSE(tapfd);
M
Mark McLoughlin 已提交
8388

8389 8390 8391 8392 8393 8394
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("guest unexpectedly quit"));
        goto cleanup;
    }

8395 8396 8397 8398 8399 8400 8401
    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 已提交
8402

8403
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8404 8405 8406
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
8407
            qemuDomainNetAudit(vm, NULL, net, "attach", false);
8408 8409 8410 8411 8412 8413
            goto try_remove;
        }
    } else {
        if (qemuMonitorAddPCINetwork(priv->mon, nicstr,
                                     &guestAddr) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
8414
            qemuDomainNetAudit(vm, NULL, net, "attach", false);
8415 8416 8417 8418
            goto try_remove;
        }
        net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
        memcpy(&net->info.addr.pci, &guestAddr, sizeof(guestAddr));
8419
    }
8420
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8421

8422 8423
    qemuDomainNetAudit(vm, NULL, net, "attach", true);

8424
    ret = 0;
M
Mark McLoughlin 已提交
8425 8426 8427

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

8428
cleanup:
8429 8430 8431 8432 8433 8434
    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");

8435
    if (ret != 0)
8436
        virDomainConfNWFilterTeardown(net);
S
Stefan Berger 已提交
8437

8438 8439 8440
    VIR_FREE(nicstr);
    VIR_FREE(netstr);
    VIR_FREE(tapfd_name);
8441
    VIR_FORCE_CLOSE(tapfd);
8442

8443
    return ret;
8444

8445
try_remove:
8446
    if (!virDomainObjIsActive(vm))
8447 8448
        goto cleanup;

8449
    if (vlan < 0) {
8450 8451 8452 8453 8454 8455 8456
        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)
8457
                VIR_WARN("Failed to remove network backend for netdev %s",
8458 8459 8460 8461
                         netdev_name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
            VIR_FREE(netdev_name);
        } else {
8462
            VIR_WARN0("Unable to remove network backend");
8463
        }
8464 8465 8466 8467
    } else {
        char *hostnet_name;
        if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0)
            goto no_memory;
8468
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
8469
        if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
8470
            VIR_WARN("Failed to remove network backend for vlan %d, net %s",
8471
                     vlan, hostnet_name);
8472
        qemuDomainObjExitMonitorWithDriver(driver, vm);
8473
        VIR_FREE(hostnet_name);
8474
    }
8475
    goto cleanup;
8476

8477
try_tapfd_close:
8478
    if (!virDomainObjIsActive(vm))
8479 8480
        goto cleanup;

8481
    if (tapfd_name) {
8482
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
8483
        if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
8484
            VIR_WARN("Failed to close tapfd with '%s'", tapfd_name);
8485
        qemuDomainObjExitMonitorWithDriver(driver, vm);
8486
    }
8487

8488 8489
    goto cleanup;

8490
no_memory:
8491
    virReportOOMError();
8492
    goto cleanup;
M
Mark McLoughlin 已提交
8493 8494
}

8495

8496
static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
8497
                                          virDomainObjPtr vm,
8498
                                          virDomainHostdevDefPtr hostdev,
8499
                                          unsigned long long qemuCmdFlags)
8500
{
8501
    qemuDomainObjPrivatePtr priv = vm->privateData;
8502
    int ret;
8503
    char *devstr = NULL;
8504 8505
    int configfd = -1;
    char *configfd_name = NULL;
8506 8507

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

8512
    if (qemuPrepareHostdevPCIDevices(driver, &hostdev, 1) < 0)
8513
        return -1;
8514

8515
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
8516 8517
        if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
            goto error;
8518 8519
        if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
            goto error;
8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543
        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;
        }
8544

8545
        if (!(devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name)))
8546
            goto error;
8547

8548
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
8549
        ret = qemuMonitorAddDevice(priv->mon, devstr);
8550 8551 8552 8553 8554
        qemuDomainObjExitMonitorWithDriver(driver, vm);
    } else {
        virDomainDevicePCIAddress guestAddr;

        qemuDomainObjEnterMonitorWithDriver(driver, vm);
8555 8556 8557
        ret = qemuMonitorAddPCIHostDevice(priv->mon,
                                          &hostdev->source.subsys.u.pci,
                                          &guestAddr);
8558 8559 8560 8561 8562
        qemuDomainObjExitMonitorWithDriver(driver, vm);

        hostdev->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
        memcpy(&hostdev->info.addr.pci, &guestAddr, sizeof(guestAddr));
    }
8563
    if (ret < 0)
8564
        goto error;
8565 8566 8567

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

8568
    VIR_FREE(devstr);
8569
    VIR_FREE(configfd_name);
8570
    VIR_FORCE_CLOSE(configfd);
8571

8572
    return 0;
8573 8574

error:
8575 8576 8577 8578 8579
    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");

8580
    qemuDomainReAttachHostdevDevices(driver, &hostdev, 1);
8581 8582

    VIR_FREE(devstr);
8583
    VIR_FREE(configfd_name);
8584
    VIR_FORCE_CLOSE(configfd);
8585 8586

    return -1;
8587 8588
}

8589

8590
static int qemudDomainAttachHostUsbDevice(struct qemud_driver *driver,
M
Mark McLoughlin 已提交
8591
                                          virDomainObjPtr vm,
8592
                                          virDomainHostdevDefPtr hostdev,
8593
                                          unsigned long long qemuCmdFlags)
8594 8595
{
    int ret;
8596
    qemuDomainObjPrivatePtr priv = vm->privateData;
8597 8598
    char *devstr = NULL;

8599 8600 8601 8602 8603 8604
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
            goto error;
        if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
            goto error;
    }
8605

8606
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
8607
        virReportOOMError();
8608
        goto error;
8609
    }
8610

8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        virCgroupPtr cgroup = NULL;
        usbDevice *usb;

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

        if ((usb = usbGetDevice(hostdev->source.subsys.u.usb.bus,
                                hostdev->source.subsys.u.usb.device)) == NULL)
            goto error;

        if (usbDeviceFileIterate(usb, qemuSetupHostUsbDeviceCgroup, cgroup) < 0 )
            goto error;
    }

8630
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
8631 8632 8633
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
        ret = qemuMonitorAddDevice(priv->mon, devstr);
    else
8634
        ret = qemuMonitorAddUSBDeviceExact(priv->mon,
8635 8636
                                           hostdev->source.subsys.u.usb.bus,
                                           hostdev->source.subsys.u.usb.device);
8637
    qemuDomainObjExitMonitorWithDriver(driver, vm);
8638 8639 8640 8641
    if (ret < 0)
        goto error;

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

8643
    VIR_FREE(devstr);
8644

8645 8646 8647 8648 8649
    return 0;

error:
    VIR_FREE(devstr);
    return -1;
8650 8651
}

8652

8653
static int qemudDomainAttachHostDevice(struct qemud_driver *driver,
M
Mark McLoughlin 已提交
8654
                                       virDomainObjPtr vm,
8655
                                       virDomainHostdevDefPtr hostdev,
8656
                                       unsigned long long qemuCmdFlags)
M
Mark McLoughlin 已提交
8657 8658
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
8659
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8660 8661
                        _("hostdev mode '%s' not supported"),
                        virDomainHostdevModeTypeToString(hostdev->mode));
M
Mark McLoughlin 已提交
8662 8663 8664
        return -1;
    }

8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681
    /* 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);
    }


8682
    if (driver->securityDriver &&
8683
        driver->securityDriver->domainSetSecurityHostdevLabel &&
8684 8685
        driver->securityDriver->domainSetSecurityHostdevLabel(driver->securityDriver,
                                                              vm, hostdev) < 0)
8686
        return -1;
M
Mark McLoughlin 已提交
8687 8688

    switch (hostdev->source.subsys.type) {
8689
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
8690
        if (qemudDomainAttachHostPciDevice(driver, vm,
8691
                                           hostdev, qemuCmdFlags) < 0)
8692 8693 8694
            goto error;
        break;

M
Mark McLoughlin 已提交
8695
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
8696
        if (qemudDomainAttachHostUsbDevice(driver, vm,
8697
                                           hostdev, qemuCmdFlags) < 0)
8698 8699 8700
            goto error;
        break;

M
Mark McLoughlin 已提交
8701
    default:
8702
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8703 8704
                        _("hostdev subsys type '%s' not supported"),
                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
8705
        goto error;
M
Mark McLoughlin 已提交
8706
    }
8707 8708 8709 8710 8711 8712

    return 0;

error:
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityHostdevLabel &&
8713 8714
        driver->securityDriver->domainRestoreSecurityHostdevLabel(driver->securityDriver,
                                                                  vm, hostdev) < 0)
8715 8716 8717
        VIR_WARN0("Unable to restore host device labelling on hotplug fail");

    return -1;
M
Mark McLoughlin 已提交
8718 8719
}

8720

8721
static int qemudDomainAttachDevice(virDomainPtr dom,
8722 8723
                                   const char *xml)
{
8724 8725 8726
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDeviceDefPtr dev = NULL;
8727
    unsigned long long qemuCmdFlags;
8728
    virCgroupPtr cgroup = NULL;
8729
    int ret = -1;
8730

8731
    qemuDriverLock(driver);
8732
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8733
    if (!vm) {
8734 8735
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8736 8737
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
8738
        goto cleanup;
8739 8740
    }

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

D
Daniel P. Berrange 已提交
8744
    if (!virDomainObjIsActive(vm)) {
8745 8746
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot attach device on inactive domain"));
8747
        goto endjob;
8748 8749
    }

8750
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
8751
                                  VIR_DOMAIN_XML_INACTIVE);
8752
    if (dev == NULL)
8753
        goto endjob;
8754

8755 8756 8757
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
8758
        goto endjob;
8759

8760
    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
8761
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
8762
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) !=0 ) {
8763 8764 8765
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                _("Unable to find cgroup for %s\n"),
                                vm->def->name);
8766
                goto endjob;
8767
            }
8768
            if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0)
8769
                goto endjob;
8770 8771
        }

8772
        switch (dev->data.disk->device) {
8773 8774
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
8775 8776
            ret = qemudDomainChangeEjectableMedia(driver, vm,
                                                  dev->data.disk,
8777 8778
                                                  qemuCmdFlags,
                                                  false);
8779 8780
            if (ret == 0)
                dev->data.disk = NULL;
8781
            break;
8782

8783 8784
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
8785
                ret = qemudDomainAttachUsbMassstorageDevice(driver, vm,
8786
                                                            dev->data.disk, qemuCmdFlags);
8787 8788
                if (ret == 0)
                    dev->data.disk = NULL;
8789
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
8790
                ret = qemudDomainAttachPciDiskDevice(driver, vm,
8791
                                                     dev->data.disk, qemuCmdFlags);
8792 8793
                if (ret == 0)
                    dev->data.disk = NULL;
8794
            } else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
8795
                ret = qemudDomainAttachSCSIDisk(driver, vm,
8796
                                                dev->data.disk, qemuCmdFlags);
8797 8798
                if (ret == 0)
                    dev->data.disk = NULL;
8799
            } else {
8800
                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8801 8802
                                _("disk bus '%s' cannot be hotplugged."),
                                virDomainDiskBusTypeToString(dev->data.disk->bus));
8803
                /* fallthrough */
8804 8805
            }
            break;
8806

8807
        default:
8808
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8809 8810
                            _("disk device type '%s' cannot be hotplugged"),
                            virDomainDiskDeviceTypeToString(dev->data.disk->device));
8811 8812
            /* Fallthrough */
        }
8813
        if (ret != 0 && cgroup) {
8814
            if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
8815 8816
                VIR_WARN("Failed to teardown cgroup for disk path %s",
                         NULLSTR(dev->data.disk->src));
8817
        }
8818 8819
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
8820
            ret = qemudDomainAttachPciControllerDevice(driver, vm,
8821
                                                       dev->data.controller, qemuCmdFlags);
8822 8823
            if (ret == 0)
                dev->data.controller = NULL;
8824
        } else {
8825
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8826 8827
                            _("disk controller bus '%s' cannot be hotplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
8828 8829
            /* fallthrough */
        }
M
Mark McLoughlin 已提交
8830
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
8831 8832
        ret = qemudDomainAttachNetDevice(dom->conn, driver, vm,
                                         dev->data.net, qemuCmdFlags);
8833 8834
        if (ret == 0)
            dev->data.net = NULL;
M
Mark McLoughlin 已提交
8835
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
8836
        ret = qemudDomainAttachHostDevice(driver, vm,
8837
                                          dev->data.hostdev, qemuCmdFlags);
8838 8839
        if (ret == 0)
            dev->data.hostdev = NULL;
8840
    } else {
8841
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
8842 8843
                        _("device type '%s' cannot be attached"),
                        virDomainDeviceTypeToString(dev->type));
8844
        goto endjob;
8845 8846
    }

8847
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
8848 8849
        ret = -1;

8850
endjob:
8851 8852
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
8853

8854
cleanup:
8855 8856 8857
    if (cgroup)
        virCgroupFree(&cgroup);

8858
    virDomainDeviceDefFree(dev);
8859 8860
    if (vm)
        virDomainObjUnlock(vm);
8861
    qemuDriverUnlock(driver);
8862 8863 8864
    return ret;
}

8865 8866 8867 8868
static int qemudDomainAttachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
8869 8870
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
8871 8872 8873 8874 8875 8876
        return -1;
    }

    return qemudDomainAttachDevice(dom, xml);
}

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 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925
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;
        }

8926 8927
        if (STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd, dev->data.vnc.auth.passwd)) {
            VIR_DEBUG("Updating password on VNC server %p %p", dev->data.vnc.auth.passwd, driver->vncPassword);
8928 8929
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            ret = qemuMonitorSetVNCPassword(priv->mon,
8930 8931
                                            dev->data.vnc.auth.passwd ?
                                            dev->data.vnc.auth.passwd :
8932 8933 8934 8935
                                            driver->vncPassword);
            qemuDomainObjExitMonitorWithDriver(driver, vm);

            /* Steal the new dev's  char * reference */
8936 8937 8938
            VIR_FREE(olddev->data.vnc.auth.passwd);
            olddev->data.vnc.auth.passwd = dev->data.vnc.auth.passwd;
            dev->data.vnc.auth.passwd = NULL;
8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954
        } else {
            ret = 0;
        }
        break;

    default:
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unable to change config on '%s' graphics type"),
                        virDomainGraphicsTypeToString(dev->type));
        break;
    }

    return ret;
}


8955 8956 8957 8958 8959 8960 8961 8962 8963 8964
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;
8965
    bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
8966

8967 8968
    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_CURRENT |
                  VIR_DOMAIN_DEVICE_MODIFY_LIVE |
8969 8970
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG |
                  VIR_DOMAIN_DEVICE_MODIFY_FORCE, -1);
8971

8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015
    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;
            }
9016
            if (qemuSetupDiskCgroup(driver, cgroup, dev->data.disk) < 0)
9017 9018 9019 9020 9021 9022
                goto endjob;
        }

        switch (dev->data.disk->device) {
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
        case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
9023 9024
            ret = qemudDomainChangeEjectableMedia(driver, vm,
                                                  dev->data.disk,
9025 9026
                                                  qemuCmdFlags,
                                                  force);
9027 9028 9029 9030 9031 9032
            if (ret == 0)
                dev->data.disk = NULL;
            break;


        default:
9033
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9034 9035 9036 9037 9038 9039
                            _("disk bus '%s' cannot be updated."),
                            virDomainDiskBusTypeToString(dev->data.disk->bus));
            break;
        }

        if (ret != 0 && cgroup) {
9040
            if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
9041 9042
                VIR_WARN("Failed to teardown cgroup for disk path %s",
                         NULLSTR(dev->data.disk->src));
9043 9044 9045
        }
        break;

9046 9047 9048 9049
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;

9050
    default:
9051
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075
                        _("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 已提交
9076
static inline int qemudFindDisk(virDomainDefPtr def, const char *dst)
W
Wolfgang Mauerer 已提交
9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089
{
    int i;

    for (i = 0 ; i < def->ndisks ; i++) {
        if (STREQ(def->disks[i]->dst, dst)) {
            return i;
        }
    }

    return -1;
}


9090
static int qemudDomainDetachPciDiskDevice(struct qemud_driver *driver,
9091
                                          virDomainObjPtr vm,
9092 9093
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
9094 9095 9096
{
    int i, ret = -1;
    virDomainDiskDefPtr detach = NULL;
9097
    qemuDomainObjPrivatePtr priv = vm->privateData;
9098
    virCgroupPtr cgroup = NULL;
9099

W
Wolfgang Mauerer 已提交
9100
    i = qemudFindDisk(vm->def, dev->data.disk->dst);
9101

W
Wolfgang Mauerer 已提交
9102
    if (i < 0) {
9103 9104
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk %s not found"), dev->data.disk->dst);
9105
        goto cleanup;
9106 9107
    }

W
Wolfgang Mauerer 已提交
9108 9109
    detach = vm->def->disks[i];

9110 9111 9112 9113 9114 9115 9116 9117 9118
    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;
        }
    }

9119 9120
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
9121 9122
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("device cannot be detached without a PCI address"));
9123
        goto cleanup;
9124 9125
    }

9126
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137
    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;
        }
9138
    }
9139
    qemuDomainObjExitMonitorWithDriver(driver, vm);
9140

9141 9142
    qemuDomainDiskAudit(vm, detach, NULL, "detach", ret >= 0);

9143 9144 9145 9146
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
        VIR_WARN("Unable to release PCI address on %s", dev->data.disk->src);

9147
    virDomainDiskRemove(vm->def, i);
W
Wolfgang Mauerer 已提交
9148

9149 9150
    virDomainDiskDefFree(detach);

9151 9152
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
9153 9154
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, dev->data.disk) < 0)
9155 9156
        VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);

9157
    if (cgroup != NULL) {
9158
        if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
9159 9160 9161 9162
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(dev->data.disk->src));
    }

9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176
    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;
9177
    virCgroupPtr cgroup = NULL;
9178 9179 9180 9181 9182 9183 9184 9185 9186 9187

    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)) {
9188
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
9189 9190 9191 9192 9193 9194
                        _("Underlying qemu does not support SCSI disk removal"));
        goto cleanup;
    }

    detach = vm->def->disks[i];

9195 9196 9197 9198 9199 9200 9201 9202 9203
    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;
        }
    }

9204 9205 9206 9207 9208 9209 9210
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
        qemuDomainObjExitMonitor(vm);
        goto cleanup;
    }
    qemuDomainObjExitMonitorWithDriver(driver, vm);

9211 9212
    qemuDomainDiskAudit(vm, detach, NULL, "detach", ret >= 0);

9213
    virDomainDiskRemove(vm->def, i);
9214

9215
    virDomainDiskDefFree(detach);
9216

9217 9218
    if (driver->securityDriver &&
        driver->securityDriver->domainRestoreSecurityImageLabel &&
9219 9220
        driver->securityDriver->domainRestoreSecurityImageLabel(driver->securityDriver,
                                                                vm, dev->data.disk) < 0)
9221 9222
        VIR_WARN("Unable to restore security label on %s", dev->data.disk->src);

9223
    if (cgroup != NULL) {
9224
        if (qemuTeardownDiskCgroup(driver, cgroup, dev->data.disk) < 0)
9225 9226 9227 9228
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(dev->data.disk->src));
    }

9229
    ret = 0;
9230 9231

cleanup:
9232
    virCgroupFree(&cgroup);
9233 9234 9235
    return ret;
}

9236
static int qemudDomainDetachPciControllerDevice(struct qemud_driver *driver,
9237
                                                virDomainObjPtr vm,
9238 9239
                                                virDomainDeviceDefPtr dev,
                                                unsigned long long qemuCmdFlags)
9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253
{
    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) {
9254 9255 9256 9257
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("disk controller %s:%d not found"),
                        virDomainControllerTypeToString(dev->data.controller->type),
                        dev->data.controller->idx);
9258 9259 9260 9261 9262
        goto cleanup;
    }

    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
9263 9264
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("device cannot be detached without a PCI address"));
9265 9266 9267
        goto cleanup;
    }

9268 9269 9270 9271 9272
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuAssignDeviceControllerAlias(detach) < 0)
            goto cleanup;
    }

9273
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284
    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;
        }
9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300
    }
    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;
    }
9301

9302 9303
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
9304 9305
        VIR_WARN0("Unable to release PCI address on controller");

9306 9307 9308 9309 9310 9311 9312 9313
    virDomainControllerDefFree(detach);

    ret = 0;

cleanup:
    return ret;
}

9314
static int
9315
qemudDomainDetachNetDevice(struct qemud_driver *driver,
9316
                           virDomainObjPtr vm,
9317 9318
                           virDomainDeviceDefPtr dev,
                           unsigned long long qemuCmdFlags)
9319 9320 9321
{
    int i, ret = -1;
    virDomainNetDefPtr detach = NULL;
9322
    qemuDomainObjPrivatePtr priv = vm->privateData;
9323 9324
    int vlan;
    char *hostnet_name = NULL;
9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335

    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) {
9336 9337 9338 9339 9340
        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]);
9341 9342 9343
        goto cleanup;
    }

9344 9345
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
9346 9347
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a PCI address"));
9348 9349 9350
        goto cleanup;
    }

9351
    if ((vlan = qemuDomainNetVLAN(detach)) < 0) {
9352 9353
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("unable to determine original VLAN"));
9354 9355 9356 9357
        goto cleanup;
    }

    if (virAsprintf(&hostnet_name, "host%s", detach->info.alias) < 0) {
9358
        virReportOOMError();
9359 9360 9361
        goto cleanup;
    }

9362
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9363 9364 9365
    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
        if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
            qemuDomainObjExitMonitor(vm);
9366
            qemuDomainNetAudit(vm, detach, NULL, "detach", false);
9367 9368 9369 9370 9371 9372
            goto cleanup;
        }
    } else {
        if (qemuMonitorRemovePCIDevice(priv->mon,
                                       &detach->info.addr.pci) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
9373
            qemuDomainNetAudit(vm, detach, NULL, "detach", false);
9374 9375
            goto cleanup;
        }
9376
    }
9377

9378 9379 9380 9381
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
        if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
9382
            qemuDomainNetAudit(vm, detach, NULL, "detach", false);
9383 9384 9385 9386 9387
            goto cleanup;
        }
    } else {
        if (qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
            qemuDomainObjExitMonitorWithDriver(driver, vm);
9388
            qemuDomainNetAudit(vm, detach, NULL, "detach", false);
9389 9390
            goto cleanup;
        }
9391
    }
9392
    qemuDomainObjExitMonitorWithDriver(driver, vm);
9393

9394 9395
    qemuDomainNetAudit(vm, detach, NULL, "detach", true);

9396 9397 9398 9399
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
        VIR_WARN0("Unable to release PCI address on NIC");

9400
    virDomainConfNWFilterTeardown(detach);
9401

9402
#if WITH_MACVTAP
9403
    if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
9404
        delMacvtap(detach->ifname, detach->mac, detach->data.direct.linkdev,
9405
                   &detach->data.direct.virtPortProfile);
9406 9407
        VIR_FREE(detach->ifname);
    }
9408 9409
#endif

9410
    if ((driver->macFilter) && (detach->ifname != NULL)) {
9411
        if ((errno = networkDisallowMacOnPort(driver,
9412 9413
                                              detach->ifname,
                                              detach->mac))) {
9414
            virReportSystemError(errno,
9415 9416 9417 9418 9419
             _("failed to remove ebtables rule on  '%s'"),
                                 detach->ifname);
        }
    }

9420 9421 9422 9423 9424 9425 9426 9427 9428 9429
    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 {
9430
        VIR_FREE(vm->def->nets);
9431
        vm->def->nnets = 0;
9432
    }
9433
    virDomainNetDefFree(detach);
9434

9435 9436 9437
    ret = 0;

cleanup:
9438
    VIR_FREE(hostnet_name);
9439 9440 9441
    return ret;
}

9442
static int qemudDomainDetachHostPciDevice(struct qemud_driver *driver,
9443
                                          virDomainObjPtr vm,
9444 9445
                                          virDomainDeviceDefPtr dev,
                                          unsigned long long qemuCmdFlags)
9446
{
9447
    virDomainHostdevDefPtr detach = NULL;
9448
    qemuDomainObjPrivatePtr priv = vm->privateData;
9449
    int i, ret;
9450
    pciDevice *pci;
9451 9452

    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
9453 9454 9455 9456
        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;

9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471
        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) {
9472 9473 9474 9475 9476 9477
        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);
9478 9479 9480
        return -1;
    }

9481 9482
    if (!virDomainDeviceAddressIsValid(&detach->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
9483 9484
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("device cannot be detached without a PCI address"));
9485 9486 9487
        return -1;
    }

9488
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499
    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;
        }
9500
    }
9501
    qemuDomainObjExitMonitorWithDriver(driver, vm);
9502 9503 9504

    ret = 0;

9505
    pci = pciGetDevice(detach->source.subsys.u.pci.domain,
9506 9507 9508 9509 9510 9511
                       detach->source.subsys.u.pci.bus,
                       detach->source.subsys.u.pci.slot,
                       detach->source.subsys.u.pci.function);
    if (!pci)
        ret = -1;
    else {
9512
        pciDeviceSetManaged(pci, detach->managed);
9513
        pciDeviceListDel(driver->activePciHostdevs, pci);
9514
        if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
9515
            ret = -1;
9516
        qemudReattachPciDevice(pci, driver);
9517
        pciFreeDevice(pci);
9518 9519
    }

9520 9521
    if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
        qemuDomainPCIAddressReleaseAddr(priv->pciaddrs, &detach->info) < 0)
9522
        VIR_WARN0("Unable to release PCI address on host device");
9523

9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535
    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;
9536
    }
9537
    virDomainHostdevDefFree(detach);
9538 9539 9540 9541

    return ret;
}

9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557
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;
9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573
        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;
            }
9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623
        }
    }

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

9624
static int qemudDomainDetachHostDevice(struct qemud_driver *driver,
9625
                                       virDomainObjPtr vm,
9626 9627
                                       virDomainDeviceDefPtr dev,
                                       unsigned long long qemuCmdFlags)
9628 9629 9630 9631 9632
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
    int ret;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
9633
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9634 9635
                        _("hostdev mode '%s' not supported"),
                        virDomainHostdevModeTypeToString(hostdev->mode));
9636 9637 9638 9639 9640
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
9641
        ret = qemudDomainDetachHostPciDevice(driver, vm, dev, qemuCmdFlags);
9642
        break;
9643 9644 9645
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        ret = qemudDomainDetachHostUsbDevice(driver, vm, dev, qemuCmdFlags);
        break;
9646
    default:
9647
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9648 9649
                        _("hostdev subsys type '%s' not supported"),
                        virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
9650 9651 9652
        return -1;
    }

9653
    if (driver->securityDriver &&
9654
        driver->securityDriver->domainRestoreSecurityHostdevLabel &&
9655 9656
        driver->securityDriver->domainRestoreSecurityHostdevLabel(driver->securityDriver,
                                                                  vm, dev->data.hostdev) < 0)
9657
        VIR_WARN0("Failed to restore host device labelling");
9658

9659 9660 9661
    return ret;
}

9662 9663
static int qemudDomainDetachDevice(virDomainPtr dom,
                                   const char *xml) {
9664 9665
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
9666
    unsigned long long qemuCmdFlags;
9667 9668
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;
9669

9670
    qemuDriverLock(driver);
9671
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
9672
    if (!vm) {
9673 9674
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9675 9676
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9677
        goto cleanup;
9678 9679
    }

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

D
Daniel P. Berrange 已提交
9683
    if (!virDomainObjIsActive(vm)) {
9684 9685
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot detach device on inactive domain"));
9686
        goto endjob;
9687 9688
    }

9689
    dev = virDomainDeviceDefParse(driver->caps, vm->def, xml,
9690
                                  VIR_DOMAIN_XML_INACTIVE);
9691
    if (dev == NULL)
9692
        goto endjob;
9693

9694 9695 9696 9697
    if (qemudExtractVersionInfo(vm->def->emulator,
                                NULL,
                                &qemuCmdFlags) < 0)
        goto endjob;
9698 9699

    if (dev->type == VIR_DOMAIN_DEVICE_DISK &&
9700 9701 9702 9703 9704 9705 9706 9707 9708
        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 {
9709
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
9710 9711
                            _("This type of disk cannot be hot unplugged"));
        }
9712
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
9713
        ret = qemudDomainDetachNetDevice(driver, vm, dev, qemuCmdFlags);
9714 9715
    } else if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
        if (dev->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
9716 9717
            ret = qemudDomainDetachPciControllerDevice(driver, vm, dev,
                                                       qemuCmdFlags);
9718
        } else {
9719
            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9720 9721
                            _("disk controller bus '%s' cannot be hotunplugged."),
                            virDomainControllerTypeToString(dev->data.controller->type));
9722 9723
            /* fallthrough */
        }
9724
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
9725
        ret = qemudDomainDetachHostDevice(driver, vm, dev, qemuCmdFlags);
9726
    } else {
9727
        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9728
                        "%s", _("This type of device cannot be hot unplugged"));
9729
    }
9730

9731
    if (!ret && virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
9732 9733
        ret = -1;

9734
endjob:
9735 9736
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
9737

9738 9739
cleanup:
    virDomainDeviceDefFree(dev);
9740 9741
    if (vm)
        virDomainObjUnlock(vm);
9742
    qemuDriverUnlock(driver);
9743 9744 9745
    return ret;
}

9746 9747 9748 9749
static int qemudDomainDetachDeviceFlags(virDomainPtr dom,
                                        const char *xml,
                                        unsigned int flags) {
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
9750 9751
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify the persistent configuration of a domain"));
9752 9753 9754 9755 9756 9757
        return -1;
    }

    return qemudDomainDetachDevice(dom, xml);
}

9758
static int qemudDomainGetAutostart(virDomainPtr dom,
9759
                                   int *autostart) {
9760 9761 9762
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
9763

9764
    qemuDriverLock(driver);
9765
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
9766 9767
    qemuDriverUnlock(driver);

9768
    if (!vm) {
9769 9770
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9771 9772
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9773
        goto cleanup;
9774 9775 9776
    }

    *autostart = vm->autostart;
9777
    ret = 0;
9778

9779
cleanup:
9780 9781
    if (vm)
        virDomainObjUnlock(vm);
9782
    return ret;
9783 9784
}

9785
static int qemudDomainSetAutostart(virDomainPtr dom,
9786
                                   int autostart) {
9787 9788
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
9789 9790
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
9791

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

9795
    if (!vm) {
9796 9797
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9798 9799
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
9800
        goto cleanup;
9801 9802
    }

9803
    if (!vm->persistent) {
9804 9805
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("cannot set autostart for transient domain"));
9806
        goto cleanup;
9807 9808
    }

9809 9810
    autostart = (autostart != 0);

9811
    if (vm->autostart != autostart) {
9812
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
9813
            goto cleanup;
9814
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
9815
            goto cleanup;
9816

9817 9818
        if (autostart) {
            int err;
9819

9820
            if ((err = virFileMakePath(driver->autostartDir))) {
9821
                virReportSystemError(err,
9822 9823
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
9824 9825
                goto cleanup;
            }
9826

9827
            if (symlink(configFile, autostartLink) < 0) {
9828
                virReportSystemError(errno,
9829 9830
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
9831 9832 9833 9834
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
9835
                virReportSystemError(errno,
9836 9837
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
9838 9839
                goto cleanup;
            }
9840 9841
        }

9842
        vm->autostart = autostart;
9843
    }
9844
    ret = 0;
9845

9846 9847 9848
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
9849 9850
    if (vm)
        virDomainObjUnlock(vm);
9851
    qemuDriverUnlock(driver);
9852
    return ret;
9853 9854
}

9855 9856 9857 9858 9859

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

9862
    qemuDriverLock(driver);
9863
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
9864 9865
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
9866
        goto cleanup;
9867 9868 9869 9870 9871 9872 9873
    }

    if (nparams)
        *nparams = 1;

    ret = strdup("posix");
    if (!ret)
9874
        virReportOOMError();
9875 9876 9877

cleanup:
    qemuDriverUnlock(driver);
9878 9879 9880
    return ret;
}

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 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947

static int qemuDomainSetMemoryParameters(virDomainPtr dom,
                                         virMemoryParameterPtr params,
                                         int nparams,
                                         unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

    qemuDriverLock(driver);
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
        goto cleanup;
    }

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

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
        goto cleanup;
    }

    ret = 0;
    for (i = 0; i < nparams; i++) {
        virMemoryParameterPtr param = &params[i];

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            int rc;
            if (param->type != VIR_DOMAIN_MEMORY_PARAM_ULLONG) {
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for memory hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

            rc = virCgroupSetMemoryHardLimit(group, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory hard_limit tunable"));
                ret = -1;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
            int rc;
            if (param->type != VIR_DOMAIN_MEMORY_PARAM_ULLONG) {
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for memory soft_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

            rc = virCgroupSetMemorySoftLimit(group, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory soft_limit tunable"));
                ret = -1;
            }
9948
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
9949 9950 9951 9952 9953 9954 9955 9956 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
            int rc;
            if (param->type != VIR_DOMAIN_MEMORY_PARAM_ULLONG) {
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for swap_hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

            rc = virCgroupSetSwapHardLimit(group, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set swap_hard_limit tunable"));
                ret = -1;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Memory tunable `%s' not implemented"), param->field);
            ret = -1;
        } else {
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Parameter `%s' not supported"), param->field);
            ret = -1;
        }
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 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
static int qemuDomainGetMemoryParameters(virDomainPtr dom,
                                         virMemoryParameterPtr params,
                                         int *nparams,
                                         unsigned int flags ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    unsigned long val;
    int ret = -1;
    int rc;

    qemuDriverLock(driver);

    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
        goto cleanup;
    }

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

    if (vm == NULL) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
        goto cleanup;
    }

    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

    if ((*nparams) != QEMU_NB_MEM_PARAM) {
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
        goto cleanup;
    }

    for (i = 0; i < *nparams; i++) {
        virMemoryParameterPtr param = &params[i];
        val = 0;
        param->value.ul = 0;
        param->type = VIR_DOMAIN_MEMORY_PARAM_ULLONG;

        switch(i) {
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
10042
                goto cleanup;
10043 10044 10045 10046
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field memory hard limit too long for destination"));
10047
                goto cleanup;
10048 10049 10050 10051 10052 10053 10054 10055 10056
            }
            param->value.ul = val;
            break;

        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
10057
                goto cleanup;
10058 10059 10060 10061
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) {
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field memory soft limit too long for destination"));
10062
                goto cleanup;
10063 10064 10065 10066 10067 10068 10069 10070 10071
            }
            param->value.ul = val;
            break;

        case 2: /* fill swap hard limit here */
            rc = virCgroupGetSwapHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
10072
                goto cleanup;
10073
            }
10074
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT) == NULL) {
10075 10076
                qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("Field swap hard limit too long for destination"));
10077
                goto cleanup;
10078 10079 10080 10081 10082 10083 10084 10085 10086 10087
            }
            param->value.ul = val;
            break;

        default:
            break;
            /* should not hit here */
        }
    }

10088 10089
    ret = 0;

10090 10091 10092 10093 10094 10095 10096 10097 10098
cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

10099 10100 10101 10102 10103 10104 10105 10106 10107 10108
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;

10109
    qemuDriverLock(driver);
10110
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
10111 10112
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
10113
        goto cleanup;
10114 10115 10116 10117 10118
    }

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

    if (vm == NULL) {
10119 10120
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
10121 10122 10123 10124
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
10125 10126
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
10127 10128 10129 10130 10131 10132 10133 10134 10135
        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) {
10136 10137
                qemuReportError(VIR_ERR_INVALID_ARG, "%s",
                                _("invalid type for cpu_shares tunable, expected a 'ullong'"));
10138 10139 10140 10141 10142
                goto cleanup;
            }

            rc = virCgroupSetCpuShares(group, params[i].value.ul);
            if (rc != 0) {
10143
                virReportSystemError(-rc, "%s",
10144 10145 10146 10147
                                     _("unable to set cpu shares tunable"));
                goto cleanup;
            }
        } else {
10148 10149
            qemuReportError(VIR_ERR_INVALID_ARG,
                            _("Invalid parameter `%s'"), param->field);
10150 10151 10152 10153 10154 10155 10156 10157 10158
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
10159
    qemuDriverUnlock(driver);
10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173
    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;

10174
    qemuDriverLock(driver);
10175
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
10176 10177
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        __FUNCTION__);
10178
        goto cleanup;
10179 10180 10181
    }

    if ((*nparams) != 1) {
10182 10183
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("Invalid parameter count"));
10184
        goto cleanup;
10185 10186 10187 10188 10189
    }

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

    if (vm == NULL) {
10190 10191
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("No such domain %s"), dom->uuid);
10192 10193 10194 10195
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
10196 10197
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find cgroup for domain %s"), vm->def->name);
10198 10199 10200 10201 10202
        goto cleanup;
    }

    rc = virCgroupGetCpuShares(group, &val);
    if (rc != 0) {
10203
        virReportSystemError(-rc, "%s",
10204 10205 10206 10207 10208
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
    params[0].value.ul = val;
    params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
C
Chris Lalancette 已提交
10209
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
10210 10211
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Field cpu_shares too long for destination"));
C
Chris Lalancette 已提交
10212 10213
        goto cleanup;
    }
10214 10215 10216 10217 10218 10219 10220

    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
10221
    qemuDriverUnlock(driver);
10222 10223 10224 10225
    return ret;
}


10226 10227 10228 10229 10230 10231 10232 10233 10234
/* 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)
{
10235
    struct qemud_driver *driver = dom->conn->privateData;
10236
    int i, ret = -1;
10237
    virDomainObjPtr vm;
10238
    virDomainDiskDefPtr disk = NULL;
10239

10240
    qemuDriverLock(driver);
10241
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
10242
    qemuDriverUnlock(driver);
10243
    if (!vm) {
10244 10245
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10246 10247
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
10248
        goto cleanup;
10249
    }
10250 10251 10252 10253

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

D
Daniel P. Berrange 已提交
10254
    if (!virDomainObjIsActive (vm)) {
10255 10256
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
10257
        goto endjob;
10258 10259
    }

10260 10261 10262 10263 10264 10265 10266 10267
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (STREQ(path, vm->def->disks[i]->dst)) {
            disk = vm->def->disks[i];
            break;
        }
    }

    if (!disk) {
10268 10269
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path: %s"), path);
10270
        goto endjob;
10271 10272
    }

10273
    if (!disk->info.alias) {
10274 10275
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("missing disk device alias name for %s"), disk->dst);
10276
        goto endjob;
10277
    }
10278

10279
    qemuDomainObjPrivatePtr priv = vm->privateData;
10280 10281
    qemuDomainObjEnterMonitor(vm);
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
10282
                                       disk->info.alias,
10283 10284 10285 10286 10287 10288
                                       &stats->rd_req,
                                       &stats->rd_bytes,
                                       &stats->wr_req,
                                       &stats->wr_bytes,
                                       &stats->errs);
    qemuDomainObjExitMonitor(vm);
10289

10290
endjob:
10291 10292
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
10293

10294
cleanup:
10295 10296
    if (vm)
        virDomainObjUnlock(vm);
10297
    return ret;
10298 10299
}

10300
#ifdef __linux__
10301 10302 10303 10304 10305
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
10306 10307
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
10308
    int i;
10309
    int ret = -1;
10310

10311
    qemuDriverLock(driver);
10312
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
10313 10314
    qemuDriverUnlock(driver);

10315
    if (!vm) {
10316 10317
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10318 10319
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
10320
        goto cleanup;
10321 10322
    }

D
Daniel P. Berrange 已提交
10323
    if (!virDomainObjIsActive(vm)) {
10324 10325
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
10326
        goto cleanup;
10327 10328 10329
    }

    /* Check the path is one of the domain's network interfaces. */
10330 10331
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
10332 10333 10334 10335
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
10336 10337
    }

10338
    if (ret == 0)
10339
        ret = linuxDomainInterfaceStats(path, stats);
10340
    else
10341 10342
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("invalid path, '%s' is not a known interface"), path);
10343

10344
cleanup:
10345 10346
    if (vm)
        virDomainObjUnlock(vm);
10347 10348
    return ret;
}
10349
#else
10350 10351 10352 10353
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
10354 10355
    qemuReportError(VIR_ERR_NO_SUPPORT,
                    "%s", __FUNCTION__);
10356 10357
    return -1;
}
10358
#endif
10359

10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375
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);
10376 10377
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
10378 10379 10380
        goto cleanup;
    }

10381 10382 10383
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

10384 10385 10386
    if (virDomainObjIsActive(vm)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        qemuDomainObjEnterMonitor(vm);
10387
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
10388 10389
        qemuDomainObjExitMonitor(vm);
    } else {
10390 10391
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
10392 10393
    }

10394 10395 10396
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

10397 10398 10399 10400 10401 10402
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

10403 10404 10405 10406 10407 10408 10409
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
                      unsigned int flags ATTRIBUTE_UNUSED)
{
10410 10411 10412
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int fd = -1, ret = -1, i;
10413

10414
    qemuDriverLock(driver);
10415
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
10416 10417
    qemuDriverUnlock(driver);

10418
    if (!vm) {
10419 10420
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10421 10422
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
10423
        goto cleanup;
10424 10425 10426
    }

    if (!path || path[0] == '\0') {
10427 10428
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("NULL or empty path"));
10429
        goto cleanup;
10430 10431 10432
    }

    /* Check the path belongs to this domain. */
10433 10434
    for (i = 0 ; i < vm->def->ndisks ; i++) {
        if (vm->def->disks[i]->src != NULL &&
10435 10436 10437 10438
            STREQ (vm->def->disks[i]->src, path)) {
            ret = 0;
            break;
        }
10439 10440
    }

10441 10442 10443 10444 10445
    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) {
10446 10447
            virReportSystemError(errno,
                                 _("%s: failed to open"), path);
10448 10449
            goto cleanup;
        }
10450

10451 10452 10453 10454 10455 10456
        /* 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) {
10457 10458
            virReportSystemError(errno,
                                 _("%s: failed to seek or read"), path);
10459 10460 10461 10462 10463
            goto cleanup;
        }

        ret = 0;
    } else {
10464 10465
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("invalid path"));
10466 10467
    }

10468
cleanup:
10469
    VIR_FORCE_CLOSE(fd);
10470 10471
    if (vm)
        virDomainObjUnlock(vm);
10472 10473 10474
    return ret;
}

R
Richard W.M. Jones 已提交
10475 10476 10477 10478 10479 10480
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
10481 10482
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
10483
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
10484 10485
    int fd = -1, ret = -1;

10486
    qemuDriverLock(driver);
10487
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
10488
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
10489 10490

    if (!vm) {
10491 10492
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10493 10494
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
10495 10496 10497
        goto cleanup;
    }

10498
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
10499 10500
        qemuReportError(VIR_ERR_INVALID_ARG,
                        "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
10501
        goto cleanup;
R
Richard W.M. Jones 已提交
10502 10503
    }

10504 10505 10506
    if (qemuDomainObjBeginJob(vm) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
10507
    if (!virDomainObjIsActive(vm)) {
10508 10509
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
10510
        goto endjob;
R
Richard W.M. Jones 已提交
10511 10512
    }

10513
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", driver->cacheDir) < 0) {
10514
        virReportOOMError();
10515
        goto endjob;
10516 10517
    }

R
Richard W.M. Jones 已提交
10518 10519
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
10520 10521
        virReportSystemError(errno,
                             _("mkstemp(\"%s\") failed"), tmp);
10522
        goto endjob;
R
Richard W.M. Jones 已提交
10523 10524
    }

10525
    qemuDomainObjPrivatePtr priv = vm->privateData;
10526
    qemuDomainObjEnterMonitor(vm);
10527
    if (flags == VIR_MEMORY_VIRTUAL) {
10528 10529
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
10530
            goto endjob;
10531
        }
10532
    } else {
10533 10534
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
            qemuDomainObjExitMonitor(vm);
10535
            goto endjob;
10536
        }
R
Richard W.M. Jones 已提交
10537
    }
10538
    qemuDomainObjExitMonitor(vm);
R
Richard W.M. Jones 已提交
10539 10540 10541

    /* Read the memory file into buffer. */
    if (saferead (fd, buffer, size) == (ssize_t) -1) {
10542 10543 10544
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
10545
        goto endjob;
R
Richard W.M. Jones 已提交
10546 10547 10548
    }

    ret = 0;
10549

10550
endjob:
10551 10552
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
10553

10554
cleanup:
10555
    VIR_FREE(tmp);
10556
    VIR_FORCE_CLOSE(fd);
R
Richard W.M. Jones 已提交
10557
    unlink (tmp);
10558 10559
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
10560 10561 10562
    return ret;
}

10563

10564 10565 10566 10567 10568 10569 10570 10571 10572 10573
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;
10574
    virDomainDiskDefPtr disk = NULL;
10575 10576
    struct stat sb;
    int i;
10577
    int format;
10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601

    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)) {
10602
            disk = vm->def->disks[i];
10603 10604 10605 10606
            break;
        }
    }

10607
    if (!disk) {
10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621
        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 */
10622 10623 10624 10625 10626 10627 10628 10629
    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 {
10630 10631 10632 10633 10634 10635 10636
        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);
10637
            goto cleanup;
10638
        }
10639 10640 10641 10642 10643
    }

    if (virStorageFileGetMetadataFromFD(path, fd,
                                        format,
                                        &meta) < 0)
10644 10645 10646 10647 10648 10649 10650 10651 10652 10653
        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)) {
10654
#ifndef WIN32
10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682
        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;

10683
    /* Set default value .. */
10684 10685
    info->allocation = info->physical;

10686 10687 10688
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
10689
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
10690
        format != VIR_STORAGE_FILE_RAW &&
10691 10692 10693 10694
        S_ISBLK(sb.st_mode)) {
        qemuDomainObjPrivatePtr priv = vm->privateData;
        if (qemuDomainObjBeginJob(vm) < 0)
            goto cleanup;
10695 10696 10697 10698 10699 10700 10701 10702 10703
        if (!virDomainObjIsActive(vm))
            ret = 0;
        else {
            qemuDomainObjEnterMonitor(vm);
            ret = qemuMonitorGetBlockExtent(priv->mon,
                                            disk->info.alias,
                                            &info->allocation);
            qemuDomainObjExitMonitor(vm);
        }
10704 10705 10706 10707 10708 10709

        if (qemuDomainObjEndJob(vm) == 0)
            vm = NULL;
    } else {
        ret = 0;
    }
10710 10711

cleanup:
10712
    VIR_FORCE_CLOSE(fd);
10713 10714 10715 10716 10717 10718
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


10719
static int
10720 10721 10722 10723
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
10724
{
10725 10726 10727
    struct qemud_driver *driver = conn->privateData;
    int ret;

10728
    qemuDriverLock(driver);
10729 10730
    ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
                                        callback, opaque, freecb);
10731
    qemuDriverUnlock(driver);
10732

10733
    return ret;
10734 10735
}

10736

10737
static int
10738 10739
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
10740
{
10741 10742 10743
    struct qemud_driver *driver = conn->privateData;
    int ret;

10744
    qemuDriverLock(driver);
10745 10746 10747 10748 10749 10750
    if (driver->domainEventDispatching)
        ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
                                                   callback);
    else
        ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
                                               callback);
10751
    qemuDriverUnlock(driver);
10752

10753
    return ret;
10754 10755
}

10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798

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


10799 10800
static void qemuDomainEventDispatchFunc(virConnectPtr conn,
                                        virDomainEventPtr event,
10801
                                        virConnectDomainEventGenericCallback cb,
10802 10803
                                        void *cbopaque,
                                        void *opaque)
10804
{
10805
    struct qemud_driver *driver = opaque;
10806

10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850
    /* 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);
10851 10852
}

D
Daniel Veillard 已提交
10853 10854
/* Migration support. */

10855 10856 10857 10858 10859
static bool ATTRIBUTE_NONNULL(1)
qemuDomainIsMigratable(virDomainDefPtr def)
{
    if (def->nhostdevs > 0) {
        qemuReportError(VIR_ERR_OPERATION_INVALID,
10860
            "%s", _("Domain with assigned host devices cannot be migrated"));
10861 10862 10863 10864 10865 10866
        return false;
    }

    return true;
}

C
Chris Lalancette 已提交
10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887
/* 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;
10888
    unsigned long long qemuCmdFlags;
10889 10890 10891 10892 10893 10894 10895 10896
    qemuDomainObjPrivatePtr priv = NULL;
    struct timeval now;

    if (gettimeofday(&now, NULL) < 0) {
        virReportSystemError(errno, "%s",
                             _("cannot get time of day"));
        return -1;
    }
C
Chris Lalancette 已提交
10897 10898 10899

    qemuDriverLock(driver);
    if (!dom_xml) {
10900 10901
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
10902 10903 10904
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
10905
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
10906 10907 10908 10909
                         "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }
    if (st == NULL) {
10910 10911
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
10912 10913 10914 10915
        goto cleanup;
    }

    /* Parse the domain XML. */
10916
    if (!(def = virDomainDefParseString(driver->caps, dom_xml,
C
Chris Lalancette 已提交
10917
                                        VIR_DOMAIN_XML_INACTIVE))) {
10918 10919
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
C
Chris Lalancette 已提交
10920 10921 10922
        goto cleanup;
    }

10923 10924 10925
    if (!qemuDomainIsMigratable(def))
        goto cleanup;

C
Chris Lalancette 已提交
10926
    /* Target domain name, maybe renamed. */
10927 10928 10929 10930 10931 10932
    if (dname) {
        VIR_FREE(def->name);
        def->name = strdup(dname);
        if (def->name == NULL)
            goto cleanup;
    }
C
Chris Lalancette 已提交
10933

10934 10935
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
C
Chris Lalancette 已提交
10936

10937
    if (!(vm = virDomainAssignDef(driver->caps,
C
Chris Lalancette 已提交
10938
                                  &driver->domains,
10939
                                  def, true))) {
10940
        /* virDomainAssignDef already set the error */
C
Chris Lalancette 已提交
10941 10942 10943
        goto cleanup;
    }
    def = NULL;
10944
    priv = vm->privateData;
C
Chris Lalancette 已提交
10945

10946 10947
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
10948
    priv->jobActive = QEMU_JOB_MIGRATION_OUT;
10949

C
Chris Lalancette 已提交
10950 10951 10952 10953
    /* Domain starts inactive, even if the domain XML had an id field. */
    vm->def->id = -1;

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.dest.%s",
10954
                    driver->libDir, vm->def->name) < 0) {
10955
        virReportOOMError();
10956
        goto endjob;
C
Chris Lalancette 已提交
10957 10958 10959 10960 10961
    }
    unlink(unixfile);

    /* check that this qemu version supports the interactive exec */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
10962 10963 10964
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot determine QEMU argv syntax %s"),
                        vm->def->emulator);
10965
        goto endjob;
C
Chris Lalancette 已提交
10966 10967 10968 10969 10970 10971
    }
    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 {
10972 10973
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("Destination qemu is too old to support tunnelled migration"));
10974
        goto endjob;
C
Chris Lalancette 已提交
10975 10976
    }
    if (internalret < 0) {
10977
        virReportOOMError();
10978
        goto endjob;
C
Chris Lalancette 已提交
10979 10980 10981 10982
    }
    /* Start the QEMU daemon, with the same command-line arguments plus
     * -incoming unix:/path/to/file or exec:nc -U /path/to/file
     */
10983 10984
    internalret = qemudStartVMDaemon(dconn, driver, vm, migrateFrom, true,
                                     -1, NULL);
C
Chris Lalancette 已提交
10985 10986
    VIR_FREE(migrateFrom);
    if (internalret < 0) {
10987
        qemuDomainStartAudit(vm, "migrated", false);
C
Chris Lalancette 已提交
10988 10989 10990 10991 10992 10993 10994
        /* 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;
        }
10995
        goto endjob;
C
Chris Lalancette 已提交
10996 10997
    }

10998 10999 11000
    if (virFDStreamConnectUNIX(st,
                               unixfile,
                               false) < 0) {
11001
        qemuDomainStartAudit(vm, "migrated", false);
11002
        qemudShutdownVMDaemon(driver, vm, 0);
11003
        if (!vm->persistent) {
11004 11005
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
11006 11007
            vm = NULL;
        }
11008
        virReportSystemError(errno,
C
Chris Lalancette 已提交
11009 11010
                             _("cannot open unix socket '%s' for tunnelled migration"),
                             unixfile);
11011
        goto endjob;
C
Chris Lalancette 已提交
11012 11013
    }

11014
    qemuDomainStartAudit(vm, "migrated", true);
11015

C
Chris Lalancette 已提交
11016 11017 11018 11019 11020
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_MIGRATED);
    ret = 0;

11021
endjob:
11022 11023 11024
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
11025

11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037
    /* 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 已提交
11038 11039
cleanup:
    virDomainDefFree(def);
11040 11041
    if (unixfile)
        unlink(unixfile);
C
Chris Lalancette 已提交
11042 11043 11044 11045 11046 11047 11048 11049 11050
    VIR_FREE(unixfile);
    if (vm)
        virDomainObjUnlock(vm);
    if (event)
        qemuDomainEventQueue(driver, event);
    qemuDriverUnlock(driver);
    return ret;
}

D
Daniel Veillard 已提交
11051 11052 11053 11054
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
11055
static int ATTRIBUTE_NONNULL (5)
D
Daniel Veillard 已提交
11056 11057 11058 11059 11060
qemudDomainMigratePrepare2 (virConnectPtr dconn,
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
11061
                            unsigned long flags,
D
Daniel Veillard 已提交
11062 11063 11064 11065 11066
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
    static int port = 0;
11067 11068
    struct qemud_driver *driver = dconn->privateData;
    virDomainDefPtr def = NULL;
D
Daniel Veillard 已提交
11069 11070
    virDomainObjPtr vm = NULL;
    int this_port;
C
Chris Lalancette 已提交
11071
    char *hostname = NULL;
D
Daniel Veillard 已提交
11072 11073
    char migrateFrom [64];
    const char *p;
11074
    virDomainEventPtr event = NULL;
11075
    int ret = -1;
11076
    int internalret;
11077 11078 11079 11080 11081 11082 11083 11084
    qemuDomainObjPrivatePtr priv = NULL;
    struct timeval now;

    if (gettimeofday(&now, NULL) < 0) {
        virReportSystemError(errno, "%s",
                             _("cannot get time of day"));
        return -1;
    }
11085

C
Chris Lalancette 已提交
11086 11087 11088 11089 11090 11091 11092 11093 11094
    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);

11095
    *uri_out = NULL;
D
Daniel Veillard 已提交
11096

11097
    qemuDriverLock(driver);
C
Chris Lalancette 已提交
11098 11099 11100 11101
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
11102 11103
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
11104 11105 11106
        goto cleanup;
    }

D
Daniel Veillard 已提交
11107
    if (!dom_xml) {
11108 11109
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no domain XML passed"));
11110
        goto cleanup;
D
Daniel Veillard 已提交
11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127
    }

    /* 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 已提交
11128
        if ((hostname = virGetHostname(NULL)) == NULL)
11129
            goto cleanup;
D
Daniel Veillard 已提交
11130

C
Chris Lalancette 已提交
11131 11132 11133 11134 11135 11136
        if (STRPREFIX(hostname, "localhost")) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("hostname on destination resolved to localhost, but migration requires an FQDN"));
            goto cleanup;
        }

11137 11138 11139 11140 11141
        /* 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 已提交
11142
        /* Caller frees */
11143 11144
        internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
        if (internalret < 0) {
11145
            virReportOOMError();
11146
            goto cleanup;
D
Daniel Veillard 已提交
11147 11148 11149 11150 11151 11152
        }
    } 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.
         */
11153
        if (!STRPREFIX (uri_in, "tcp:")) {
11154 11155
            qemuReportError (VIR_ERR_INVALID_ARG,
                             "%s", _("only tcp URIs are supported for KVM/QEMU migrations"));
11156
            goto cleanup;
D
Daniel Veillard 已提交
11157 11158 11159 11160
        }

        /* Get the port number. */
        p = strrchr (uri_in, ':');
11161 11162 11163 11164 11165 11166 11167 11168
        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) {
11169
                virReportOOMError();
11170 11171 11172 11173 11174 11175 11176
                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)) {
11177 11178
                qemuReportError(VIR_ERR_INVALID_ARG,
                                "%s", _("URI ended with incorrect ':port'"));
11179 11180
                goto cleanup;
            }
D
Daniel Veillard 已提交
11181 11182 11183
        }
    }

11184
    if (*uri_out)
11185 11186
        VIR_DEBUG("Generated uri_out=%s", *uri_out);

D
Daniel Veillard 已提交
11187
    /* Parse the domain XML. */
11188
    if (!(def = virDomainDefParseString(driver->caps, dom_xml,
11189
                                        VIR_DOMAIN_XML_INACTIVE))) {
11190 11191
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to parse XML"));
11192
        goto cleanup;
D
Daniel Veillard 已提交
11193 11194
    }

11195 11196 11197
    if (!qemuDomainIsMigratable(def))
        goto cleanup;

D
Daniel Veillard 已提交
11198
    /* Target domain name, maybe renamed. */
11199 11200 11201 11202 11203 11204
    if (dname) {
        VIR_FREE(def->name);
        def->name = strdup(dname);
        if (def->name == NULL)
            goto cleanup;
    }
D
Daniel Veillard 已提交
11205

11206 11207
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
11208

11209
    if (!(vm = virDomainAssignDef(driver->caps,
D
Daniel Veillard 已提交
11210
                                  &driver->domains,
11211
                                  def, true))) {
11212
        /* virDomainAssignDef already set the error */
11213
        goto cleanup;
D
Daniel Veillard 已提交
11214
    }
11215
    def = NULL;
11216
    priv = vm->privateData;
D
Daniel Veillard 已提交
11217

11218 11219
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
11220
    priv->jobActive = QEMU_JOB_MIGRATION_OUT;
11221

D
Daniel Veillard 已提交
11222 11223 11224 11225 11226 11227 11228
    /* 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);
11229 11230
    if (qemudStartVMDaemon (dconn, driver, vm, migrateFrom, true,
                            -1, NULL) < 0) {
11231
        qemuDomainStartAudit(vm, "migrated", false);
11232 11233 11234
        /* Note that we don't set an error here because qemudStartVMDaemon
         * should have already done that.
         */
11235
        if (!vm->persistent) {
11236 11237
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
11238 11239
            vm = NULL;
        }
11240
        goto endjob;
D
Daniel Veillard 已提交
11241
    }
11242

11243
    qemuDomainStartAudit(vm, "migrated", true);
11244 11245 11246
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_MIGRATED);
11247
    ret = 0;
D
Daniel Veillard 已提交
11248

11249
endjob:
11250 11251 11252
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
11253

11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265
    /* 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);
    }

11266
cleanup:
C
Chris Lalancette 已提交
11267
    VIR_FREE(hostname);
11268
    virDomainDefFree(def);
C
Chris Lalancette 已提交
11269
    if (ret != 0)
11270
        VIR_FREE(*uri_out);
11271 11272
    if (vm)
        virDomainObjUnlock(vm);
11273 11274
    if (event)
        qemuDomainEventQueue(driver, event);
11275
    qemuDriverUnlock(driver);
11276
    return ret;
C
Chris Lalancette 已提交
11277 11278 11279

}

11280 11281 11282 11283

/* Perform migration using QEMU's native TCP migrate support,
 * not encrypted obviously
 */
11284
static int doNativeMigrate(struct qemud_driver *driver,
11285 11286
                           virDomainObjPtr vm,
                           const char *uri,
11287
                           unsigned int flags,
11288 11289 11290 11291
                           const char *dname ATTRIBUTE_UNUSED,
                           unsigned long resource)
{
    int ret = -1;
11292
    xmlURIPtr uribits = NULL;
11293
    qemuDomainObjPrivatePtr priv = vm->privateData;
11294
    unsigned int background_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
11295

11296 11297 11298 11299 11300
    /* 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) {
11301
            virReportOOMError();
11302 11303 11304 11305 11306 11307 11308 11309
            goto cleanup;
        }
        uribits = xmlParseURI(tmpuri);
        VIR_FREE(tmpuri);
    } else {
        uribits = xmlParseURI(uri);
    }
    if (!uribits) {
11310 11311
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot parse URI %s"), uri);
11312 11313 11314
        goto cleanup;
    }

11315
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
11316
    if (resource > 0 &&
11317
        qemuMonitorSetMigrationSpeed(priv->mon, resource) < 0) {
11318
        qemuDomainObjExitMonitorWithDriver(driver, vm);
11319
        goto cleanup;
11320
    }
11321

11322 11323 11324 11325 11326 11327 11328 11329
    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) {
11330
        qemuDomainObjExitMonitorWithDriver(driver, vm);
11331 11332
        goto cleanup;
    }
11333
    qemuDomainObjExitMonitorWithDriver(driver, vm);
11334

11335
    if (qemuDomainWaitForMigrationComplete(driver, vm) < 0)
11336 11337 11338 11339 11340 11341 11342 11343 11344 11345
        goto cleanup;

    ret = 0;

cleanup:
    xmlFreeURI(uribits);
    return ret;
}


11346 11347
#define TUNNEL_SEND_BUF_SIZE 65536

11348
static int doTunnelSendAll(virStreamPtr st,
11349 11350
                           int sock)
{
11351 11352 11353 11354 11355 11356 11357 11358
    char *buffer;
    int nbytes = TUNNEL_SEND_BUF_SIZE;

    if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0) {
        virReportOOMError();
        virStreamAbort(st);
        return -1;
    }
11359 11360 11361 11362 11363

    /* XXX should honour the 'resource' parameter here */
    for (;;) {
        nbytes = saferead(sock, buffer, nbytes);
        if (nbytes < 0) {
11364
            virReportSystemError(errno, "%s",
11365
                                 _("tunnelled migration failed to read from qemu"));
11366 11367
            virStreamAbort(st);
            VIR_FREE(buffer);
11368 11369 11370 11371 11372 11373 11374
            return -1;
        }
        else if (nbytes == 0)
            /* EOF; get out of here */
            break;

        if (virStreamSend(st, buffer, nbytes) < 0) {
11375 11376
            qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                            _("Failed to write migration data to remote libvirtd"));
11377
            VIR_FREE(buffer);
11378 11379 11380 11381
            return -1;
        }
    }

11382 11383
    VIR_FREE(buffer);

11384 11385 11386 11387 11388 11389 11390
    if (virStreamFinish(st) < 0)
        /* virStreamFinish set the error for us */
        return -1;

    return 0;
}

C
Chris Lalancette 已提交
11391
static int doTunnelMigrate(virDomainPtr dom,
11392
                           struct qemud_driver *driver,
11393
                           virConnectPtr dconn,
C
Chris Lalancette 已提交
11394
                           virDomainObjPtr vm,
11395
                           const char *dom_xml,
C
Chris Lalancette 已提交
11396 11397 11398 11399 11400
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
11401
    qemuDomainObjPrivatePtr priv = vm->privateData;
11402 11403
    int client_sock = -1;
    int qemu_sock = -1;
C
Chris Lalancette 已提交
11404 11405
    struct sockaddr_un sa_qemu, sa_client;
    socklen_t addrlen;
11406
    virDomainPtr ddomain = NULL;
C
Chris Lalancette 已提交
11407
    int retval = -1;
11408
    virStreamPtr st = NULL;
C
Chris Lalancette 已提交
11409 11410
    char *unixfile = NULL;
    int internalret;
11411
    unsigned long long qemuCmdFlags;
C
Chris Lalancette 已提交
11412 11413
    int status;
    unsigned long long transferred, remaining, total;
11414
    unsigned int background_flags = QEMU_MONITOR_MIGRATE_BACKGROUND;
C
Chris Lalancette 已提交
11415

11416 11417 11418 11419 11420 11421 11422 11423
    /*
     * 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 已提交
11424 11425
     */

11426

11427
    /* Stage 1. setup local support infrastructure */
C
Chris Lalancette 已提交
11428 11429

    if (virAsprintf(&unixfile, "%s/qemu.tunnelmigrate.src.%s",
11430
                    driver->libDir, vm->def->name) < 0) {
11431
        virReportOOMError();
11432
        goto cleanup;
C
Chris Lalancette 已提交
11433 11434 11435 11436
    }

    qemu_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (qemu_sock < 0) {
11437
        virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
11438
                             _("cannot open tunnelled migration socket"));
11439
        goto cleanup;
C
Chris Lalancette 已提交
11440 11441 11442 11443 11444
    }
    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) {
11445 11446 11447
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Unix socket '%s' too big for destination"),
                        unixfile);
11448
        goto cleanup;
C
Chris Lalancette 已提交
11449 11450 11451
    }
    unlink(unixfile);
    if (bind(qemu_sock, (struct sockaddr *)&sa_qemu, sizeof(sa_qemu)) < 0) {
11452
        virReportSystemError(errno,
C
Chris Lalancette 已提交
11453 11454
                             _("Cannot bind to unix socket '%s' for tunnelled migration"),
                             unixfile);
11455
        goto cleanup;
C
Chris Lalancette 已提交
11456 11457
    }
    if (listen(qemu_sock, 1) < 0) {
11458
        virReportSystemError(errno,
C
Chris Lalancette 已提交
11459 11460
                             _("Cannot listen on unix socket '%s' for tunnelled migration"),
                             unixfile);
11461
        goto cleanup;
C
Chris Lalancette 已提交
11462 11463
    }

11464 11465 11466 11467 11468 11469 11470
    if (chown(unixfile, qemu_driver->user, qemu_driver->group) < 0) {
        virReportSystemError(errno,
                             _("Cannot change unix socket '%s' owner"),
                             unixfile);
        goto cleanup;
    }

C
Chris Lalancette 已提交
11471 11472
    /* check that this qemu version supports the unix migration */
    if (qemudExtractVersionInfo(vm->def->emulator, NULL, &qemuCmdFlags) < 0) {
11473 11474 11475
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Cannot extract Qemu version from '%s'"),
                        vm->def->emulator);
11476 11477 11478 11479 11480
        goto cleanup;
    }

    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX) &&
        !(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
11481 11482
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("Source qemu is too old to support tunnelled migration"));
11483
        goto cleanup;
C
Chris Lalancette 已提交
11484
    }
11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496


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

11497
    qemuDomainObjEnterRemoteWithDriver(driver, vm);
11498 11499 11500
    internalret = dconn->driver->domainMigratePrepareTunnel(dconn, st,
                                                            flags, dname,
                                                            resource, dom_xml);
11501
    qemuDomainObjExitRemoteWithDriver(driver, vm);
11502 11503 11504 11505 11506

    if (internalret < 0)
        /* domainMigratePrepareTunnel sets the error for us */
        goto cleanup;

11507 11508 11509 11510 11511 11512 11513 11514 11515
    /* 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;
    }

11516
    /*   3. start migration on source */
11517
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
11518 11519 11520 11521 11522 11523 11524 11525
    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 已提交
11526 11527
    else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
        const char *args[] = { "nc", "-U", unixfile, NULL };
11528
        internalret = qemuMonitorMigrateToCommand(priv->mon, QEMU_MONITOR_MIGRATE_BACKGROUND, args);
11529 11530
    } else {
        internalret = -1;
C
Chris Lalancette 已提交
11531
    }
11532
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
11533
    if (internalret < 0) {
11534 11535
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("tunnelled migration monitor command failed"));
11536
        goto finish;
C
Chris Lalancette 已提交
11537 11538
    }

11539 11540 11541 11542 11543 11544
    if (!virDomainObjIsActive(vm)) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("guest unexpectedly quit"));
        goto cleanup;
    }

11545 11546 11547
    /* From this point onwards we *must* call cancel to abort the
     * migration on source if anything goes wrong */

C
Chris Lalancette 已提交
11548 11549 11550
    /* it is also possible that the migrate didn't fail initially, but
     * rather failed later on.  Check the output of "info migrate"
     */
11551
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
11552 11553
    if (qemuMonitorGetMigrationStatus(priv->mon,
                                      &status,
C
Chris Lalancette 已提交
11554 11555 11556
                                      &transferred,
                                      &remaining,
                                      &total) < 0) {
11557
        qemuDomainObjExitMonitorWithDriver(driver, vm);
11558
        goto cancel;
C
Chris Lalancette 已提交
11559
    }
11560
    qemuDomainObjExitMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
11561 11562

    if (status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
11563 11564
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s",_("migrate failed"));
11565
        goto cancel;
C
Chris Lalancette 已提交
11566 11567 11568 11569 11570 11571
    }

    addrlen = sizeof(sa_client);
    while ((client_sock = accept(qemu_sock, (struct sockaddr *)&sa_client, &addrlen)) < 0) {
        if (errno == EAGAIN || errno == EINTR)
            continue;
11572
        virReportSystemError(errno, "%s",
C
Chris Lalancette 已提交
11573
                             _("tunnelled migration failed to accept from qemu"));
11574
        goto cancel;
C
Chris Lalancette 已提交
11575 11576
    }

11577
    retval = doTunnelSendAll(st, client_sock);
11578

11579
cancel:
11580
    if (retval != 0 && virDomainObjIsActive(vm)) {
11581
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
11582
        qemuMonitorMigrateCancel(priv->mon);
11583
        qemuDomainObjExitMonitorWithDriver(driver, vm);
11584
    }
C
Chris Lalancette 已提交
11585

11586
finish:
C
Chris Lalancette 已提交
11587
    dname = dname ? dname : dom->name;
11588
    qemuDomainObjEnterRemoteWithDriver(driver, vm);
C
Chris Lalancette 已提交
11589 11590
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri, flags, retval);
11591
    qemuDomainObjExitRemoteWithDriver(driver, vm);
11592 11593

cleanup:
11594 11595
    VIR_FORCE_CLOSE(client_sock);
    VIR_FORCE_CLOSE(qemu_sock);
11596

C
Chris Lalancette 已提交
11597 11598 11599
    if (ddomain)
        virUnrefDomain(ddomain);

11600 11601 11602 11603
    if (unixfile) {
        unlink(unixfile);
        VIR_FREE(unixfile);
    }
C
Chris Lalancette 已提交
11604

11605 11606 11607
    if (st)
        /* don't call virStreamFree(), because that resets any pending errors */
        virUnrefStream(st);
11608 11609 11610 11611
    return retval;
}


11612 11613 11614 11615
/* 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,
11616
                              struct qemud_driver *driver,
11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627
                              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;
11628
    int rc;
11629

11630
    qemuDomainObjEnterRemoteWithDriver(driver, vm);
11631 11632
    /* NB we don't pass 'uri' into this, since that's the libvirtd
     * URI in this context - so we let dest pick it */
11633 11634 11635 11636 11637 11638 11639 11640 11641
    rc = dconn->driver->domainMigratePrepare2(dconn,
                                              NULL, /* cookie */
                                              0, /* cookielen */
                                              NULL, /* uri */
                                              &uri_out,
                                              flags, dname,
                                              resource, dom_xml);
    qemuDomainObjExitRemoteWithDriver(driver, vm);
    if (rc < 0)
11642 11643 11644
        /* domainMigratePrepare2 sets the error for us */
        goto cleanup;

11645 11646 11647 11648 11649 11650 11651 11652 11653
    /* 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;
    }

11654
    if (uri_out == NULL) {
11655 11656
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("domainMigratePrepare2 did not set uri"));
11657
        goto cleanup;
11658 11659
    }

11660
    if (doNativeMigrate(driver, vm, uri_out, flags, dname, resource) < 0)
11661 11662 11663 11664 11665 11666
        goto finish;

    retval = 0;

finish:
    dname = dname ? dname : dom->name;
11667
    qemuDomainObjEnterRemoteWithDriver(driver, vm);
11668 11669
    ddomain = dconn->driver->domainMigrateFinish2
        (dconn, dname, NULL, 0, uri_out, flags, retval);
11670
    qemuDomainObjExitRemoteWithDriver(driver, vm);
11671 11672 11673 11674 11675 11676 11677 11678 11679

    if (ddomain)
        virUnrefDomain(ddomain);

cleanup:
    return retval;
}


11680
static int doPeer2PeerMigrate(virDomainPtr dom,
11681
                              struct qemud_driver *driver,
11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697
                              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) {
11698 11699
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        _("Failed to connect to remote libvirt URI %s"), uri);
11700 11701 11702
        return -1;
    }
    if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
11703
                                  VIR_DRV_FEATURE_MIGRATION_P2P)) {
11704 11705
        qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
                        _("Destination libvirt does not support peer-to-peer migration protocol"));
11706 11707 11708
        goto cleanup;
    }

11709 11710 11711
    dom_xml = qemudVMDumpXML(driver, vm,
                             VIR_DOMAIN_XML_SECURE |
                             VIR_DOMAIN_XML_UPDATE_CPU);
11712
    if (!dom_xml) {
11713 11714
        qemuReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to get domain xml"));
11715 11716 11717
        goto cleanup;
    }

11718
    if (flags & VIR_MIGRATE_TUNNELLED)
11719
        ret = doTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
11720
    else
11721
        ret = doNonTunnelMigrate(dom, driver, dconn, vm, dom_xml, uri, flags, dname, resource);
11722 11723 11724

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

11728
    return ret;
D
Daniel Veillard 已提交
11729 11730
}

11731

D
Daniel Veillard 已提交
11732 11733 11734 11735 11736 11737
/* 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,
11738
                           unsigned long flags,
11739
                           const char *dname,
D
Daniel Veillard 已提交
11740 11741
                           unsigned long resource)
{
11742 11743
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
11744
    virDomainEventPtr event = NULL;
11745
    int ret = -1;
11746
    int resume = 0;
11747
    qemuDomainObjPrivatePtr priv;
D
Daniel Veillard 已提交
11748

C
Chris Lalancette 已提交
11749 11750 11751 11752 11753 11754 11755 11756 11757
    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);

11758
    qemuDriverLock(driver);
11759
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
11760
    if (!vm) {
11761 11762
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
11763 11764
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
11765
        goto cleanup;
D
Daniel Veillard 已提交
11766
    }
11767
    priv = vm->privateData;
D
Daniel Veillard 已提交
11768

11769 11770
    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
11771
    priv->jobActive = QEMU_JOB_MIGRATION_OUT;
11772

D
Daniel P. Berrange 已提交
11773
    if (!virDomainObjIsActive(vm)) {
11774 11775
        qemuReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("domain is not running"));
11776
        goto endjob;
D
Daniel Veillard 已提交
11777 11778
    }

11779 11780 11781
    memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
    priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;

11782
    resume = vm->state == VIR_DOMAIN_RUNNING;
11783
    if (!(flags & VIR_MIGRATE_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
11784
        if (qemuDomainMigrateOffline(driver, vm) < 0)
11785
            goto endjob;
11786 11787
    }

11788
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
11789
        if (doPeer2PeerMigrate(dom, driver, vm, uri, flags, dname, resource) < 0)
11790
            /* doPeer2PeerMigrate already set the error, so just get out */
11791
            goto endjob;
11792
    } else {
11793
        if (doNativeMigrate(driver, vm, uri, flags, dname, resource) < 0)
11794
            goto endjob;
11795 11796
    }

D
Daniel Veillard 已提交
11797
    /* Clean up the source domain. */
11798
    qemudShutdownVMDaemon(driver, vm, 1);
11799
    qemuDomainStopAudit(vm, "migrated");
11800
    resume = 0;
11801 11802 11803 11804

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
C
Chris Lalancette 已提交
11805
    if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
11806
        virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm);
11807 11808
        if (qemuDomainObjEndJob(vm) > 0)
            virDomainRemoveInactive(&driver->domains, vm);
11809 11810
        vm = NULL;
    }
11811
    ret = 0;
D
Daniel Veillard 已提交
11812

11813
endjob:
11814
    if (resume && vm->state == VIR_DOMAIN_PAUSED) {
11815
        /* we got here through some sort of failure; start the domain again */
11816
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
11817
        if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
11818 11819 11820 11821
            /* 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
             */
11822
            VIR_ERROR(_("Failed to resume guest %s after failure"),
11823
                      vm->def->name);
11824
        }
11825
        qemuDomainObjExitMonitorWithDriver(driver, vm);
11826

11827
        vm->state = VIR_DOMAIN_RUNNING;
11828 11829 11830 11831
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
    }
11832 11833 11834
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
11835

11836
cleanup:
11837 11838
    if (vm)
        virDomainObjUnlock(vm);
11839 11840
    if (event)
        qemuDomainEventQueue(driver, event);
11841
    qemuDriverUnlock(driver);
11842
    return ret;
D
Daniel Veillard 已提交
11843 11844 11845 11846 11847 11848 11849 11850 11851
}

/* 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 已提交
11852
                           unsigned long flags,
D
Daniel Veillard 已提交
11853 11854
                           int retcode)
{
11855 11856 11857
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
11858
    virDomainEventPtr event = NULL;
11859
    virErrorPtr orig_err;
C
Chris Lalancette 已提交
11860
    int newVM = 1;
11861
    qemuDomainObjPrivatePtr priv = NULL;
D
Daniel Veillard 已提交
11862

C
Chris Lalancette 已提交
11863 11864 11865 11866 11867 11868 11869 11870 11871
    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);

11872 11873 11874
    /* Migration failed. Save the current error so nothing squashes it */
    orig_err = virSaveLastError();

11875
    qemuDriverLock(driver);
11876
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
11877
    if (!vm) {
11878 11879
        qemuReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching name '%s'"), dname);
11880
        goto cleanup;
D
Daniel Veillard 已提交
11881 11882
    }

11883 11884 11885 11886 11887 11888 11889 11890 11891
    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));

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

D
Daniel Veillard 已提交
11895 11896 11897 11898
    /* Did the migration go as planned?  If yes, return the domain
     * object, but if no, clean up the empty qemu process.
     */
    if (retcode == 0) {
11899 11900 11901 11902 11903 11904
        if (!virDomainObjIsActive(vm)) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("guest unexpectedly quit"));
            goto cleanup;
        }

C
Chris Lalancette 已提交
11905 11906 11907 11908 11909
        if (flags & VIR_MIGRATE_PERSIST_DEST) {
            if (vm->persistent)
                newVM = 0;
            vm->persistent = 1;

11910
            if (virDomainSaveConfig(driver->configDir, vm->def) < 0) {
C
Chris Lalancette 已提交
11911 11912 11913 11914 11915 11916 11917 11918 11919 11920
                /* 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;
11921
                goto endjob;
C
Chris Lalancette 已提交
11922 11923 11924 11925 11926 11927 11928 11929 11930
            }

            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_DEFINED,
                                             newVM ?
                                             VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                             VIR_DOMAIN_EVENT_DEFINED_UPDATED);
            if (event)
                qemuDomainEventQueue(driver, event);
11931
            event = NULL;
C
Chris Lalancette 已提交
11932 11933

        }
D
Daniel Veillard 已提交
11934
        dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
11935

11936 11937 11938 11939 11940 11941 11942 11943
        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)
11944 11945
                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                    "%s", _("resume operation failed"));
11946 11947 11948
                qemuDomainObjExitMonitorWithDriver(driver, vm);
                goto endjob;
            }
11949
            qemuDomainObjExitMonitorWithDriver(driver, vm);
11950 11951

            vm->state = VIR_DOMAIN_RUNNING;
11952 11953
        }

11954 11955 11956
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
11957 11958 11959 11960 11961 11962
        if (vm->state == VIR_DOMAIN_PAUSED) {
            qemuDomainEventQueue(driver, event);
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
        }
11963 11964 11965 11966
        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 已提交
11967
    } else {
11968
        qemudShutdownVMDaemon(driver, vm, 1);
11969
        qemuDomainStopAudit(vm, "failed");
11970 11971 11972
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FAILED);
11973
        if (!vm->persistent) {
11974 11975
            if (qemuDomainObjEndJob(vm) > 0)
                virDomainRemoveInactive(&driver->domains, vm);
11976 11977
            vm = NULL;
        }
D
Daniel Veillard 已提交
11978
    }
11979

11980
endjob:
11981 11982 11983
    if (vm &&
        qemuDomainObjEndJob(vm) == 0)
        vm = NULL;
11984

11985
cleanup:
11986 11987 11988 11989
    if (orig_err) {
        virSetError(orig_err);
        virFreeError(orig_err);
    }
11990 11991
    if (vm)
        virDomainObjUnlock(vm);
11992 11993
    if (event)
        qemuDomainEventQueue(driver, event);
11994
    qemuDriverUnlock(driver);
11995
    return dom;
D
Daniel Veillard 已提交
11996 11997
}

11998 11999 12000 12001 12002 12003 12004 12005 12006 12007 12008 12009 12010 12011 12012 12013
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;

12014
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE);
12015 12016 12017 12018 12019 12020 12021 12022 12023 12024 12025 12026 12027 12028 12029 12030 12031
    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) {
12032 12033
        qemuReportError(VIR_ERR_INVALID_ARG,
                        _("device %s is not a PCI device"), dev->name);
12034 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044 12045 12046
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
qemudNodeDeviceDettach (virNodeDevicePtr dev)
{
12047
    struct qemud_driver *driver = dev->conn->privateData;
12048 12049 12050 12051 12052 12053 12054
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

12055
    pci = pciGetDevice(domain, bus, slot, function);
12056 12057 12058
    if (!pci)
        return -1;

12059 12060
    qemuDriverLock(driver);
    if (pciDettachDevice(pci, driver->activePciHostdevs) < 0)
12061 12062 12063 12064
        goto out;

    ret = 0;
out:
12065
    qemuDriverUnlock(driver);
12066
    pciFreeDevice(pci);
12067 12068 12069 12070 12071 12072
    return ret;
}

static int
qemudNodeDeviceReAttach (virNodeDevicePtr dev)
{
12073
    struct qemud_driver *driver = dev->conn->privateData;
12074 12075 12076 12077 12078 12079 12080
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

12081
    pci = pciGetDevice(domain, bus, slot, function);
12082 12083 12084
    if (!pci)
        return -1;

12085 12086
    qemuDriverLock(driver);
    if (pciReAttachDevice(pci, driver->activePciHostdevs) < 0)
12087 12088 12089 12090
        goto out;

    ret = 0;
out:
12091
    qemuDriverUnlock(driver);
12092
    pciFreeDevice(pci);
12093 12094 12095 12096 12097 12098
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
12099
    struct qemud_driver *driver = dev->conn->privateData;
12100 12101 12102 12103 12104 12105 12106
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

12107
    pci = pciGetDevice(domain, bus, slot, function);
12108 12109 12110
    if (!pci)
        return -1;

12111 12112
    qemuDriverLock(driver);

12113
    if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
12114 12115 12116 12117
        goto out;

    ret = 0;
out:
12118
    qemuDriverUnlock(driver);
12119
    pciFreeDevice(pci);
12120 12121 12122
    return ret;
}

12123 12124 12125 12126 12127 12128 12129 12130 12131 12132 12133
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) {
12134 12135
        qemuReportError(VIR_ERR_NO_SUPPORT,
                        "%s", _("cannot get host CPU capabilities"));
12136 12137
    }
    else
12138
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
12139 12140 12141 12142 12143 12144

    qemuDriverUnlock(driver);

    return ret;
}

12145

12146 12147 12148 12149 12150 12151 12152 12153 12154 12155 12156 12157 12158
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;
}

12159 12160 12161 12162 12163 12164 12165 12166 12167 12168 12169 12170 12171 12172 12173 12174 12175 12176 12177 12178 12179 12180 12181

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) {
12182 12183
            struct timeval now;

12184
            memcpy(info, &priv->jobInfo, sizeof(*info));
12185 12186 12187 12188 12189 12190 12191 12192 12193 12194 12195 12196 12197 12198

            /* 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;
12199 12200 12201 12202 12203 12204 12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217
        } 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;
}


12218 12219 12220 12221 12222 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239
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);
12240
            priv->jobSignals |= QEMU_JOB_SIGNAL_CANCEL;
12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260
        } 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;
}


12261 12262 12263 12264 12265 12266 12267 12268 12269 12270
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;

12271
    virCheckFlags(0, -1);
12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291

    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;

12292
    if (priv->jobActive != QEMU_JOB_MIGRATION_OUT) {
12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309
        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 已提交
12310 12311 12312 12313 12314 12315 12316 12317 12318 12319 12320 12321 12322 12323 12324 12325 12326 12327 12328 12329 12330 12331 12332 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349 12350 12351 12352 12353 12354 12355 12356 12357 12358 12359 12360 12361 12362 12363 12364 12365 12366 12367 12368 12369 12370 12371 12372 12373 12374 12375
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);
12376
    VIR_FORCE_CLOSE(fd);
C
Chris Lalancette 已提交
12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403 12404 12405 12406 12407 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417
    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,
12418 12419
                            _("Disk '%s' does not support snapshotting"),
                            vm->def->disks[i]->src);
C
Chris Lalancette 已提交
12420 12421 12422 12423 12424 12425 12426 12427 12428
            return 0;
        }
    }

    return 1;
}

static virDomainSnapshotPtr qemuDomainSnapshotCreateXML(virDomainPtr domain,
                                                        const char *xmlDesc,
12429
                                                        unsigned int flags)
C
Chris Lalancette 已提交
12430 12431 12432 12433 12434 12435 12436 12437 12438 12439
{
    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;

12440 12441
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
12442 12443 12444 12445 12446 12447 12448 12449 12450 12451 12452 12453 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 12466 12467 12468 12469 12470 12471 12472 12473 12474 12475 12476 12477 12478 12479 12480 12481 12482 12483 12484 12485 12486 12487 12488 12489 12490 12491 12492 12493 12494 12495 12496 12497 12498 12499 12500 12501 12502
    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 {
12503 12504 12505 12506 12507
        qemuDomainObjPrivatePtr priv;
        int ret;

        if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
            goto cleanup;
C
Chris Lalancette 已提交
12508 12509
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
12510
        ret = qemuMonitorCreateSnapshot(priv->mon, def->name);
C
Chris Lalancette 已提交
12511
        qemuDomainObjExitMonitorWithDriver(driver, vm);
12512
        if (qemuDomainObjEndJob(vm) == 0) {
12513
            vm = NULL;
12514 12515
            goto cleanup;
        }
12516 12517
        if (ret < 0)
            goto cleanup;
C
Chris Lalancette 已提交
12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 12538 12539 12540 12541 12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553
    }

    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,
12554
                                       unsigned int flags)
C
Chris Lalancette 已提交
12555 12556 12557 12558 12559
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

12560 12561
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
12562 12563 12564 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 12575 12576 12577 12578 12579 12580 12581
    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,
12582
                                 unsigned int flags)
C
Chris Lalancette 已提交
12583 12584 12585 12586 12587
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int n = -1;

12588 12589
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
12590 12591 12592 12593 12594 12595 12596 12597 12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610
    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,
12611
                                                           unsigned int flags)
C
Chris Lalancette 已提交
12612 12613 12614 12615 12616 12617
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

12618 12619
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
12620 12621 12622 12623 12624 12625 12626 12627 12628 12629 12630 12631 12632 12633 12634 12635 12636 12637 12638 12639 12640 12641 12642 12643 12644 12645 12646
    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,
12647
                                        unsigned int flags)
C
Chris Lalancette 已提交
12648 12649 12650 12651 12652
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

12653 12654
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 12670 12671 12672 12673 12674
    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,
12675
                                                      unsigned int flags)
C
Chris Lalancette 已提交
12676 12677 12678 12679 12680
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

12681 12682
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
12683 12684 12685 12686 12687 12688 12689 12690 12691 12692 12693 12694 12695 12696 12697 12698 12699 12700 12701 12702 12703 12704 12705 12706 12707 12708
    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,
12709
                                       unsigned int flags)
C
Chris Lalancette 已提交
12710 12711 12712 12713 12714 12715 12716
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

12717 12718
    virCheckFlags(0, NULL);

C
Chris Lalancette 已提交
12719 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 12739 12740 12741 12742 12743 12744 12745
    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,
12746
                                      unsigned int flags)
C
Chris Lalancette 已提交
12747 12748 12749 12750 12751 12752 12753 12754 12755 12756
{
    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;

12757 12758
    virCheckFlags(0, -1);

C
Chris Lalancette 已提交
12759 12760 12761 12762 12763 12764 12765 12766 12767 12768 12769 12770 12771 12772 12773 12774 12775 12776 12777 12778 12779 12780 12781 12782 12783 12784 12785 12786 12787 12788 12789
    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)
12790
                goto endjob;
C
Chris Lalancette 已提交
12791 12792 12793
        }
        else {
            if (qemuDomainSnapshotSetActive(vm, driver->snapshotDir) < 0)
12794
                goto endjob;
C
Chris Lalancette 已提交
12795 12796

            rc = qemudStartVMDaemon(snapshot->domain->conn, driver, vm, NULL,
12797
                                    false, -1, NULL);
12798
            qemuDomainStartAudit(vm, "from-snapshot", rc >= 0);
C
Chris Lalancette 已提交
12799
            if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
12800
                goto endjob;
C
Chris Lalancette 已提交
12801
            if (rc < 0)
12802
                goto endjob;
C
Chris Lalancette 已提交
12803 12804 12805 12806 12807 12808
        }

        if (snap->def->state == VIR_DOMAIN_PAUSED) {
            /* qemu unconditionally starts the domain running again after
             * loadvm, so let's pause it to keep consistency
             */
12809
            int state = vm->state;
C
Chris Lalancette 已提交
12810
            priv = vm->privateData;
12811
            vm->state = VIR_DOMAIN_PAUSED;
C
Chris Lalancette 已提交
12812 12813 12814
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            rc = qemuMonitorStopCPUs(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
12815 12816
            if (rc < 0) {
                vm->state = state;
12817
                goto endjob;
12818
            }
C
Chris Lalancette 已提交
12819 12820 12821 12822 12823 12824 12825 12826 12827 12828 12829 12830 12831 12832 12833 12834 12835 12836
        }

        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)) {
12837
            qemudShutdownVMDaemon(driver, vm, 0);
12838
            qemuDomainStopAudit(vm, "from-snapshot");
C
Chris Lalancette 已提交
12839 12840 12841
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
                                             VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
12842 12843 12844 12845
            if (!vm->persistent) {
                if (qemuDomainObjEndJob(vm) > 0)
                    virDomainRemoveInactive(&driver->domains, vm);
                vm = NULL;
12846
                goto cleanup;
12847
            }
C
Chris Lalancette 已提交
12848 12849 12850
        }

        if (qemuDomainSnapshotSetActive(vm, driver->snapshotDir) < 0)
12851
            goto endjob;
C
Chris Lalancette 已提交
12852 12853 12854 12855 12856 12857
    }

    vm->state = snap->def->state;

    ret = 0;

12858
endjob:
C
Chris Lalancette 已提交
12859 12860 12861
    if (vm && qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

12862
cleanup:
C
Chris Lalancette 已提交
12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906 12907 12908 12909 12910 12911 12912 12913 12914 12915 12916 12917 12918 12919 12920 12921 12922 12923 12924 12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957 12958 12959 12960 12961 12962 12963 12964 12965 12966 12967 12968 12969 12970 12971 12972 12973 12974 12975 12976 12977 12978 12979 12980 12981 12982 12983 12984 12985 12986 12987 12988 12989 12990 12991 12992 12993 12994 12995 12996
    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;

12997 12998
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);

C
Chris Lalancette 已提交
12999 13000 13001 13002 13003 13004 13005 13006 13007 13008 13009 13010 13011 13012 13013 13014 13015
    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;
    }

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

C
Chris Lalancette 已提交
13019 13020 13021 13022 13023 13024 13025 13026
    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)
13027
            goto endjob;
C
Chris Lalancette 已提交
13028 13029 13030 13031
    }

    ret = qemuDomainSnapshotDiscard(driver, vm, snap);

13032 13033 13034 13035
endjob:
    if (qemuDomainObjEndJob(vm) == 0)
        vm = NULL;

C
Chris Lalancette 已提交
13036 13037 13038 13039 13040 13041
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
13042

13043 13044 13045 13046 13047 13048 13049 13050 13051 13052 13053 13054 13055 13056 13057 13058 13059 13060 13061 13062 13063 13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093
static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
                                    char **result, unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

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

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

    priv = vm->privateData;

    if (!priv->monitor_warned) {
        VIR_INFO("Qemu monitor command '%s' executed; libvirt results may be unpredictable!",
                 cmd);
        priv->monitor_warned = 1;
    }

    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
        goto cleanup;
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    if (qemuDomainObjEndJob(vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

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

13094 13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 13109 13110 13111 13112 13113 13114 13115 13116 13117 13118 13119 13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 13136 13137 13138 13139 13140 13141 13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 13152 13153 13154 13155 13156 13157 13158 13159 13160 13161 13162 13163 13164 13165 13166 13167 13168 13169

static int
qemuDomainOpenConsole(virDomainPtr dom,
                      const char *devname,
                      virStreamPtr st,
                      unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    int i;
    virDomainChrDefPtr chr = NULL;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        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;
    }

    if (devname) {
        if (vm->def->console &&
            STREQ(devname, vm->def->console->info.alias))
            chr = vm->def->console;
        for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
            if (STREQ(devname, vm->def->serials[i]->info.alias))
                chr = vm->def->serials[i];
        }
        for (i = 0 ; !chr && i < vm->def->nparallels ; i++) {
            if (STREQ(devname, vm->def->parallels[i]->info.alias))
                chr = vm->def->parallels[i];
        }
    } else {
        if (vm->def->console)
            chr = vm->def->console;
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot find character device %s"),
                        NULLSTR(devname));
        goto cleanup;
    }

    if (chr->type != VIR_DOMAIN_CHR_TYPE_PTY) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("character device %s is not using a PTY"),
                        NULLSTR(devname));
        goto cleanup;
    }

    if (virFDStreamOpenFile(st, chr->data.file.path, O_RDWR) < 0)
        goto cleanup;

    ret = 0;
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}


13170 13171 13172 13173 13174
static virDriver qemuDriver = {
    VIR_DRV_QEMU,
    "QEMU",
    qemudOpen, /* open */
    qemudClose, /* close */
D
Daniel Veillard 已提交
13175
    qemudSupportsFeature, /* supports_feature */
13176 13177
    qemudGetType, /* type */
    qemudGetVersion, /* version */
13178
    NULL, /* libvirtVersion (impl. in libvirt.c) */
13179
    virGetHostname, /* getHostname */
13180
    qemudGetMaxVCPUs, /* getMaxVcpus */
13181
    nodeGetInfo, /* nodeGetInfo */
13182 13183 13184
    qemudGetCapabilities, /* getCapabilities */
    qemudListDomains, /* listDomains */
    qemudNumDomains, /* numOfDomains */
13185
    qemudDomainCreate, /* domainCreateXML */
13186 13187 13188 13189 13190
    qemudDomainLookupByID, /* domainLookupByID */
    qemudDomainLookupByUUID, /* domainLookupByUUID */
    qemudDomainLookupByName, /* domainLookupByName */
    qemudDomainSuspend, /* domainSuspend */
    qemudDomainResume, /* domainResume */
13191
    qemudDomainShutdown, /* domainShutdown */
13192 13193 13194
    NULL, /* domainReboot */
    qemudDomainDestroy, /* domainDestroy */
    qemudDomainGetOSType, /* domainGetOSType */
13195
    qemudDomainGetMaxMemory, /* domainGetMaxMemory */
13196
    NULL, /* domainSetMaxMemory */
13197
    qemudDomainSetMemory, /* domainSetMemory */
13198 13199 13200
    qemudDomainGetInfo, /* domainGetInfo */
    qemudDomainSave, /* domainSave */
    qemudDomainRestore, /* domainRestore */
P
Paolo Bonzini 已提交
13201
    qemudDomainCoreDump, /* domainCoreDump */
13202
    qemudDomainSetVcpus, /* domainSetVcpus */
13203 13204
    qemudDomainSetVcpusFlags, /* domainSetVcpusFlags */
    qemudDomainGetVcpusFlags, /* domainGetVcpusFlags */
13205 13206
    qemudDomainPinVcpu, /* domainPinVcpu */
    qemudDomainGetVcpus, /* domainGetVcpus */
13207
    qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */
13208 13209
    qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
    qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
13210
    qemudDomainDumpXML, /* domainDumpXML */
13211
    qemuDomainXMLFromNative, /* domainXmlFromNative */
13212
    qemuDomainXMLToNative, /* domainXMLToNative */
13213 13214
    qemudListDefinedDomains, /* listDefinedDomains */
    qemudNumDefinedDomains, /* numOfDefinedDomains */
13215
    qemudDomainStart, /* domainCreate */
13216
    qemudDomainStartWithFlags, /* domainCreateWithFlags */
13217 13218
    qemudDomainDefine, /* domainDefineXML */
    qemudDomainUndefine, /* domainUndefine */
13219
    qemudDomainAttachDevice, /* domainAttachDevice */
13220
    qemudDomainAttachDeviceFlags, /* domainAttachDeviceFlags */
13221
    qemudDomainDetachDevice, /* domainDetachDevice */
13222
    qemudDomainDetachDeviceFlags, /* domainDetachDeviceFlags */
13223
    qemuDomainUpdateDeviceFlags, /* domainUpdateDeviceFlags */
13224 13225
    qemudDomainGetAutostart, /* domainGetAutostart */
    qemudDomainSetAutostart, /* domainSetAutostart */
13226 13227 13228
    qemuGetSchedulerType, /* domainGetSchedulerType */
    qemuGetSchedulerParameters, /* domainGetSchedulerParameters */
    qemuSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
13229 13230
    NULL, /* domainMigratePrepare (v1) */
    qemudDomainMigratePerform, /* domainMigratePerform */
13231
    NULL, /* domainMigrateFinish */
13232
    qemudDomainBlockStats, /* domainBlockStats */
13233
    qemudDomainInterfaceStats, /* domainInterfaceStats */
13234
    qemudDomainMemoryStats, /* domainMemoryStats */
13235
    qemudDomainBlockPeek, /* domainBlockPeek */
R
Richard W.M. Jones 已提交
13236
    qemudDomainMemoryPeek, /* domainMemoryPeek */
13237
    qemuDomainGetBlockInfo, /* domainGetBlockInfo */
13238 13239
    nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
    nodeGetFreeMemory,  /* getFreeMemory */
13240 13241
    qemuDomainEventRegister, /* domainEventRegister */
    qemuDomainEventDeregister, /* domainEventDeregister */
D
Daniel Veillard 已提交
13242 13243
    qemudDomainMigratePrepare2, /* domainMigratePrepare2 */
    qemudDomainMigrateFinish2, /* domainMigrateFinish2 */
13244 13245 13246
    qemudNodeDeviceDettach, /* nodeDeviceDettach */
    qemudNodeDeviceReAttach, /* nodeDeviceReAttach */
    qemudNodeDeviceReset, /* nodeDeviceReset */
C
Chris Lalancette 已提交
13247
    qemudDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
13248 13249 13250 13251
    qemuIsEncrypted, /* isEncrypted */
    qemuIsSecure, /* isSecure */
    qemuDomainIsActive, /* domainIsActive */
    qemuDomainIsPersistent, /* domainIsPersistent */
13252
    qemuCPUCompare, /* cpuCompare */
13253
    qemuCPUBaseline, /* cpuBaseline */
13254
    qemuDomainGetJobInfo, /* domainGetJobInfo */
13255
    qemuDomainAbortJob, /* domainAbortJob */
13256
    qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */
13257 13258
    qemuDomainEventRegisterAny, /* domainEventRegisterAny */
    qemuDomainEventDeregisterAny, /* domainEventDeregisterAny */
13259 13260 13261
    qemuDomainManagedSave, /* domainManagedSave */
    qemuDomainHasManagedSaveImage, /* domainHasManagedSaveImage */
    qemuDomainManagedSaveRemove, /* domainManagedSaveRemove */
C
Chris Lalancette 已提交
13262 13263 13264 13265 13266 13267 13268 13269 13270
    qemuDomainSnapshotCreateXML, /* domainSnapshotCreateXML */
    qemuDomainSnapshotDumpXML, /* domainSnapshotDumpXML */
    qemuDomainSnapshotNum, /* domainSnapshotNum */
    qemuDomainSnapshotListNames, /* domainSnapshotListNames */
    qemuDomainSnapshotLookupByName, /* domainSnapshotLookupByName */
    qemuDomainHasCurrentSnapshot, /* domainHasCurrentSnapshot */
    qemuDomainSnapshotCurrent, /* domainSnapshotCurrent */
    qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */
    qemuDomainSnapshotDelete, /* domainSnapshotDelete */
13271
    qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
13272
    qemuDomainSetMemoryParameters, /* domainSetMemoryParameters */
13273
    qemuDomainGetMemoryParameters, /* domainGetMemoryParameters */
13274
    qemuDomainOpenConsole, /* domainOpenConsole */
13275 13276 13277
};


13278
static virStateDriver qemuStateDriver = {
13279
    .name = "QEMU",
13280 13281 13282 13283
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
13284
};
13285

S
Stefan Berger 已提交
13286
static int
13287
qemudVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
S
Stefan Berger 已提交
13288 13289 13290
                     virHashIterator iter, void *data)
{
    virHashForEach(qemu_driver->domains.objs, iter, data);
13291

S
Stefan Berger 已提交
13292 13293 13294
    return 0;
}

13295 13296 13297 13298 13299 13300 13301 13302 13303 13304 13305 13306 13307 13308 13309 13310 13311 13312 13313 13314 13315 13316
static int
qemudVMFiltersInstantiate(virConnectPtr conn,
                          virDomainDefPtr def)
{
    int err = 0;
    int i;

    if (!conn)
        return 1;

    for (i = 0 ; i < def->nnets ; i++) {
        virDomainNetDefPtr net = def->nets[i];
        if ((net->filter) && (net->ifname)) {
           if (virDomainConfNWFilterInstantiate(conn, net)) {
                err = 1;
                break;
            }
        }
    }

    return err;
}
S
Stefan Berger 已提交
13317

13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330

static void
qemudVMDriverLock(void) {
    qemuDriverLock(qemu_driver);
};


static void
qemudVMDriverUnlock(void) {
    qemuDriverUnlock(qemu_driver);
};


S
Stefan Berger 已提交
13331 13332 13333
static virNWFilterCallbackDriver qemuCallbackDriver = {
    .name = "QEMU",
    .vmFilterRebuild = qemudVMFilterRebuild,
13334 13335
    .vmDriverLock = qemudVMDriverLock,
    .vmDriverUnlock = qemudVMDriverUnlock,
S
Stefan Berger 已提交
13336 13337
};

13338
int qemuRegister(void) {
13339 13340
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
S
Stefan Berger 已提交
13341
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
13342 13343
    return 0;
}