qemu_hotplug.c 210.6 KB
Newer Older
1
/*
2
 * qemu_hotplug.c: QEMU device hotplug management
3
 *
4
 * Copyright (C) 2006-2016 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25
 */


#include <config.h>

#include "qemu_hotplug.h"
26
#define LIBVIRT_QEMU_HOTPLUGPRIV_H_ALLOW
27
#include "qemu_hotplugpriv.h"
28
#include "qemu_alias.h"
29 30
#include "qemu_capabilities.h"
#include "qemu_domain.h"
31
#include "qemu_domain_address.h"
32 33
#include "qemu_command.h"
#include "qemu_hostdev.h"
34
#include "qemu_interface.h"
35
#include "qemu_process.h"
36
#include "qemu_security.h"
37
#include "qemu_block.h"
38
#include "domain_audit.h"
39
#include "netdev_bandwidth_conf.h"
40
#include "domain_nwfilter.h"
41
#include "virlog.h"
42
#include "datatypes.h"
43
#include "virerror.h"
44
#include "viralloc.h"
45
#include "virpci.h"
E
Eric Blake 已提交
46
#include "virfile.h"
47
#include "virprocess.h"
48
#include "qemu_cgroup.h"
49
#include "locking/domain_lock.h"
50 51
#include "virnetdev.h"
#include "virnetdevbridge.h"
A
Ansis Atteka 已提交
52
#include "virnetdevtap.h"
53
#include "virnetdevopenvswitch.h"
54
#include "virnetdevmidonet.h"
55
#include "device_conf.h"
56
#include "virstoragefile.h"
57
#include "virstring.h"
58
#include "virtime.h"
59 60

#define VIR_FROM_THIS VIR_FROM_QEMU
61 62 63

VIR_LOG_INIT("qemu.qemu_hotplug");

64
#define CHANGE_MEDIA_TIMEOUT 5000
65

66 67 68 69
/* Wait up to 5 seconds for device removal to finish. */
unsigned long long qemuDomainRemoveDeviceWaitTime = 1000ull * 5;


70 71 72
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm);

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
/**
 * qemuDomainDeleteDevice:
 * @vm: domain object
 * @alias: device to remove
 *
 * This is a wrapper over qemuMonitorDelDevice() plus enter/exit
 * monitor calls.  This function MUST be used instead of plain
 * qemuMonitorDelDevice() in all places where @alias represents a
 * device from domain XML, i.e. caller marks the device for
 * removal and then calls qemuDomainWaitForDeviceRemoval()
 * followed by qemuDomainRemove*Device().
 *
 * For collateral devices (e.g. extension devices like zPCI) it
 * is safe to use plain qemuMonitorDelDevice().
 *
 * Upon entry, @vm must be locked.
 *
 * Returns: 0 on success,
 *         -1 otherwise.
 */
static int
qemuDomainDeleteDevice(virDomainObjPtr vm,
                       const char *alias)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virQEMUDriverPtr driver = priv->driver;
    int rc;

    qemuDomainObjEnterMonitor(driver, vm);

    rc = qemuMonitorDelDevice(priv->mon, alias);

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        /* Domain is no longer running. No cleanup needed. */
        return -1;
    }

    if (rc < 0) {
        /* Deleting device failed. Let's check if DEVICE_DELETED
         * even arrived. If it did, we need to claim success to
         * make the caller remove device from domain XML. */

        if (priv->unplug.eventSeen) {
            /* The event arrived. Return success. */
            VIR_DEBUG("Detaching of device %s failed, but event arrived", alias);
            qemuDomainResetDeviceRemoval(vm);
            rc = 0;
        } else if (rc == -2) {
            /* The device does not exist in qemu, but it still
             * exists in libvirt. Claim success to make caller
             * qemuDomainWaitForDeviceRemoval(). Otherwise if
             * domain XML is queried right after detach API the
             * device would still be there.  */
            VIR_DEBUG("Detaching of device %s failed and no event arrived", alias);
            rc = 0;
        }
    }
130 131 132 133 134

    return rc;
}


135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
static int
qemuDomainAttachZPCIDevice(qemuMonitorPtr mon,
                           virDomainDeviceInfoPtr info)
{
    char *devstr_zpci = NULL;
    int ret = -1;

    if (!(devstr_zpci = qemuBuildZPCIDevStr(info)))
        goto cleanup;

    if (qemuMonitorAddDevice(mon, devstr_zpci) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    VIR_FREE(devstr_zpci);
    return ret;
}


static int
qemuDomainDetachZPCIDevice(qemuMonitorPtr mon,
                           virDomainDeviceInfoPtr info)
{
    char *zpciAlias = NULL;
    int ret = -1;

    if (virAsprintf(&zpciAlias, "zpci%d", info->addr.pci.zpci.uid) < 0)
        goto cleanup;

    if (qemuMonitorDelDevice(mon, zpciAlias) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    VIR_FREE(zpciAlias);
    return ret;
}


static int
qemuDomainAttachExtensionDevice(qemuMonitorPtr mon,
                                virDomainDeviceInfoPtr info)
{
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
        info->addr.pci.extFlags == VIR_PCI_ADDRESS_EXTENSION_NONE) {
        return 0;
    }

    if (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI)
        return qemuDomainAttachZPCIDevice(mon, info);

    return 0;
}


static int
qemuDomainDetachExtensionDevice(qemuMonitorPtr mon,
                                virDomainDeviceInfoPtr info)
{
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
        info->addr.pci.extFlags == VIR_PCI_ADDRESS_EXTENSION_NONE) {
        return 0;
    }

    if (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI)
        return qemuDomainDetachZPCIDevice(mon, info);

    return 0;
}


209
static int
210 211
qemuHotplugWaitForTrayEject(virDomainObjPtr vm,
                            virDomainDiskDefPtr disk)
212 213 214 215 216 217 218 219 220 221 222 223
{
    unsigned long long now;
    int rc;

    if (virTimeMillisNow(&now) < 0)
        return -1;

    while (disk->tray_status != VIR_DOMAIN_DISK_TRAY_OPEN) {
        if ((rc = virDomainObjWaitUntil(vm, now + CHANGE_MEDIA_TIMEOUT)) < 0)
            return -1;

        if (rc > 0) {
224 225
            /* the caller called qemuMonitorEjectMedia which usually reports an
             * error. Report the failure in an off-chance that it didn't. */
226
            if (virGetLastErrorCode() == VIR_ERR_OK) {
227 228 229
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("timed out waiting to open tray of '%s'"),
                               disk->dst);
230
            }
231 232 233 234 235 236 237 238
            return -1;
        }
    }

    return 0;
}


239
/**
240
 * qemuDomainChangeMediaLegacy:
241 242 243 244 245 246 247 248 249 250 251 252 253
 * @driver: qemu driver structure
 * @vm: domain definition
 * @disk: disk definition to change the source of
 * @newsrc: new disk source to change to
 * @force: force the change of media
 *
 * Change the media in an ejectable device to the one described by
 * @newsrc. This function also removes the old source from the
 * shared device table if appropriate. Note that newsrc is consumed
 * on success and the old source is freed on success.
 *
 * Returns 0 on success, -1 on error and reports libvirt error
 */
254 255 256 257 258 259
static int
qemuDomainChangeMediaLegacy(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainDiskDefPtr disk,
                            virStorageSourcePtr newsrc,
                            bool force)
260
{
261 262
    int rc;
    VIR_AUTOFREE(char *) driveAlias = NULL;
263
    qemuDomainObjPrivatePtr priv = vm->privateData;
264
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
265
    const char *format = NULL;
266
    VIR_AUTOFREE(char *) sourcestr = NULL;
267

268
    if (!disk->info.alias) {
269
        virReportError(VIR_ERR_INTERNAL_ERROR,
270
                       _("missing disk device alias name for %s"), disk->dst);
271
        return -1;
272 273
    }

274
    if (!(driveAlias = qemuAliasDiskDriveFromDisk(disk)))
275
        return -1;
276

277 278 279
    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
280
        return -1;
281

282 283
    /* If the tray is present wait for it to open. */
    if (!force && diskPriv->tray) {
284
        rc = qemuHotplugWaitForTrayEject(vm, disk);
285
        if (rc < 0)
286
            return -1;
287 288 289 290 291

        /* re-issue ejection command to pop out the media */
        qemuDomainObjEnterMonitor(driver, vm);
        rc = qemuMonitorEjectMedia(priv->mon, driveAlias, false);
        if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
292
            return -1;
293

294 295 296
    } else  {
        /* otherwise report possible errors from the attempt to eject the media*/
        if (rc < 0)
297
            return -1;
298
    }
299

300
    if (!virStorageSourceIsEmpty(newsrc)) {
301
        if (qemuGetDriveSourceString(newsrc, NULL, &sourcestr) < 0)
302
            return -1;
303

304 305 306
        if (virStorageSourceGetActualType(newsrc) != VIR_STORAGE_TYPE_DIR)
            format = virStorageFileFormatTypeToString(newsrc->format);

307
        qemuDomainObjEnterMonitor(driver, vm);
308 309 310 311 312
        rc = qemuMonitorChangeMedia(priv->mon,
                                    driveAlias,
                                    sourcestr,
                                    format);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
313
            return -1;
314
    }
315

316
    if (rc < 0)
317
        return -1;
318

319
    return 0;
320 321
}

322

323
/**
324 325
 * qemuHotplugAttachManagedPR:
 * @driver: QEMU driver object
326
 * @vm: domain object
327 328
 * @src: new disk source to be attached to @vm
 * @asyncJob: asynchronous job identifier
329
 *
330 331
 * Checks if it's needed to start qemu-pr-helper and add the corresponding
 * pr-manager-helper object.
332
 *
333
 * Returns: 0 on success, -1 on error.
334 335
 */
static int
336 337 338 339
qemuHotplugAttachManagedPR(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virStorageSourcePtr src,
                           qemuDomainAsyncJob asyncJob)
340 341
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
342
    virJSONValuePtr props = NULL;
343
    bool daemonStarted = false;
344
    int ret = -1;
345
    int rc;
346

347
    if (priv->prDaemonRunning ||
348
        !virStorageSourceChainHasManagedPR(src))
349 350
        return 0;

351
    if (!(props = qemuBuildPRManagedManagerInfoProps(priv)))
352 353
        return -1;

354 355
    if (qemuProcessStartManagedPRDaemon(vm) < 0)
        goto cleanup;
356

357 358 359 360 361 362 363 364 365 366
    daemonStarted = true;

    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;

    rc = qemuMonitorAddObject(priv->mon, &props, NULL);

    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
        goto cleanup;

367
    ret = 0;
368

369
 cleanup:
370 371
    if (ret < 0 && daemonStarted)
        qemuProcessKillManagedPRDaemon(vm);
372 373
    virJSONValueFree(props);
    return ret;
374 375 376
}


377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
/**
 * qemuHotplugRemoveManagedPR:
 * @driver: QEMU driver object
 * @vm: domain object
 * @asyncJob: asynchronous job identifier
 *
 * Removes the managed PR object from @vm if the configuration does not require
 * it any more.
 */
static int
qemuHotplugRemoveManagedPR(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virErrorPtr orig_err;
393
    int ret = -1;
394

395
    if (qemuDomainDefHasManagedPR(vm))
396 397
        return 0;

398 399
    virErrorPreserveLast(&orig_err);

400
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
401
        goto cleanup;
402 403
    ignore_value(qemuMonitorDelObject(priv->mon, qemuDomainGetManagedPRAlias()));
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
404
        goto cleanup;
405 406 407

    qemuProcessKillManagedPRDaemon(vm);

408 409 410 411
    ret = 0;
 cleanup:
    virErrorRestore(&orig_err);
    return ret;
412 413 414
}


M
Marc-André Lureau 已提交
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
/**
 * qemuDomainAttachDBusVMState:
 * @driver: QEMU driver object
 * @vm: domain object
 * @id
 * @addr
 * @asyncJob: asynchronous job identifier
 *
 * Add dbus-vmstate object.
 *
 * Returns: 0 on success, -1 on error.
 */
int
qemuDomainAttachDBusVMState(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            const char *id,
                            const char *addr,
                            qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    VIR_AUTOPTR(virJSONValue) props = NULL;
    int ret;

    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("dbus-vmstate object is not supported by this QEMU binary"));
        return -1;
    }

    if (!(props = qemuBuildDBusVMStateInfoProps(id, addr)))
        return -1;

    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        return -1;

    ret = qemuMonitorAddObject(priv->mon, &props, NULL);

    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        return -1;

    return ret;
}


/**
 * qemuDomainDetachDBusVMState:
 * @driver: QEMU driver object
 * @vm: domain object
 * @asyncJob: asynchronous job identifier
 *
 * Remove dbus-vmstate object from @vm.
 *
 * Returns: 0 on success, -1 on error.
 */
int
qemuDomainDetachDBusVMState(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            const char *id,
                            qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    VIR_AUTOFREE(char *) alias = qemuAliasDBusVMStateFromId(id);
    int ret;

    if (!alias ||
        qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        return -1;

    ret = qemuMonitorDelObject(priv->mon, alias);

    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        return -1;

    return ret;
}


492 493 494 495 496
/**
 * qemuDomainChangeMediaBlockdev:
 * @driver: qemu driver structure
 * @vm: domain definition
 * @disk: disk definition to change the source of
497
 * @oldsrc: old source definition
498 499 500 501 502 503 504 505 506 507 508 509 510 511
 * @newsrc: new disk source to change to
 * @force: force the change of media
 *
 * Change the media in an ejectable device to the one described by
 * @newsrc. This function also removes the old source from the
 * shared device table if appropriate. Note that newsrc is consumed
 * on success and the old source is freed on success.
 *
 * Returns 0 on success, -1 on error and reports libvirt error
 */
static int
qemuDomainChangeMediaBlockdev(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainDiskDefPtr disk,
512
                              virStorageSourcePtr oldsrc,
513 514 515 516 517
                              virStorageSourcePtr newsrc,
                              bool force)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
518 519
    VIR_AUTOPTR(qemuBlockStorageSourceChainData) newbackend = NULL;
    VIR_AUTOPTR(qemuBlockStorageSourceChainData) oldbackend = NULL;
520 521 522 523
    char *nodename = NULL;
    int rc;
    int ret = -1;

524
    if (!virStorageSourceIsEmpty(oldsrc) &&
525
        !(oldbackend = qemuBlockStorageSourceChainDetachPrepareBlockdev(oldsrc)))
526 527
        goto cleanup;

528
    if (!virStorageSourceIsEmpty(newsrc)) {
529 530
        if (!(newbackend = qemuBuildStorageSourceChainAttachPrepareBlockdev(newsrc,
                                                                            priv->qemuCaps)))
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
            goto cleanup;

        if (qemuDomainDiskGetBackendAlias(disk, priv->qemuCaps, &nodename) < 0)
            goto cleanup;
    }

    if (diskPriv->tray && disk->tray_status != VIR_DOMAIN_DISK_TRAY_OPEN) {
        qemuDomainObjEnterMonitor(driver, vm);
        rc = qemuMonitorBlockdevTrayOpen(priv->mon, diskPriv->qomName, force);
        if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
            goto cleanup;

        if (!force && qemuHotplugWaitForTrayEject(vm, disk) < 0)
            goto cleanup;
    }

    qemuDomainObjEnterMonitor(driver, vm);

    rc = qemuMonitorBlockdevMediumRemove(priv->mon, diskPriv->qomName);

    if (rc == 0 && oldbackend)
552
        qemuBlockStorageSourceChainDetach(priv->mon, oldbackend);
553 554 555

    if (newbackend && nodename) {
        if (rc == 0)
556
            rc = qemuBlockStorageSourceChainAttach(priv->mon, newbackend);
557 558 559 560 561 562 563 564 565

        if (rc == 0)
            rc = qemuMonitorBlockdevMediumInsert(priv->mon, diskPriv->qomName,
                                                 nodename);
    }

    if (rc == 0)
        rc = qemuMonitorBlockdevTrayClose(priv->mon, diskPriv->qomName);

566 567 568
    if (rc < 0 && newbackend)
        qemuBlockStorageSourceChainDetach(priv->mon, newbackend);

569 570 571 572 573 574
    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
        goto cleanup;

    ret = 0;

 cleanup:
575
    VIR_FREE(nodename);
576 577 578 579
    return ret;
}


580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
/**
 * qemuDomainChangeEjectableMedia:
 * @driver: qemu driver structure
 * @vm: domain definition
 * @disk: disk definition to change the source of
 * @newsrc: new disk source to change to
 * @force: force the change of media
 *
 * Change the media in an ejectable device to the one described by
 * @newsrc. This function also removes the old source from the
 * shared device table if appropriate. Note that newsrc is consumed
 * on success and the old source is freed on success.
 *
 * Returns 0 on success, -1 on error and reports libvirt error
 */
595
int
596 597 598 599 600 601
qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainDiskDefPtr disk,
                               virStorageSourcePtr newsrc,
                               bool force)
{
602
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
603
    qemuDomainObjPrivatePtr priv = vm->privateData;
604
    virStorageSourcePtr oldsrc = disk->src;
605
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
606
    bool sharedAdded = false;
607 608 609
    int ret = -1;
    int rc;

610 611 612 613 614 615
    if (diskPriv->blockjob && qemuBlockJobIsRunning(diskPriv->blockjob)) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("can't change media while a block job is running on the device"));
        return -1;
    }

616 617
    disk->src = newsrc;

618 619 620 621 622 623 624 625
    if (virDomainDiskTranslateSourcePool(disk) < 0)
        goto cleanup;

    if (qemuAddSharedDisk(driver, disk, vm->def->name) < 0)
        goto cleanup;

    sharedAdded = true;

626
    if (qemuDomainDetermineDiskChain(driver, vm, disk, NULL, true) < 0)
627 628
        goto cleanup;

629 630 631
    if (qemuDomainPrepareDiskSource(disk, priv, cfg) < 0)
        goto cleanup;

632
    if (qemuDomainStorageSourceChainAccessAllow(driver, vm, newsrc) < 0)
633 634
        goto cleanup;

635 636 637
    if (qemuHotplugAttachManagedPR(driver, vm, newsrc, QEMU_ASYNC_JOB_NONE) < 0)
        goto cleanup;

638
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
639
        rc = qemuDomainChangeMediaBlockdev(driver, vm, disk, oldsrc, newsrc, force);
640 641
    else
        rc = qemuDomainChangeMediaLegacy(driver, vm, disk, newsrc, force);
642

643
    virDomainAuditDisk(vm, oldsrc, newsrc, "update", rc >= 0);
644

645
    if (rc < 0)
646 647 648
        goto cleanup;

    /* remove the old source from shared device list */
649
    disk->src = oldsrc;
650
    ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));
651
    ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, oldsrc));
652

653
    /* media was changed, so we can remove the old media definition now */
654
    virObjectUnref(oldsrc);
655 656
    oldsrc = NULL;
    disk->src = newsrc;
657

658 659 660
    ret = 0;

 cleanup:
661 662 663 664 665
    /* undo changes to the new disk */
    if (ret < 0) {
        if (sharedAdded)
            ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));

666
        ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, newsrc));
667 668 669 670 671 672
    }

    /* remove PR manager object if unneeded */
    ignore_value(qemuHotplugRemoveManagedPR(driver, vm, QEMU_ASYNC_JOB_NONE));

    /* revert old image do the disk definition */
673 674 675
    if (oldsrc)
        disk->src = oldsrc;

676 677 678 679
    return ret;
}


680 681 682 683 684
/**
 * qemuDomainAttachDiskGeneric:
 *
 * Attaches disk to a VM. This function aggregates common code for all bus types.
 * In cases when the VM crashed while adding the disk, -2 is returned. */
685
static int
686
qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
687 688
                            virDomainObjPtr vm,
                            virDomainDiskDefPtr disk)
689
{
690
    VIR_AUTOPTR(qemuBlockStorageSourceChainData) data = NULL;
691
    int ret = -1;
692
    qemuDomainObjPrivatePtr priv = vm->privateData;
693
    VIR_AUTOFREE(char *) devstr = NULL;
694
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
695 696
    VIR_AUTOPTR(virJSONValue) corProps = NULL;
    VIR_AUTOFREE(char *) corAlias = NULL;
697
    bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
698

699
    if (qemuDomainStorageSourceChainAccessAllow(driver, vm, disk->src) < 0)
700
        goto cleanup;
701

702
    if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
703
        goto error;
704

705 706 707
    if (qemuDomainPrepareDiskSource(disk, priv, cfg) < 0)
        goto error;

708
    if (blockdev) {
709 710 711 712
        if (disk->copy_on_read == VIR_TRISTATE_SWITCH_ON &&
            !(corProps = qemuBlockStorageGetCopyOnReadProps(disk)))
        goto cleanup;

713 714 715 716 717 718 719 720
        if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdev(disk->src,
                                                                      priv->qemuCaps)))
            goto cleanup;
    } else {
        if (!(data = qemuBuildStorageSourceChainAttachPrepareDrive(disk,
                                                                   priv->qemuCaps)))
            goto cleanup;
    }
721

722
    if (!(devstr = qemuBuildDiskDeviceStr(vm->def, disk, 0, priv->qemuCaps)))
723
        goto error;
724

725
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
726 727
        goto error;

728 729
    if (qemuHotplugAttachManagedPR(driver, vm, disk->src, QEMU_ASYNC_JOB_NONE) < 0)
        goto error;
730

731
    qemuDomainObjEnterMonitor(driver, vm);
732

733
    if (qemuBlockStorageSourceChainAttach(priv->mon, data) < 0)
734
        goto exit_monitor;
735

736 737 738 739
    if (corProps &&
        qemuMonitorAddObject(priv->mon, &corProps, &corAlias) < 0)
        goto exit_monitor;

740 741 742 743 744
    if (qemuDomainAttachExtensionDevice(priv->mon, &disk->info) < 0)
        goto exit_monitor;

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &disk->info));
745
        goto exit_monitor;
746
    }
747

748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
    /* Setup throttling of disk via block_set_io_throttle QMP command. This
     * is a hack until the 'throttle' blockdev driver will support modification
     * of the trhottle group. See also qemuProcessSetupDiskThrottlingBlockdev.
     * As there isn't anything sane to do if this fails, let's just return
     * success.
     */
    if (blockdev &&
        qemuDiskConfigBlkdeviotuneEnabled(disk)) {
        qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
        if (qemuMonitorSetBlockIoThrottle(priv->mon, NULL, diskPriv->qomName,
                                          &disk->blkdeviotune,
                                          true, true, true) < 0)
            VIR_WARN("failed to set blkdeviotune for '%s' of '%s'", disk->dst, vm->def->name);
    }

763
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
764
        ret = -2;
765
        goto error;
766
    }
767

768
    virDomainAuditDisk(vm, NULL, disk->src, "attach", true);
769 770

    virDomainDiskInsertPreAlloced(vm->def, disk);
771
    ret = 0;
772

773
 cleanup:
774
    qemuDomainSecretDiskDestroy(disk);
775
    return ret;
776

777
 exit_monitor:
778 779
    if (corAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, corAlias));
780
    qemuBlockStorageSourceChainDetach(priv->mon, data);
781

782
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
783
        ret = -2;
784 785 786

    if (virStorageSourceChainHasManagedPR(disk->src) &&
        qemuHotplugRemoveManagedPR(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
787
        ret = -2;
788 789 790

    virDomainAuditDisk(vm, NULL, disk->src, "attach", false);

791
 error:
792
    ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, disk->src));
793
    goto cleanup;
794 795 796
}


797
static int
798
qemuDomainAttachVirtioDiskDevice(virQEMUDriverPtr driver,
799 800 801 802 803 804 805 806 807 808
                                 virDomainObjPtr vm,
                                 virDomainDiskDefPtr disk)
{
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_DISK, { .disk = disk } };
    bool releaseaddr = false;
    int rv;

    if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, disk->dst) < 0)
        return -1;

809
    if ((rv = qemuDomainAttachDiskGeneric(driver, vm, disk)) < 0) {
810
        if (rv == -1 && releaseaddr)
811
            qemuDomainReleaseDeviceAddress(vm, &disk->info);
812 813 814 815 816 817 818 819

        return -1;
    }

    return 0;
}


820 821 822
int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
                                     virDomainObjPtr vm,
                                     virDomainControllerDefPtr controller)
823 824 825 826 827
{
    int ret = -1;
    const char* type = virDomainControllerTypeToString(controller->type);
    char *devstr = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
828 829
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CONTROLLER,
                               { .controller = controller } };
830
    bool releaseaddr = false;
831

832 833 834 835 836 837 838
    if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
                       virDomainControllerTypeToString(controller->type));
        return -1;
    }

839 840 841 842 843 844 845 846
    /* default idx would normally be set by virDomainDefPostParse(),
     * which isn't called in the case of live attach of a single
     * device.
     */
    if (controller->idx == -1)
       controller->idx = virDomainControllerFindUnusedIndex(vm->def,
                                                            controller->type);

847
    if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) {
848 849 850 851
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target %s:%d already exists"),
                       type, controller->idx);
        return -1;
852 853
    }

854 855
    if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, "controller") < 0)
        return -1;
856

857 858 859
    if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, controller) < 0)
        goto cleanup;

860
    if (qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, &devstr) < 0)
861 862 863
        goto cleanup;

    if (!devstr)
864
        goto cleanup;
865

866
    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0)
867 868
        goto cleanup;

869
    qemuDomainObjEnterMonitor(driver, vm);
870 871 872 873 874 875 876 877 878 879

    if ((ret = qemuDomainAttachExtensionDevice(priv->mon,
                                               &controller->info)) < 0) {
        goto exit_monitor;
    }

    if ((ret = qemuMonitorAddDevice(priv->mon, devstr)) < 0)
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &controller->info));

 exit_monitor:
880 881 882 883 884
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseaddr = false;
        ret = -1;
        goto cleanup;
    }
885

886
    if (ret == 0)
887 888
        virDomainControllerInsertPreAlloced(vm->def, controller);

889
 cleanup:
890
    if (ret != 0 && releaseaddr)
891
        qemuDomainReleaseDeviceAddress(vm, &controller->info);
892 893 894 895 896 897

    VIR_FREE(devstr);
    return ret;
}

static virDomainControllerDefPtr
898
qemuDomainFindOrCreateSCSIDiskController(virQEMUDriverPtr driver,
899
                                         virDomainObjPtr vm,
900
                                         int controller)
901
{
902
    size_t i;
903
    virDomainControllerDefPtr cont;
904
    qemuDomainObjPrivatePtr priv = vm->privateData;
905
    int model = -1;
906

907
    for (i = 0; i < vm->def->ncontrollers; i++) {
908 909 910 911 912 913 914
        cont = vm->def->controllers[i];

        if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
            continue;

        if (cont->idx == controller)
            return cont;
915 916 917 918 919 920 921 922 923 924

        /* Because virDomainHostdevAssignAddress called during
         * virDomainHostdevDefPostParse cannot add a new controller
         * it will assign a controller index to a controller that doesn't
         * exist leaving this code to perform the magic of adding the
         * controller. Because that code would be attempting to add a
         * SCSI disk to an existing controller, let's save the model
         * of the "last" SCSI controller we find so that if we end up
         * creating a controller below it uses the same controller model. */
        model = cont->model;
925 926 927 928
    }

    /* No SCSI controller present, for backward compatibility we
     * now hotplug a controller */
929
    if (VIR_ALLOC(cont) < 0)
930 931
        return NULL;
    cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
932
    cont->idx = controller;
933
    if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT)
934 935 936
        cont->model = qemuDomainGetSCSIControllerModel(vm->def, cont, priv->qemuCaps);
    else
        cont->model = model;
937

938
    VIR_INFO("No SCSI controller present, hotplugging one model=%s",
939
             virDomainControllerModelSCSITypeToString(cont->model));
940
    if (qemuDomainAttachControllerDevice(driver, vm, cont) < 0) {
941 942 943 944 945
        VIR_FREE(cont);
        return NULL;
    }

    if (!virDomainObjIsActive(vm)) {
946 947
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
948 949 950 951 952 953 954 955 956
        /* cont doesn't need freeing here, since the reference
         * now held in def->controllers */
        return NULL;
    }

    return cont;
}


957
static int
958
qemuDomainAttachSCSIDisk(virQEMUDriverPtr driver,
959 960
                         virDomainObjPtr vm,
                         virDomainDiskDefPtr disk)
961
{
962
    size_t i;
963 964 965

    /* We should have an address already, so make sure */
    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
966 967 968
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk address type %s"),
                       virDomainDeviceAddressTypeToString(disk->info.type));
969
        return -1;
970 971
    }

972 973 974 975 976 977
    if (virDomainSCSIDriveAddressIsUsed(vm->def, &disk->info.addr.drive)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain already contains a disk with that address"));
        return -1;
    }

978 979 980 981 982 983 984 985 986
    /* Let's make sure the disk has a controller defined and loaded before
     * trying to add it. The controller used by the disk must exist before a
     * qemu command line string is generated.
     *
     * Ensure that the given controller and all controllers with a smaller index
     * exist; there must not be any missing index in between.
     */
    for (i = 0; i <= disk->info.addr.drive.controller; i++) {
        if (!qemuDomainFindOrCreateSCSIDiskController(driver, vm, i))
987
            return -1;
988
    }
989

990
    if (qemuDomainAttachDiskGeneric(driver, vm, disk) < 0)
991
        return -1;
992

993
    return 0;
994 995 996
}


997
static int
998
qemuDomainAttachUSBMassStorageDevice(virQEMUDriverPtr driver,
999 1000
                                     virDomainObjPtr vm,
                                     virDomainDiskDefPtr disk)
1001 1002
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1003

1004 1005
    if (virDomainUSBAddressEnsure(priv->usbaddrs, &disk->info) < 0)
        return -1;
1006

1007
    if (qemuDomainAttachDiskGeneric(driver, vm, disk) < 0) {
1008
        virDomainUSBAddressRelease(priv->usbaddrs, &disk->info);
1009
        return -1;
1010
    }
1011

1012
    return 0;
1013 1014 1015
}


1016 1017 1018 1019
static int
qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriverPtr driver,
                                       virDomainObjPtr vm,
                                       virDomainDeviceDefPtr dev)
1020
{
1021
    size_t i;
1022 1023 1024
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

1025 1026 1027 1028 1029 1030 1031
    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM ||
        disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cdrom/floppy device hotplug isn't supported"));
        return -1;
    }

1032
    if (virDomainDiskTranslateSourcePool(disk) < 0)
1033
        goto cleanup;
1034 1035

    if (qemuAddSharedDevice(driver, dev, vm->def->name) < 0)
1036
        goto cleanup;
1037 1038

    if (qemuSetUnprivSGIO(dev) < 0)
1039
        goto cleanup;
1040

1041
    if (qemuDomainDetermineDiskChain(driver, vm, disk, NULL, true) < 0)
1042
        goto cleanup;
1043

1044 1045 1046 1047
    for (i = 0; i < vm->def->ndisks; i++) {
        if (virDomainDiskDefCheckDuplicateInfo(vm->def->disks[i], disk) < 0)
            goto cleanup;
    }
1048

1049 1050 1051 1052 1053
    switch ((virDomainDiskBus) disk->bus) {
    case VIR_DOMAIN_DISK_BUS_USB:
        if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("disk device='lun' is not supported for usb bus"));
1054
            break;
1055
        }
1056
        ret = qemuDomainAttachUSBMassStorageDevice(driver, vm, disk);
1057
        break;
1058

1059 1060
    case VIR_DOMAIN_DISK_BUS_VIRTIO:
        ret = qemuDomainAttachVirtioDiskDevice(driver, vm, disk);
1061
        break;
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079

    case VIR_DOMAIN_DISK_BUS_SCSI:
        ret = qemuDomainAttachSCSIDisk(driver, vm, disk);
        break;

    case VIR_DOMAIN_DISK_BUS_IDE:
    case VIR_DOMAIN_DISK_BUS_FDC:
    case VIR_DOMAIN_DISK_BUS_XEN:
    case VIR_DOMAIN_DISK_BUS_UML:
    case VIR_DOMAIN_DISK_BUS_SATA:
    case VIR_DOMAIN_DISK_BUS_SD:
        /* Note that SD card hotplug support should be added only once
         * they support '-device' (don't require -drive only).
         * See also: qemuDiskBusNeedsDriveArg */
    case VIR_DOMAIN_DISK_BUS_LAST:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("disk bus '%s' cannot be hotplugged."),
                       virDomainDiskBusTypeToString(disk->bus));
1080 1081
    }

1082
 cleanup:
1083 1084 1085 1086 1087 1088
    if (ret != 0)
        ignore_value(qemuRemoveSharedDevice(driver, dev, vm->def->name));
    return ret;
}


1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
/**
 * qemuDomainAttachDeviceDiskLive:
 * @driver: qemu driver struct
 * @vm: domain object
 * @dev: device to attach (expected type is DISK)
 *
 * Attach a new disk or in case of cdroms/floppies change the media in the drive.
 * This function handles all the necessary steps to attach a new storage source
 * to the VM.
 */
int
qemuDomainAttachDeviceDiskLive(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainDeviceDefPtr dev)
{
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
    virDomainDiskDefPtr disk = dev->data.disk;
    virDomainDiskDefPtr orig_disk = NULL;

    /* this API overloads media change semantics on disk hotplug
     * for devices supporting media changes */
    if ((disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM ||
         disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) &&
        (orig_disk = virDomainDiskFindByBusAndDst(vm->def, disk->bus, disk->dst))) {
        if (qemuDomainChangeEjectableMedia(driver, vm, orig_disk,
                                           disk->src, false) < 0)
            return -1;

        disk->src = NULL;
        return 0;
    }

1120 1121 1122 1123
    return qemuDomainAttachDeviceDiskLiveInternal(driver, vm, dev);
}


1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
static void
qemuDomainNetDeviceVportRemove(virDomainNetDefPtr net)
{
    virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net);
    const char *brname;

    if (!vport)
        return;

    if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_MIDONET) {
        ignore_value(virNetDevMidonetUnbindPort(vport));
    } else if (vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
        brname = virDomainNetGetActualBridgeName(net);
        ignore_value(virNetDevOpenvswitchRemovePort(brname, net->ifname));
    }
}


1142 1143 1144 1145
int
qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainNetDefPtr net)
1146 1147
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1148
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_NET, { .net = net } };
1149
    virErrorPtr originalError = NULL;
1150 1151
    VIR_AUTOFREE(char *) slirpfdName = NULL;
    int slirpfd = -1;
1152 1153
    char **tapfdName = NULL;
    int *tapfd = NULL;
1154
    size_t tapfdSize = 0;
1155 1156
    char **vhostfdName = NULL;
    int *vhostfd = NULL;
1157
    size_t vhostfdSize = 0;
1158
    size_t queueSize = 0;
1159 1160 1161
    char *nicstr = NULL;
    char *netstr = NULL;
    int ret = -1;
1162
    bool releaseaddr = false;
1163
    bool iface_connected = false;
1164
    virDomainNetType actualType;
1165
    virNetDevBandwidthPtr actualBandwidth;
1166
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
1167
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
1168
    size_t i;
1169 1170 1171
    char *charDevAlias = NULL;
    bool charDevPlugged = false;
    bool netdevPlugged = false;
1172
    char *netdev_name;
1173
    virConnectPtr conn = NULL;
1174
    virErrorPtr save_err = NULL;
1175

1176
    /* preallocate new slot for device */
1177
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
1178
        goto cleanup;
1179

1180 1181 1182 1183
    /* If appropriate, grab a physical device from the configured
     * network's pool of devices, or resolve bridge device name
     * to the one defined in the network definition.
     */
1184 1185 1186 1187 1188 1189
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        if (!(conn = virGetConnectNetwork()))
            goto cleanup;
        if (virDomainNetAllocateActualDevice(conn, vm->def, net) < 0)
            goto cleanup;
    }
1190

1191 1192
    /* final validation now that we have full info on the type */
    if (qemuDomainValidateActualNetDef(net, priv->qemuCaps) < 0)
1193 1194
        return -1;

1195
    actualType = virDomainNetGetActualType(net);
1196

1197 1198 1199
    if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
        goto cleanup;

1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
    if (qemuDomainIsS390CCW(vm->def) &&
        net->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CCW)) {
        net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
        if (!(ccwaddrs = virDomainCCWAddressSetCreateFromDomain(vm->def)))
            goto cleanup;
        if (virDomainCCWAddressAssign(&net->info, ccwaddrs,
                                      !net->info.addr.ccw.assigned) < 0)
            goto cleanup;
    } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("virtio-s390 net device cannot be hotplugged."));
        goto cleanup;
    } else if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0) {
        goto cleanup;
    }

    releaseaddr = true;

1219 1220
    switch (actualType) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
1221
    case VIR_DOMAIN_NET_TYPE_NETWORK:
1222 1223 1224
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1225
        queueSize = tapfdSize;
1226
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1227
            goto cleanup;
1228 1229 1230 1231
        memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
        if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
            goto cleanup;
        memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
1232
        if (qemuInterfaceBridgeConnect(vm->def, driver, net,
1233
                                       tapfd, &tapfdSize) < 0)
1234 1235
            goto cleanup;
        iface_connected = true;
J
Ján Tomko 已提交
1236
        if (qemuInterfaceOpenVhostNet(vm->def, net, vhostfd, &vhostfdSize) < 0)
1237
            goto cleanup;
1238 1239 1240
        break;

    case VIR_DOMAIN_NET_TYPE_DIRECT:
1241 1242 1243
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1244
        queueSize = tapfdSize;
1245
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1246
            goto cleanup;
1247 1248
        memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
        if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
1249
            goto cleanup;
1250
        memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
1251 1252 1253
        if (qemuInterfaceDirectConnect(vm->def, driver, net,
                                       tapfd, tapfdSize,
                                       VIR_NETDEV_VPORT_PROFILE_OP_CREATE) < 0)
1254 1255
            goto cleanup;
        iface_connected = true;
J
Ján Tomko 已提交
1256
        if (qemuInterfaceOpenVhostNet(vm->def, net, vhostfd, &vhostfdSize) < 0)
1257
            goto cleanup;
1258 1259 1260
        break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
1261 1262 1263
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1264
        queueSize = tapfdSize;
1265
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1266
            goto cleanup;
1267 1268 1269 1270 1271
        memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
        if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
            goto cleanup;
        memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
        if (qemuInterfaceEthernetConnect(vm->def, driver, net,
1272
                                         tapfd, tapfdSize) < 0)
1273 1274
            goto cleanup;
        iface_connected = true;
J
Ján Tomko 已提交
1275
        if (qemuInterfaceOpenVhostNet(vm->def, net, vhostfd, &vhostfdSize) < 0)
1276
            goto cleanup;
1277 1278 1279
        break;

    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
1280 1281 1282 1283 1284
        /* This is really a "smart hostdev", so it should be attached
         * as a hostdev (the hostdev code will reach over into the
         * netdev-specific code as appropriate), then also added to
         * the nets list (see cleanup:) if successful.
         */
1285
        ret = qemuDomainAttachHostDevice(driver, vm,
1286 1287
                                         virDomainNetGetActualHostdev(net));
        goto cleanup;
1288 1289 1290
        break;

    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
1291 1292 1293
        queueSize = net->driver.virtio.queues;
        if (!queueSize)
            queueSize = 1;
1294
        if (!qemuDomainSupportsNicdev(vm->def, net)) {
1295
            virReportError(VIR_ERR_INTERNAL_ERROR,
1296
                           "%s", _("Nicdev support unavailable"));
1297 1298 1299
            goto cleanup;
        }

1300
        if (!(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias)))
1301
            goto cleanup;
1302 1303 1304 1305 1306

        if (virNetDevOpenvswitchGetVhostuserIfname(net->data.vhostuser->data.nix.path,
                                                   &net->ifname) < 0)
            goto cleanup;

1307 1308 1309
        break;

    case VIR_DOMAIN_NET_TYPE_USER:
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
        if (!priv->disableSlirp &&
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NET_SOCKET_DGRAM)) {
            qemuSlirpPtr slirp = qemuInterfacePrepareSlirp(driver, net);

            if (!slirp)
                break;

            QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp = slirp;

            if (qemuSlirpOpen(slirp, driver, vm->def) < 0 ||
                qemuSlirpStart(slirp, vm, driver, net, true, NULL) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("Failed to start slirp"));
                goto cleanup;
            }

            slirpfd = qemuSlirpGetFD(slirp);
            if (virAsprintf(&slirpfdName, "slirpfd-%s", net->info.alias) < 0)
                goto cleanup;
        }
1330 1331
        break;

1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_UDP:
    case VIR_DOMAIN_NET_TYPE_LAST:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("hotplug of interface type of %s is not implemented yet"),
                       virDomainNetTypeToString(actualType));
        goto cleanup;
1342 1343
    }

1344 1345
    /* Set device online immediately */
    if (qemuInterfaceStartDevice(net) < 0)
1346
        goto cleanup;
1347

1348 1349 1350 1351
    /* Set bandwidth or warn if requested and not supported. */
    actualBandwidth = virDomainNetGetActualBandwidth(net);
    if (actualBandwidth) {
        if (virNetDevSupportBandwidth(actualType)) {
1352 1353
            if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false,
                                      !virDomainNetTypeSharesHostView(net)) < 0)
1354 1355 1356 1357 1358 1359 1360
                goto cleanup;
        } else {
            VIR_WARN("setting bandwidth on interfaces of "
                     "type '%s' is not implemented yet",
                     virDomainNetTypeToString(actualType));
        }
    }
1361

1362 1363 1364 1365
    if (net->mtu &&
        virNetDevSetMTU(net->ifname, net->mtu) < 0)
        goto cleanup;

M
Michal Privoznik 已提交
1366
    for (i = 0; i < tapfdSize; i++) {
1367 1368
        if (qemuSecuritySetTapFDLabel(driver->securityManager,
                                      vm->def, tapfd[i]) < 0)
M
Michal Privoznik 已提交
1369 1370 1371
            goto cleanup;
    }

1372
    if (VIR_ALLOC_N(tapfdName, tapfdSize) < 0 ||
1373
        VIR_ALLOC_N(vhostfdName, vhostfdSize) < 0)
1374 1375 1376
        goto cleanup;

    for (i = 0; i < tapfdSize; i++) {
1377
        if (virAsprintf(&tapfdName[i], "fd-%s%zu", net->info.alias, i) < 0)
1378
            goto cleanup;
1379 1380
    }

1381
    for (i = 0; i < vhostfdSize; i++) {
1382
        if (virAsprintf(&vhostfdName[i], "vhostfd-%s%zu", net->info.alias, i) < 0)
1383
            goto cleanup;
1384 1385
    }

1386
    if (!(netstr = qemuBuildHostNetStr(net,
J
Ján Tomko 已提交
1387
                                       tapfdName, tapfdSize,
1388
                                       vhostfdName, vhostfdSize,
1389
                                       slirpfdName)))
J
Ján Tomko 已提交
1390
        goto cleanup;
1391

1392
    qemuDomainObjEnterMonitor(driver, vm);
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402

    if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
        if (qemuMonitorAttachCharDev(priv->mon, charDevAlias, net->data.vhostuser) < 0) {
            ignore_value(qemuDomainObjExitMonitor(driver, vm));
            virDomainAuditNet(vm, NULL, net, "attach", false);
            goto cleanup;
        }
        charDevPlugged = true;
    }

J
Ján Tomko 已提交
1403 1404
    if (qemuMonitorAddNetdev(priv->mon, netstr,
                             tapfd, tapfdName, tapfdSize,
1405 1406
                             vhostfd, vhostfdName, vhostfdSize,
                             slirpfd, slirpfdName) < 0) {
J
Ján Tomko 已提交
1407 1408 1409
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto try_remove;
1410
    }
J
Ján Tomko 已提交
1411
    netdevPlugged = true;
1412

1413 1414
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
1415

1416 1417 1418 1419
    for (i = 0; i < tapfdSize; i++)
        VIR_FORCE_CLOSE(tapfd[i]);
    for (i = 0; i < vhostfdSize; i++)
        VIR_FORCE_CLOSE(vhostfd[i]);
1420

1421
    if (!(nicstr = qemuBuildNicDevStr(vm->def, net, 0,
1422
                                      queueSize, priv->qemuCaps)))
1423
        goto try_remove;
1424

1425
    qemuDomainObjEnterMonitor(driver, vm);
1426 1427 1428 1429 1430 1431 1432

    if (qemuDomainAttachExtensionDevice(priv->mon, &net->info) < 0) {
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto try_remove;
    }

1433
    if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
1434
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &net->info));
1435 1436 1437
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto try_remove;
1438
    }
1439 1440
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
1441

1442 1443 1444
    /* set link state */
    if (net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
        if (!net->info.alias) {
1445 1446
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("device alias not found: cannot set link state to down"));
1447
        } else {
1448
            qemuDomainObjEnterMonitor(driver, vm);
1449

J
Ján Tomko 已提交
1450 1451 1452 1453
            if (qemuMonitorSetLink(priv->mon, net->info.alias, VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) < 0) {
                ignore_value(qemuDomainObjExitMonitor(driver, vm));
                virDomainAuditNet(vm, NULL, net, "attach", false);
                goto try_remove;
1454 1455
            }

1456 1457
            if (qemuDomainObjExitMonitor(driver, vm) < 0)
                goto cleanup;
1458 1459 1460 1461
        }
        /* link set to down */
    }

1462
    virDomainAuditNet(vm, NULL, net, "attach", true);
1463 1464 1465

    ret = 0;

1466
 cleanup:
1467 1468 1469
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else {
1470
        virErrorPreserveLast(&save_err);
1471
        if (releaseaddr)
1472
            qemuDomainReleaseDeviceAddress(vm, &net->info);
1473

1474
        if (iface_connected) {
1475
            virErrorPreserveLast(&originalError);
1476
            virDomainConfNWFilterTeardown(net);
1477
            virErrorRestore(&originalError);
1478

1479 1480 1481 1482 1483 1484 1485 1486 1487
            if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
                ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
                                 net->ifname, &net->mac,
                                 virDomainNetGetActualDirectDev(net),
                                 virDomainNetGetActualDirectMode(net),
                                 virDomainNetGetActualVirtPortProfile(net),
                                 cfg->stateDir));
            }

1488
            qemuDomainNetDeviceVportRemove(net);
1489
        }
A
Ansis Atteka 已提交
1490

1491 1492
        virDomainNetRemoveHostdev(vm->def, net);

1493 1494 1495 1496 1497 1498
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            if (conn)
                virDomainNetReleaseActualDevice(conn, vm->def, net);
            else
                VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
        }
1499
        virErrorRestore(&save_err);
1500
    }
1501 1502 1503

    VIR_FREE(nicstr);
    VIR_FREE(netstr);
1504
    for (i = 0; tapfd && i < tapfdSize; i++) {
1505
        VIR_FORCE_CLOSE(tapfd[i]);
1506 1507
        if (tapfdName)
            VIR_FREE(tapfdName[i]);
1508 1509 1510
    }
    VIR_FREE(tapfd);
    VIR_FREE(tapfdName);
1511
    for (i = 0; vhostfd && i < vhostfdSize; i++) {
1512
        VIR_FORCE_CLOSE(vhostfd[i]);
1513 1514
        if (vhostfdName)
            VIR_FREE(vhostfdName[i]);
1515 1516 1517
    }
    VIR_FREE(vhostfd);
    VIR_FREE(vhostfdName);
1518
    VIR_FREE(charDevAlias);
1519
    virObjectUnref(conn);
1520
    virDomainCCWAddressSetFree(ccwaddrs);
1521
    VIR_FORCE_CLOSE(slirpfd);
1522 1523 1524

    return ret;

1525
 try_remove:
1526 1527 1528
    if (!virDomainObjIsActive(vm))
        goto cleanup;

1529
    virErrorPreserveLast(&originalError);
1530
    if (virAsprintf(&netdev_name, "host%s", net->info.alias) >= 0) {
1531 1532
        if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
            qemuSlirpStop(QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp, vm, driver, net, true);
1533 1534 1535 1536 1537 1538 1539 1540 1541 1542
        qemuDomainObjEnterMonitor(driver, vm);
        if (charDevPlugged &&
            qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0)
            VIR_WARN("Failed to remove associated chardev %s", charDevAlias);
        if (netdevPlugged &&
            qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
            VIR_WARN("Failed to remove network backend for netdev %s",
                     netdev_name);
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        VIR_FREE(netdev_name);
1543
    }
1544
    virErrorRestore(&originalError);
1545 1546 1547 1548
    goto cleanup;
}


1549
static int
1550
qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
1551 1552
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
1553 1554
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1555 1556
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                               { .hostdev = hostdev } };
1557
    virDomainDeviceInfoPtr info = hostdev->info;
1558 1559
    int ret;
    char *devstr = NULL;
1560
    bool releaseaddr = false;
1561
    bool teardowncgroup = false;
1562
    bool teardownlabel = false;
1563
    bool teardowndevice = false;
1564
    bool teardownmemlock = false;
1565
    int backend;
1566
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
1567
    unsigned int flags = 0;
1568

1569
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
1570
        goto cleanup;
1571

1572 1573
    if (!cfg->relaxedACS)
        flags |= VIR_HOSTDEV_STRICT_ACS_CHECK;
1574
    if (qemuHostdevPreparePCIDevices(driver, vm->def->name, vm->def->uuid,
1575 1576
                                     &hostdev, 1, priv->qemuCaps, flags) < 0)
        goto cleanup;
1577

1578
    /* this could have been changed by qemuHostdevPreparePCIDevices */
1579 1580
    backend = hostdev->source.subsys.u.pci.backend;

1581
    switch ((virDomainHostdevSubsysPCIBackendType)backend) {
1582
    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
1583 1584 1585 1586 1587 1588
        if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("VFIO PCI device assignment is not "
                             "supported by this version of qemu"));
            goto error;
        }
1589 1590
        break;

1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
        break;

    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN:
    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("QEMU does not support device assignment mode '%s'"),
                       virDomainHostdevSubsysPCIBackendTypeToString(backend));
        goto error;
1601
        break;
1602 1603
    }

1604
    if (qemuDomainAdjustMaxMemLockHostdev(vm, hostdev) < 0)
1605
        goto error;
1606
    teardownmemlock = true;
1607

1608
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
1609 1610 1611
        goto error;
    teardowndevice = true;

1612
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
1613 1614 1615
        goto error;
    teardowncgroup = true;

1616
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
1617
        goto error;
1618 1619
    if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
        teardownlabel = true;
1620

1621
    if (qemuAssignDeviceHostdevAlias(vm->def, &info->alias, -1) < 0)
1622
        goto error;
1623 1624 1625 1626 1627 1628 1629

    if (qemuDomainIsPSeries(vm->def)) {
        /* Isolation groups are only relevant for pSeries guests */
        if (qemuDomainFillDeviceIsolationGroup(vm->def, &dev) < 0)
            goto error;
    }

1630
    if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
1631 1632
        goto error;
    releaseaddr = true;
1633

1634 1635 1636 1637 1638
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit during hotplug"));
        goto error;
    }
1639

M
Michal Privoznik 已提交
1640
    if (!(devstr = qemuBuildPCIHostdevDevStr(vm->def, hostdev, 0, priv->qemuCaps)))
1641
        goto error;
1642

1643
    qemuDomainObjEnterMonitor(driver, vm);
1644 1645 1646 1647

    if ((ret = qemuDomainAttachExtensionDevice(priv->mon, hostdev->info)) < 0)
        goto exit_monitor;

M
Michal Privoznik 已提交
1648
    if ((ret = qemuMonitorAddDevice(priv->mon, devstr)) < 0)
1649 1650 1651
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, hostdev->info));

 exit_monitor:
1652 1653
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto error;
1654

1655
    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
1656 1657 1658 1659 1660 1661 1662 1663 1664
    if (ret < 0)
        goto error;

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

    VIR_FREE(devstr);

    return 0;

1665
 error:
1666 1667
    if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
        VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
1668
    if (teardownlabel &&
1669
        qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
1670
        VIR_WARN("Unable to restore host device labelling on hotplug fail");
1671
    if (teardowndevice &&
1672
        qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
1673
        VIR_WARN("Unable to remove host device from /dev");
1674 1675
    if (teardownmemlock && qemuDomainAdjustMaxMemLock(vm) < 0)
        VIR_WARN("Unable to reset maximum locked memory on hotplug fail");
1676

1677
    if (releaseaddr)
1678
        qemuDomainReleaseDeviceAddress(vm, info);
1679

1680
    qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
1681 1682 1683

    VIR_FREE(devstr);

1684
 cleanup:
1685 1686 1687 1688
    return -1;
}


1689 1690 1691
void
qemuDomainDelTLSObjects(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
1692
                        qemuDomainAsyncJob asyncJob,
1693 1694 1695 1696 1697 1698 1699 1700 1701
                        const char *secAlias,
                        const char *tlsAlias)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virErrorPtr orig_err;

    if (!tlsAlias && !secAlias)
        return;

1702
    virErrorPreserveLast(&orig_err);
1703

1704 1705
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;
1706 1707 1708 1709 1710 1711 1712 1713 1714

    if (tlsAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, tlsAlias));

    if (secAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, secAlias));

    ignore_value(qemuDomainObjExitMonitor(driver, vm));

1715
 cleanup:
1716
    virErrorRestore(&orig_err);
1717 1718 1719 1720 1721 1722
}


int
qemuDomainAddTLSObjects(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
1723
                        qemuDomainAsyncJob asyncJob,
1724 1725 1726 1727 1728
                        virJSONValuePtr *secProps,
                        virJSONValuePtr *tlsProps)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virErrorPtr orig_err;
1729
    char *secAlias = NULL;
1730

1731
    if (!tlsProps && !secProps)
1732 1733
        return 0;

1734 1735
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        return -1;
1736

1737
    if (secProps && *secProps &&
1738 1739
        qemuMonitorAddObject(priv->mon, secProps, &secAlias) < 0)
        goto error;
1740

1741 1742 1743
    if (tlsProps &&
        qemuMonitorAddObject(priv->mon, tlsProps, NULL) < 0)
        goto error;
1744

1745 1746
    VIR_FREE(secAlias);

1747 1748 1749
    return qemuDomainObjExitMonitor(driver, vm);

 error:
1750
    virErrorPreserveLast(&orig_err);
1751
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
1752
    virErrorRestore(&orig_err);
1753
    qemuDomainDelTLSObjects(driver, vm, asyncJob, secAlias, NULL);
1754
    VIR_FREE(secAlias);
1755 1756 1757 1758 1759

    return -1;
}


1760 1761 1762 1763 1764 1765
int
qemuDomainGetTLSObjects(virQEMUCapsPtr qemuCaps,
                        qemuDomainSecretInfoPtr secinfo,
                        const char *tlsCertdir,
                        bool tlsListen,
                        bool tlsVerify,
1766
                        const char *alias,
1767
                        virJSONValuePtr *tlsProps,
1768
                        virJSONValuePtr *secProps)
1769
{
1770 1771
    const char *secAlias = NULL;

1772 1773
    if (secinfo) {
        if (qemuBuildSecretInfoProps(secinfo, secProps) < 0)
1774 1775
            return -1;

1776
        secAlias = secinfo->s.aes.alias;
1777 1778
    }

1779
    if (qemuBuildTLSx509BackendProps(tlsCertdir, tlsListen, tlsVerify,
1780
                                     alias, secAlias, qemuCaps, tlsProps) < 0)
1781 1782 1783 1784 1785 1786
        return -1;

    return 0;
}


1787
static int
1788
qemuDomainAddChardevTLSObjects(virQEMUDriverPtr driver,
1789 1790
                               virDomainObjPtr vm,
                               virDomainChrSourceDefPtr dev,
1791
                               char *devAlias,
1792 1793
                               char *charAlias,
                               char **tlsAlias,
1794
                               const char **secAlias)
1795 1796
{
    int ret = -1;
1797
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
1798
    qemuDomainObjPrivatePtr priv = vm->privateData;
1799 1800
    qemuDomainChrSourcePrivatePtr chrSourcePriv;
    qemuDomainSecretInfoPtr secinfo = NULL;
1801 1802 1803
    virJSONValuePtr tlsProps = NULL;
    virJSONValuePtr secProps = NULL;

1804 1805 1806
    /* NB: This may alter haveTLS based on cfg */
    qemuDomainPrepareChardevSourceTLS(dev, cfg);

1807
    if (dev->type != VIR_DOMAIN_CHR_TYPE_TCP ||
1808 1809 1810 1811
        dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_YES) {
        ret = 0;
        goto cleanup;
    }
1812

1813
    if (qemuDomainSecretChardevPrepare(cfg, priv, devAlias, dev) < 0)
1814 1815
        goto cleanup;

1816 1817 1818
    if ((chrSourcePriv = QEMU_DOMAIN_CHR_SOURCE_PRIVATE(dev)))
        secinfo = chrSourcePriv->secinfo;

1819 1820 1821
    if (secinfo)
        *secAlias = secinfo->s.aes.alias;

1822 1823 1824
    if (!(*tlsAlias = qemuAliasTLSObjFromSrcAlias(charAlias)))
        goto cleanup;

1825 1826 1827 1828
    if (qemuDomainGetTLSObjects(priv->qemuCaps, secinfo,
                                cfg->chardevTLSx509certdir,
                                dev->data.tcp.listen,
                                cfg->chardevTLSx509verify,
1829
                                *tlsAlias, &tlsProps, &secProps) < 0)
1830
        goto cleanup;
1831
    dev->data.tcp.tlscreds = true;
1832

1833
    if (qemuDomainAddTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
1834
                                &secProps, &tlsProps) < 0)
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846
        goto cleanup;

    ret = 0;

 cleanup:
    virJSONValueFree(tlsProps);
    virJSONValueFree(secProps);

    return ret;
}


1847 1848 1849
static int
qemuDomainDelChardevTLSObjects(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
1850
                               virDomainChrSourceDefPtr dev,
1851 1852 1853
                               const char *inAlias)
{
    int ret = -1;
1854
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
1855 1856 1857 1858
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *tlsAlias = NULL;
    char *secAlias = NULL;

1859 1860 1861 1862 1863 1864
    if (dev->type != VIR_DOMAIN_CHR_TYPE_TCP ||
        dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_YES) {
        ret = 0;
        goto cleanup;
    }

1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893
    if (!(tlsAlias = qemuAliasTLSObjFromSrcAlias(inAlias)))
        goto cleanup;

    /* Best shot at this as the secinfo is destroyed after process launch
     * and this path does not recreate it. Thus, if the config has the
     * secret UUID and we have a serial TCP chardev, then formulate a
     * secAlias which we'll attempt to destroy. */
    if (cfg->chardevTLSx509secretUUID &&
        !(secAlias = qemuDomainGetSecretAESAlias(inAlias, false)))
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);

    ignore_value(qemuMonitorDelObject(priv->mon, tlsAlias));
    if (secAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, secAlias));

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

    ret = 0;

 cleanup:
    VIR_FREE(tlsAlias);
    VIR_FREE(secAlias);
    return ret;
}


1894
int qemuDomainAttachRedirdevDevice(virQEMUDriverPtr driver,
1895 1896 1897
                                   virDomainObjPtr vm,
                                   virDomainRedirdevDefPtr redirdev)
{
1898
    int ret = -1;
1899
    qemuDomainObjPrivatePtr priv = vm->privateData;
1900
    virDomainDefPtr def = vm->def;
1901
    char *charAlias = NULL;
1902
    char *devstr = NULL;
1903
    bool chardevAdded = false;
1904
    char *tlsAlias = NULL;
1905
    const char *secAlias = NULL;
1906
    bool need_release = false;
1907
    virErrorPtr orig_err;
1908

1909
    if (qemuAssignDeviceRedirdevAlias(def, redirdev, -1) < 0)
1910 1911
        goto cleanup;

1912
    if (!(charAlias = qemuAliasChardevFromDevAlias(redirdev->info.alias)))
1913 1914
        goto cleanup;

1915
    if ((virDomainUSBAddressEnsure(priv->usbaddrs, &redirdev->info)) < 0)
1916
        goto cleanup;
1917
    need_release = true;
1918

1919
    if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, priv->qemuCaps)))
1920
        goto cleanup;
1921

1922
    if (VIR_REALLOC_N(def->redirdevs, def->nredirdevs+1) < 0)
1923
        goto cleanup;
1924

1925
    if (qemuDomainAddChardevTLSObjects(driver, vm, redirdev->source,
1926 1927
                                       redirdev->info.alias, charAlias,
                                       &tlsAlias, &secAlias) < 0)
1928
        goto audit;
1929

1930
    qemuDomainObjEnterMonitor(driver, vm);
1931

1932 1933
    if (qemuMonitorAttachCharDev(priv->mon,
                                 charAlias,
1934
                                 redirdev->source) < 0)
1935 1936
        goto exit_monitor;
    chardevAdded = true;
1937

1938 1939
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
        goto exit_monitor;
1940

1941 1942
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto audit;
1943

1944
    def->redirdevs[def->nredirdevs++] = redirdev;
1945 1946 1947 1948
    ret = 0;
 audit:
    virDomainAuditRedirdev(vm, redirdev, "attach", ret == 0);
 cleanup:
1949
    if (ret < 0 && need_release)
1950
        qemuDomainReleaseDeviceAddress(vm, &redirdev->info);
1951
    VIR_FREE(tlsAlias);
1952
    VIR_FREE(charAlias);
1953
    VIR_FREE(devstr);
1954
    return ret;
1955 1956

 exit_monitor:
1957
    virErrorPreserveLast(&orig_err);
1958 1959 1960
    /* detach associated chardev on error */
    if (chardevAdded)
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
1961
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
1962
    virErrorRestore(&orig_err);
1963 1964
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
1965
    goto audit;
1966 1967
}

1968 1969 1970
static int
qemuDomainChrPreInsert(virDomainDefPtr vmdef,
                       virDomainChrDefPtr chr)
1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984
{
    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("attaching serial console is not supported"));
        return -1;
    }

    if (virDomainChrFind(vmdef, chr)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("chardev already exists"));
        return -1;
    }

1985
    if (virDomainChrPreAlloc(vmdef, chr) < 0)
1986 1987
        return -1;

1988 1989 1990 1991
    /* Due to historical reasons, the first console is an alias to the
     * first serial device (if such exists). If this is the case, we need to
     * create an object for the first console as well.
     */
1992 1993 1994 1995 1996
    if (vmdef->nserials == 0 && vmdef->nconsoles == 0 &&
        chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
        if (!vmdef->consoles && VIR_ALLOC(vmdef->consoles) < 0)
            return -1;

1997 1998
        /* We'll be dealing with serials[0] directly, so NULL is fine here. */
        if (!(vmdef->consoles[0] = virDomainChrDefNew(NULL))) {
1999
            VIR_FREE(vmdef->consoles);
2000 2001
            return -1;
        }
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
        vmdef->nconsoles++;
    }
    return 0;
}

static void
qemuDomainChrInsertPreAlloced(virDomainDefPtr vmdef,
                              virDomainChrDefPtr chr)
{
    virDomainChrInsertPreAlloced(vmdef, chr);
    if (vmdef->nserials == 1 && vmdef->nconsoles == 0 &&
        chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
2014 2015 2016 2017 2018 2019
        vmdef->nconsoles = 1;

        /* Create an console alias for the serial port */
        vmdef->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
        vmdef->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL;
    }
2020 2021 2022 2023 2024 2025 2026 2027 2028
}

static void
qemuDomainChrInsertPreAllocCleanup(virDomainDefPtr vmdef,
                                   virDomainChrDefPtr chr)
{
    /* Remove the stub console added by qemuDomainChrPreInsert */
    if (vmdef->nserials == 0 && vmdef->nconsoles == 1 &&
        chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL) {
2029
        virDomainChrDefFree(vmdef->consoles[0]);
2030 2031 2032 2033
        VIR_FREE(vmdef->consoles);
        vmdef->nconsoles = 0;
    }
}
2034

2035 2036 2037 2038 2039 2040 2041 2042 2043
int
qemuDomainChrInsert(virDomainDefPtr vmdef,
                    virDomainChrDefPtr chr)
{
    if (qemuDomainChrPreInsert(vmdef, chr) < 0) {
        qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
        return -1;
    }
    qemuDomainChrInsertPreAlloced(vmdef, chr);
2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079
    return 0;
}

virDomainChrDefPtr
qemuDomainChrRemove(virDomainDefPtr vmdef,
                    virDomainChrDefPtr chr)
{
    virDomainChrDefPtr ret;
    bool removeCompat;

    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("detaching serial console is not supported"));
        return NULL;
    }

    /* Due to some crazy backcompat stuff, the first serial device is an alias
     * to the first console too. If this is the case, the definition must be
     * duplicated as first console device. */
    removeCompat = vmdef->nserials && vmdef->nconsoles &&
        vmdef->consoles[0]->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        vmdef->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL &&
        virDomainChrEquals(vmdef->serials[0], chr);

    if (!(ret = virDomainChrRemove(vmdef, chr))) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("device not present in domain configuration"));
            return NULL;
    }

    if (removeCompat)
        VIR_DELETE_ELEMENT(vmdef->consoles, 0, vmdef->nconsoles);

    return ret;
}
2080

2081 2082 2083 2084
/* Returns  1 if the address will need to be released later,
 *         -1 on error
 *          0 otherwise
 */
2085
static int
2086
qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm,
2087 2088
                                    virDomainChrDefPtr chr,
                                    virQEMUDriverPtr driver)
2089
{
2090 2091
    virDomainDefPtr def = vm->def;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2092
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CHR, { .chr = chr } };
2093

2094 2095
    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
2096
        if (virDomainVirtioSerialAddrAutoAssign(def, &chr->info, true) < 0)
2097
            return -1;
2098
        return 0;
2099 2100 2101

    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
               chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) {
2102
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
2103 2104
            return -1;
        return 1;
2105

2106
    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
2107 2108
               chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB) {
        if (virDomainUSBAddressEnsure(priv->usbaddrs, &chr->info) < 0)
2109 2110
            return -1;
        return 1;
2111

2112 2113
    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
               chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
2114
        if (virDomainVirtioSerialAddrAutoAssign(def, &chr->info, false) < 0)
2115
            return -1;
2116
        return 0;
2117 2118 2119 2120 2121 2122
    }

    if (chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL ||
        chr->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Unsupported address type for character device"));
2123
        return -1;
2124 2125
    }

2126
    return 0;
2127 2128
}

2129
int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
2130 2131 2132
                              virDomainObjPtr vm,
                              virDomainChrDefPtr chr)
{
2133
    int ret = -1, rc;
2134
    qemuDomainObjPrivatePtr priv = vm->privateData;
2135
    virErrorPtr orig_err;
2136 2137
    virDomainDefPtr vmdef = vm->def;
    char *devstr = NULL;
2138
    virDomainChrSourceDefPtr dev = chr->source;
2139
    char *charAlias = NULL;
2140
    bool chardevAttached = false;
2141
    bool teardowncgroup = false;
2142
    bool teardowndevice = false;
2143
    bool teardownlabel = false;
2144
    char *tlsAlias = NULL;
2145
    const char *secAlias = NULL;
2146
    bool need_release = false;
2147
    bool guestfwd = false;
2148

2149 2150 2151 2152 2153 2154
    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL) {
        guestfwd = chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD;

        if (qemuDomainPrepareChannel(chr, priv->channelTargetDir) < 0)
            goto cleanup;
    }
2155

2156
    if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0)
2157
        goto cleanup;
2158

2159
    if ((rc = qemuDomainAttachChrDeviceAssignAddr(vm, chr, driver)) < 0)
2160 2161 2162
        goto cleanup;
    if (rc == 1)
        need_release = true;
2163

2164
    if (qemuDomainNamespaceSetupChardev(vm, chr) < 0)
2165 2166 2167
        goto cleanup;
    teardowndevice = true;

2168 2169 2170 2171
    if (qemuSecuritySetChardevLabel(driver, vm, chr) < 0)
        goto cleanup;
    teardownlabel = true;

2172 2173 2174 2175
    if (qemuSetupChardevCgroup(vm, chr) < 0)
        goto cleanup;
    teardowncgroup = true;

2176
    if (qemuBuildChrDeviceStr(&devstr, vmdef, chr, priv->qemuCaps) < 0)
2177
        goto cleanup;
2178

2179
    if (!(charAlias = qemuAliasChardevFromDevAlias(chr->info.alias)))
2180 2181
        goto cleanup;

2182
    if (qemuDomainChrPreInsert(vmdef, chr) < 0)
2183 2184
        goto cleanup;

2185
    if (qemuDomainAddChardevTLSObjects(driver, vm, dev,
2186
                                       chr->info.alias, charAlias,
2187
                                       &tlsAlias, &secAlias) < 0)
2188
        goto audit;
2189

2190
    qemuDomainObjEnterMonitor(driver, vm);
2191

2192
    if (qemuMonitorAttachCharDev(priv->mon, charAlias, chr->source) < 0)
2193 2194
        goto exit_monitor;
    chardevAttached = true;
2195

2196 2197
    if (guestfwd) {
        if (qemuMonitorAddNetdev(priv->mon, devstr,
2198
                                 NULL, NULL, 0, NULL, NULL, 0, -1, NULL) < 0)
2199 2200 2201 2202 2203
            goto exit_monitor;
    } else {
        if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
            goto exit_monitor;
    }
2204

2205 2206
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto audit;
2207

2208
    qemuDomainChrInsertPreAlloced(vmdef, chr);
2209
    ret = 0;
2210 2211
 audit:
    virDomainAuditChardev(vm, NULL, chr, "attach", ret == 0);
2212
 cleanup:
2213 2214 2215 2216
    if (ret < 0) {
        if (virDomainObjIsActive(vm))
            qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
        if (need_release)
2217
            qemuDomainReleaseDeviceAddress(vm, &chr->info);
2218 2219
        if (teardowncgroup && qemuTeardownChardevCgroup(vm, chr) < 0)
            VIR_WARN("Unable to remove chr device cgroup ACL on hotplug fail");
2220 2221
        if (teardownlabel && qemuSecurityRestoreChardevLabel(driver, vm, chr) < 0)
            VIR_WARN("Unable to restore security label on char device");
2222
        if (teardowndevice && qemuDomainNamespaceTeardownChardev(vm, chr) < 0)
2223
            VIR_WARN("Unable to remove chr device from /dev");
2224
    }
2225
    VIR_FREE(tlsAlias);
2226 2227 2228
    VIR_FREE(charAlias);
    VIR_FREE(devstr);
    return ret;
2229

2230
 exit_monitor:
2231
    virErrorPreserveLast(&orig_err);
2232
    /* detach associated chardev on error */
2233 2234
    if (chardevAttached)
        qemuMonitorDetachCharDev(priv->mon, charAlias);
2235
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2236
    virErrorRestore(&orig_err);
2237

2238 2239
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2240
    goto audit;
2241 2242
}

2243 2244

int
2245
qemuDomainAttachRNGDevice(virQEMUDriverPtr driver,
2246 2247 2248 2249
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2250
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_RNG, { .rng = rng } };
2251
    virErrorPtr orig_err;
2252 2253 2254
    char *devstr = NULL;
    char *charAlias = NULL;
    char *objAlias = NULL;
2255
    char *tlsAlias = NULL;
2256
    const char *secAlias = NULL;
2257
    bool releaseaddr = false;
2258
    bool teardowncgroup = false;
2259
    bool teardowndevice = false;
2260
    bool chardevAdded = false;
2261 2262 2263
    virJSONValuePtr props = NULL;
    int ret = -1;

2264
    if (qemuAssignDeviceRNGAlias(vm->def, rng) < 0)
2265
        goto cleanup;
2266 2267 2268

    /* preallocate space for the device definition */
    if (VIR_REALLOC_N(vm->def->rngs, vm->def->nrngs + 1) < 0)
2269
        goto cleanup;
2270

2271 2272
    if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, "rng") < 0)
        return -1;
2273

2274
    if (qemuDomainNamespaceSetupRNG(vm, rng) < 0)
2275 2276 2277
        goto cleanup;
    teardowndevice = true;

2278 2279 2280 2281
    if (qemuSetupRNGCgroup(vm, rng) < 0)
        goto cleanup;
    teardowncgroup = true;

2282 2283 2284 2285
    /* build required metadata */
    if (!(devstr = qemuBuildRNGDevStr(vm->def, rng, priv->qemuCaps)))
        goto cleanup;

2286
    if (qemuBuildRNGBackendProps(rng, priv->qemuCaps, &props) < 0)
2287 2288
        goto cleanup;

2289
    if (!(charAlias = qemuAliasChardevFromDevAlias(rng->info.alias)))
2290 2291
        goto cleanup;

2292
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD) {
2293
        if (qemuDomainAddChardevTLSObjects(driver, vm,
2294 2295 2296
                                           rng->source.chardev,
                                           rng->info.alias, charAlias,
                                           &tlsAlias, &secAlias) < 0)
2297
            goto audit;
2298 2299
    }

2300
    qemuDomainObjEnterMonitor(driver, vm);
2301

2302 2303 2304
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
        qemuMonitorAttachCharDev(priv->mon, charAlias,
                                 rng->source.chardev) < 0)
2305 2306
        goto exit_monitor;
    chardevAdded = true;
2307

2308
    if (qemuMonitorAddObject(priv->mon, &props, &objAlias) < 0)
2309
        goto exit_monitor;
2310

2311
    if (qemuDomainAttachExtensionDevice(priv->mon, &rng->info) < 0)
2312
        goto exit_monitor;
2313

2314 2315 2316 2317 2318
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &rng->info));
        goto exit_monitor;
    }

2319
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
2320
        releaseaddr = false;
2321 2322 2323
        goto cleanup;
    }

2324
    VIR_APPEND_ELEMENT_INPLACE(vm->def->rngs, vm->def->nrngs, rng);
2325 2326 2327 2328 2329 2330

    ret = 0;

 audit:
    virDomainAuditRNG(vm, NULL, rng, "attach", ret == 0);
 cleanup:
2331
    virJSONValueFree(props);
2332 2333
    if (ret < 0) {
        if (releaseaddr)
2334
            qemuDomainReleaseDeviceAddress(vm, &rng->info);
2335 2336
        if (teardowncgroup && qemuTeardownRNGCgroup(vm, rng) < 0)
            VIR_WARN("Unable to remove RNG device cgroup ACL on hotplug fail");
2337
        if (teardowndevice && qemuDomainNamespaceTeardownRNG(vm, rng) < 0)
2338
            VIR_WARN("Unable to remove chr device from /dev");
2339 2340
    }

2341
    VIR_FREE(tlsAlias);
2342 2343 2344 2345 2346
    VIR_FREE(charAlias);
    VIR_FREE(objAlias);
    VIR_FREE(devstr);
    return ret;

2347
 exit_monitor:
2348
    virErrorPreserveLast(&orig_err);
2349
    if (objAlias)
2350 2351
        ignore_value(qemuMonitorDelObject(priv->mon, objAlias));
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD && chardevAdded)
2352
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
2353 2354
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        releaseaddr = false;
2355
    virErrorRestore(&orig_err);
2356

2357 2358
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2359 2360 2361 2362
    goto audit;
}


2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378
/**
 * qemuDomainAttachMemory:
 * @driver: qemu driver data
 * @vm: VM object
 * @mem: Definition of the memory device to be attached. @mem is always consumed
 *
 * Attaches memory device described by @mem to domain @vm.
 *
 * Returns 0 on success -1 on error.
 */
int
qemuDomainAttachMemory(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       virDomainMemoryDefPtr mem)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2379
    virErrorPtr orig_err;
2380
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
2381
    unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
2382
    unsigned long long newmem = oldmem + mem->size;
2383 2384
    char *devstr = NULL;
    char *objalias = NULL;
2385
    bool objAdded = false;
M
Michal Privoznik 已提交
2386
    bool teardownlabel = false;
2387
    bool teardowncgroup = false;
M
Michal Privoznik 已提交
2388
    bool teardowndevice = false;
2389
    virJSONValuePtr props = NULL;
2390
    virObjectEventPtr event;
2391 2392 2393
    int id;
    int ret = -1;

2394 2395 2396
    qemuDomainMemoryDeviceAlignSize(vm->def, mem);

    if (qemuDomainDefValidateMemoryHotplug(vm->def, priv->qemuCaps, mem) < 0)
2397 2398
        goto cleanup;

2399 2400 2401
    if (qemuDomainAssignMemoryDeviceSlot(vm->def, mem) < 0)
        goto cleanup;

2402 2403 2404
    /* in cases where we are using a VM with aliases generated according to the
     * index of the memory device we need to keep continue using that scheme */
    if (qemuAssignDeviceMemoryAlias(vm->def, mem, priv->memAliasOrderMismatch) < 0)
2405 2406 2407 2408 2409
        goto cleanup;

    if (virAsprintf(&objalias, "mem%s", mem->info.alias) < 0)
        goto cleanup;

2410
    if (!(devstr = qemuBuildMemoryDeviceStr(mem, priv)))
2411 2412
        goto cleanup;

2413
    if (qemuBuildMemoryBackendProps(&props, objalias, cfg,
2414
                                    priv, vm->def, mem, true) < 0)
2415 2416
        goto cleanup;

2417
    if (qemuProcessBuildDestroyMemoryPaths(driver, vm, mem, true) < 0)
2418 2419
        goto cleanup;

2420
    if (qemuDomainNamespaceSetupMemory(vm, mem) < 0)
M
Michal Privoznik 已提交
2421 2422 2423
        goto cleanup;
    teardowndevice = true;

2424 2425 2426 2427
    if (qemuSetupMemoryDevicesCgroup(vm, mem) < 0)
        goto cleanup;
    teardowncgroup = true;

M
Michal Privoznik 已提交
2428
    if (qemuSecuritySetMemoryLabel(driver, vm, mem) < 0)
2429
        goto cleanup;
M
Michal Privoznik 已提交
2430
    teardownlabel = true;
2431

M
Michal Privoznik 已提交
2432 2433 2434 2435
    if (virDomainMemoryInsert(vm->def, mem) < 0)
        goto cleanup;

    if (qemuDomainAdjustMaxMemLock(vm) < 0)
2436 2437
        goto removedef;

2438
    qemuDomainObjEnterMonitor(driver, vm);
2439
    if (qemuMonitorAddObject(priv->mon, &props, NULL) < 0)
2440
        goto exit_monitor;
2441
    objAdded = true;
2442

2443
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2444
        goto exit_monitor;
2445 2446 2447 2448

    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        /* we shouldn't touch mem now, as the def might be freed */
        mem = NULL;
2449
        goto audit;
2450 2451
    }

2452
    event = virDomainEventDeviceAddedNewFromObj(vm, objalias);
2453
    virObjectEventStateQueue(driver->domainEventState, event);
2454

2455 2456
    /* fix the balloon size */
    ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));
2457

2458 2459 2460 2461 2462 2463 2464 2465 2466
    /* mem is consumed by vm->def */
    mem = NULL;

    /* this step is best effort, removing the device would be so much trouble */
    ignore_value(qemuDomainUpdateMemoryDeviceInfo(driver, vm,
                                                  QEMU_ASYNC_JOB_NONE));

    ret = 0;

2467 2468
 audit:
    virDomainAuditMemory(vm, oldmem, newmem, "update", ret == 0);
2469
 cleanup:
M
Michal Privoznik 已提交
2470
    if (mem && ret < 0) {
2471 2472
        if (teardowncgroup && qemuTeardownMemoryDevicesCgroup(vm, mem) < 0)
            VIR_WARN("Unable to remove memory device cgroup ACL on hotplug fail");
M
Michal Privoznik 已提交
2473 2474
        if (teardownlabel && qemuSecurityRestoreMemoryLabel(driver, vm, mem) < 0)
            VIR_WARN("Unable to restore security label on memdev");
M
Michal Privoznik 已提交
2475
        if (teardowndevice &&
2476
            qemuDomainNamespaceTeardownMemory(vm, mem) <  0)
M
Michal Privoznik 已提交
2477
            VIR_WARN("Unable to remove memory device from /dev");
M
Michal Privoznik 已提交
2478 2479 2480
    }

    virJSONValueFree(props);
2481 2482 2483 2484 2485
    VIR_FREE(devstr);
    VIR_FREE(objalias);
    virDomainMemoryDefFree(mem);
    return ret;

2486
 exit_monitor:
2487
    virErrorPreserveLast(&orig_err);
2488 2489
    if (objAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, objalias));
2490 2491
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        mem = NULL;
2492 2493 2494 2495

    if (objAdded && mem)
        ignore_value(qemuProcessDestroyMemoryBackingPath(driver, vm, mem));

2496
    virErrorRestore(&orig_err);
2497
    if (!mem)
2498
        goto audit;
2499

2500
 removedef:
2501 2502 2503 2504 2505
    if ((id = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
        mem = virDomainMemoryRemove(vm->def, id);
    else
        mem = NULL;

2506
    /* reset the mlock limit */
2507
    virErrorPreserveLast(&orig_err);
2508
    ignore_value(qemuDomainAdjustMaxMemLock(vm));
2509
    virErrorRestore(&orig_err);
2510

2511
    goto audit;
2512 2513 2514
}


2515
static int
2516
qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
2517 2518
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
2519 2520 2521
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *devstr = NULL;
2522
    bool added = false;
2523
    bool teardowncgroup = false;
2524
    bool teardownlabel = false;
2525
    bool teardowndevice = false;
2526 2527
    int ret = -1;

2528 2529
    if (virDomainUSBAddressEnsure(priv->usbaddrs, hostdev->info) < 0)
        return -1;
2530

2531
    if (qemuHostdevPrepareUSBDevices(driver, vm->def->name, &hostdev, 1, 0) < 0)
2532 2533 2534
        goto cleanup;

    added = true;
2535

2536
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2537 2538 2539
        goto cleanup;
    teardowndevice = true;

2540
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
2541 2542 2543
        goto cleanup;
    teardowncgroup = true;

2544
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
2545 2546 2547
        goto cleanup;
    teardownlabel = true;

2548 2549 2550 2551
    if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
        goto cleanup;
    if (!(devstr = qemuBuildUSBHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
        goto cleanup;
2552

2553
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0)
2554
        goto cleanup;
2555

2556
    qemuDomainObjEnterMonitor(driver, vm);
2557
    ret = qemuMonitorAddDevice(priv->mon, devstr);
2558 2559 2560 2561
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        ret = -1;
        goto cleanup;
    }
2562
    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
2563
    if (ret < 0)
2564
        goto cleanup;
2565 2566 2567

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

2568
    ret = 0;
2569
 cleanup:
2570 2571 2572 2573
    if (ret < 0) {
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
        if (teardownlabel &&
2574
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2575
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2576
        if (teardowndevice &&
2577
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2578
            VIR_WARN("Unable to remove host device from /dev");
2579
        if (added)
2580
            qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
2581
        virDomainUSBAddressRelease(priv->usbaddrs, hostdev->info);
2582
    }
2583
    VIR_FREE(devstr);
2584
    return ret;
2585 2586
}

2587

2588
static int
2589
qemuDomainAttachHostSCSIDevice(virQEMUDriverPtr driver,
2590 2591 2592
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
2593
    size_t i;
2594 2595
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2596
    virErrorPtr orig_err;
2597 2598
    char *devstr = NULL;
    char *drvstr = NULL;
2599
    char *drivealias = NULL;
2600
    char *secobjAlias = NULL;
2601
    bool teardowncgroup = false;
2602
    bool teardownlabel = false;
2603
    bool teardowndevice = false;
2604
    bool driveAdded = false;
2605 2606
    virJSONValuePtr secobjProps = NULL;
    virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
2607
    qemuDomainSecretInfoPtr secinfo = NULL;
2608

2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619
    /* Let's make sure the disk has a controller defined and loaded before
     * trying to add it. The controller used by the disk must exist before a
     * qemu command line string is generated.
     *
     * Ensure that the given controller and all controllers with a smaller index
     * exist; there must not be any missing index in between.
     */
    for (i = 0; i <= hostdev->info->addr.drive.controller; i++) {
        if (!qemuDomainFindOrCreateSCSIDiskController(driver, vm, i))
            return -1;
    }
2620

2621
    if (qemuHostdevPrepareSCSIDevices(driver, vm->def->name, &hostdev, 1) < 0)
2622 2623
        return -1;

2624
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2625 2626 2627
        goto cleanup;
    teardowndevice = true;

2628
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
2629 2630 2631
        goto cleanup;
    teardowncgroup = true;

2632
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
2633 2634 2635
        goto cleanup;
    teardownlabel = true;

2636
    if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
2637 2638
        goto cleanup;

2639
    if (qemuDomainSecretHostdevPrepare(priv, hostdev) < 0)
2640 2641
        goto cleanup;

2642 2643 2644
    if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
        qemuDomainStorageSourcePrivatePtr srcPriv =
            QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(scsisrc->u.iscsi.src);
2645 2646
        if (srcPriv)
            secinfo = srcPriv->secinfo;
2647 2648
    }

2649 2650 2651 2652 2653 2654
    if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
        if (qemuBuildSecretInfoProps(secinfo, &secobjProps) < 0)
            goto cleanup;
    }

    if (!(drvstr = qemuBuildSCSIHostdevDrvStr(hostdev, priv->qemuCaps)))
2655 2656
        goto cleanup;

2657 2658 2659
    if (!(drivealias = qemuAliasFromHostdev(hostdev)))
        goto cleanup;

2660
    if (!(devstr = qemuBuildSCSIHostdevDevStr(vm->def, hostdev)))
2661 2662
        goto cleanup;

2663
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
2664 2665 2666 2667
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);

2668 2669 2670
    if (secobjProps &&
        qemuMonitorAddObject(priv->mon, &secobjProps, &secobjAlias) < 0)
        goto exit_monitor;
2671

2672
    if (qemuMonitorAddDrive(priv->mon, drvstr) < 0)
2673 2674
        goto exit_monitor;
    driveAdded = true;
2675 2676

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2677
        goto exit_monitor;
2678 2679

    if (qemuDomainObjExitMonitor(driver, vm) < 0)
2680
        goto cleanup;
2681 2682

    virDomainAuditHostdev(vm, hostdev, "attach", true);
2683 2684 2685 2686

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

    ret = 0;
2687

2688
 cleanup:
2689
    if (ret < 0) {
2690
        qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
2691 2692
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
2693
        if (teardownlabel &&
2694
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2695
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2696
        if (teardowndevice &&
2697
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2698
            VIR_WARN("Unable to remove host device from /dev");
2699
    }
2700 2701
    qemuDomainSecretHostdevDestroy(hostdev);
    virJSONValueFree(secobjProps);
2702
    VIR_FREE(secobjAlias);
2703
    VIR_FREE(drivealias);
2704 2705 2706
    VIR_FREE(drvstr);
    VIR_FREE(devstr);
    return ret;
2707

2708
 exit_monitor:
2709
    virErrorPreserveLast(&orig_err);
2710
    if (driveAdded && qemuMonitorDriveDel(priv->mon, drivealias) < 0) {
2711 2712 2713
        VIR_WARN("Unable to remove drive %s (%s) after failed "
                 "qemuMonitorAddDevice",
                 drvstr, devstr);
2714
    }
2715 2716
    if (secobjAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, secobjAlias));
2717
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2718
    virErrorRestore(&orig_err);
2719 2720 2721 2722

    virDomainAuditHostdev(vm, hostdev, "attach", false);

    goto cleanup;
2723 2724
}

2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
static int
qemuDomainAttachSCSIVHostDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainHostdevDefPtr hostdev)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                               { .hostdev = hostdev } };
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
    char *vhostfdName = NULL;
    int vhostfd = -1;
    char *devstr = NULL;
    bool teardowncgroup = false;
    bool teardownlabel = false;
2740
    bool teardowndevice = false;
2741 2742
    bool releaseaddr = false;

2743
    if (qemuHostdevPrepareSCSIVHostDevices(driver, vm->def->name, &hostdev, 1) < 0)
2744 2745
        return -1;

2746
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2747 2748 2749
        goto cleanup;
    teardowndevice = true;

2750 2751 2752 2753
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
        goto cleanup;
    teardowncgroup = true;

2754
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
2755 2756 2757 2758 2759 2760 2761 2762 2763 2764
        goto cleanup;
    teardownlabel = true;

    if (virSCSIVHostOpenVhostSCSI(&vhostfd) < 0)
        goto cleanup;

    if (virAsprintf(&vhostfdName, "vhostfd-%d", vhostfd) < 0)
        goto cleanup;

    if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
2765
        if (qemuDomainIsS390CCW(vm->def) &&
2766
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CCW))
2767 2768 2769 2770 2771
            hostdev->info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
    }

    if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
        hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
2772
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
2773 2774
            goto cleanup;
    } else if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
2775
        if (!(ccwaddrs = virDomainCCWAddressSetCreateFromDomain(vm->def)))
2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796
            goto cleanup;
        if (virDomainCCWAddressAssign(hostdev->info, ccwaddrs,
                                      !hostdev->info->addr.ccw.assigned) < 0)
            goto cleanup;
    }
    releaseaddr = true;

    if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
        goto cleanup;

    if (!(devstr = qemuBuildSCSIVHostHostdevDevStr(vm->def,
                                                   hostdev,
                                                   priv->qemuCaps,
                                                   vhostfdName)))
        goto cleanup;

    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);

2797 2798 2799 2800 2801 2802 2803 2804
    if ((ret = qemuDomainAttachExtensionDevice(priv->mon, hostdev->info)) < 0)
        goto exit_monitor;

    if ((ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr, vhostfd,
                                          vhostfdName)) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, hostdev->info));
        goto exit_monitor;
    }
2805

2806
 exit_monitor:
2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820
    if (qemuDomainObjExitMonitor(driver, vm) < 0 || ret < 0)
        goto audit;

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

 audit:
    virDomainAuditHostdev(vm, hostdev, "attach", (ret == 0));

 cleanup:
    if (ret < 0) {
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
        if (teardownlabel &&
2821
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2822
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2823
        if (teardowndevice &&
2824
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2825
            VIR_WARN("Unable to remove host device from /dev");
2826
        if (releaseaddr)
2827
            qemuDomainReleaseDeviceAddress(vm, hostdev->info);
2828 2829 2830 2831 2832 2833 2834 2835 2836 2837
    }

    virDomainCCWAddressSetFree(ccwaddrs);

    VIR_FORCE_CLOSE(vhostfd);
    VIR_FREE(vhostfdName);
    VIR_FREE(devstr);
    return ret;
}

2838

2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849
static int
qemuDomainAttachMediatedDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    int ret = -1;
    char *devstr = NULL;
    bool added = false;
    bool teardowncgroup = false;
    bool teardownlabel = false;
    bool teardowndevice = false;
2850
    bool teardownmemlock = false;
2851 2852 2853 2854
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                                { .hostdev = hostdev } };

2855 2856 2857 2858 2859 2860 2861 2862 2863
    switch (hostdev->source.subsys.u.mdev.model) {
    case VIR_MDEV_MODEL_TYPE_VFIO_PCI:
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
            return -1;
        break;
    case VIR_MDEV_MODEL_TYPE_VFIO_CCW:
    case VIR_MDEV_MODEL_TYPE_LAST:
        break;
    }
2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893

    if (qemuHostdevPrepareMediatedDevices(driver,
                                          vm->def->name,
                                          &hostdev,
                                          1) < 0)
        goto cleanup;
    added = true;

    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
        goto cleanup;
    teardowndevice = true;

    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
        goto cleanup;
    teardowncgroup = true;

    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
        goto cleanup;
    teardownlabel = true;

    if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
        goto cleanup;

    if (!(devstr = qemuBuildHostdevMediatedDevStr(vm->def, hostdev,
                                                  priv->qemuCaps)))
        goto cleanup;

    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

2894 2895 2896 2897
    if (qemuDomainAdjustMaxMemLockHostdev(vm, hostdev) < 0)
        goto cleanup;
    teardownmemlock = true;

2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorAddDevice(priv->mon, devstr);
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        ret = -1;
        goto cleanup;
    }

    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
    if (ret < 0)
        goto cleanup;

    VIR_APPEND_ELEMENT_INPLACE(vm->def->hostdevs, vm->def->nhostdevs, hostdev);
    ret = 0;
 cleanup:
    if (ret < 0) {
2913 2914
        if (teardownmemlock && qemuDomainAdjustMaxMemLock(vm) < 0)
            VIR_WARN("Unable to reset maximum locked memory on hotplug fail");
2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
        if (teardownlabel &&
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
        if (teardowndevice &&
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device from /dev");
        if (added)
            qemuHostdevReAttachMediatedDevices(driver,
                                               vm->def->name,
                                               &hostdev,
                                               1);
2928
        qemuDomainReleaseDeviceAddress(vm, hostdev->info);
2929 2930 2931 2932 2933 2934
    }
    VIR_FREE(devstr);
    return ret;
}


2935
int
2936
qemuDomainAttachHostDevice(virQEMUDriverPtr driver,
2937 2938
                           virDomainObjPtr vm,
                           virDomainHostdevDefPtr hostdev)
2939 2940
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
2941
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2942
                       _("hotplug is not supported for hostdev mode '%s'"),
2943
                       virDomainHostdevModeTypeToString(hostdev->mode));
2944 2945 2946 2947 2948
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
2949
        if (qemuDomainAttachHostPCIDevice(driver, vm,
2950
                                          hostdev) < 0)
2951 2952 2953 2954
            goto error;
        break;

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
2955
        if (qemuDomainAttachHostUSBDevice(driver, vm,
2956
                                          hostdev) < 0)
2957 2958 2959
            goto error;
        break;

2960
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
2961
        if (qemuDomainAttachHostSCSIDevice(driver, vm,
2962 2963 2964 2965
                                           hostdev) < 0)
            goto error;
        break;

2966 2967 2968 2969
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
        if (qemuDomainAttachSCSIVHostDevice(driver, vm, hostdev) < 0)
            goto error;
        break;
2970 2971 2972 2973
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
        if (qemuDomainAttachMediatedDevice(driver, vm, hostdev) < 0)
            goto error;
        break;
2974

2975
    default:
2976
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2977
                       _("hotplug is not supported for hostdev subsys type '%s'"),
2978
                       virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
2979 2980 2981 2982 2983
        goto error;
    }

    return 0;

2984
 error:
2985 2986 2987
    return -1;
}

2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002

int
qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainShmemDefPtr shmem)
{
    int ret = -1;
    char *shmstr = NULL;
    char *charAlias = NULL;
    char *memAlias = NULL;
    bool release_backing = false;
    bool release_address = true;
    virErrorPtr orig_err = NULL;
    virJSONValuePtr props = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
3003
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_SHMEM, { .shmem = shmem } };
3004 3005 3006 3007 3008 3009 3010 3011 3012 3013

    switch ((virDomainShmemModel)shmem->model) {
    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN:
    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL:
        break;

    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live attach of shmem model '%s' is not supported"),
                       virDomainShmemModelTypeToString(shmem->model));
M
Marc Hartmayer 已提交
3014
        ATTRIBUTE_FALLTHROUGH;
3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029
    case VIR_DOMAIN_SHMEM_MODEL_LAST:
        return -1;
    }

    if (qemuAssignDeviceShmemAlias(vm->def, shmem, -1) < 0)
        return -1;

    if (qemuDomainPrepareShmemChardev(shmem) < 0)
        return -1;

    if (VIR_REALLOC_N(vm->def->shmems, vm->def->nshmems + 1) < 0)
        return -1;

    if ((shmem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
         shmem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
3030
        (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0))
3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051
        return -1;

    if (!(shmstr = qemuBuildShmemDevStr(vm->def, shmem, priv->qemuCaps)))
        goto cleanup;

    if (shmem->server.enabled) {
        if (virAsprintf(&charAlias, "char%s", shmem->info.alias) < 0)
            goto cleanup;
    } else {
        if (!(props = qemuBuildShmemBackendMemProps(shmem)))
            goto cleanup;

    }

    qemuDomainObjEnterMonitor(driver, vm);

    if (shmem->server.enabled) {
        if (qemuMonitorAttachCharDev(priv->mon, charAlias,
                                     &shmem->server.chr) < 0)
            goto exit_monitor;
    } else {
3052
        if (qemuMonitorAddObject(priv->mon, &props, &memAlias) < 0)
3053 3054 3055 3056 3057
            goto exit_monitor;
    }

    release_backing = true;

3058 3059 3060 3061 3062
    if (qemuDomainAttachExtensionDevice(priv->mon, &shmem->info) < 0)
        goto exit_monitor;

    if (qemuMonitorAddDevice(priv->mon, shmstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &shmem->info));
3063
        goto exit_monitor;
3064
    }
3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082

    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        release_address = false;
        goto cleanup;
    }

    /* Doing a copy here just so the pointer doesn't get nullified
     * because we need it in the audit function */
    VIR_APPEND_ELEMENT_COPY_INPLACE(vm->def->shmems, vm->def->nshmems, shmem);

    ret = 0;
    release_address = false;

 audit:
    virDomainAuditShmem(vm, shmem, "attach", ret == 0);

 cleanup:
    if (release_address)
3083
        qemuDomainReleaseDeviceAddress(vm, &shmem->info);
3084 3085 3086 3087 3088 3089 3090 3091 3092

    virJSONValueFree(props);
    VIR_FREE(memAlias);
    VIR_FREE(charAlias);
    VIR_FREE(shmstr);

    return ret;

 exit_monitor:
3093
    virErrorPreserveLast(&orig_err);
3094 3095 3096 3097 3098 3099 3100
    if (release_backing) {
        if (shmem->server.enabled)
            ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
        else
            ignore_value(qemuMonitorDelObject(priv->mon, memAlias));
    }

3101 3102 3103
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        release_address = false;

3104
    virErrorRestore(&orig_err);
3105 3106 3107 3108 3109

    goto audit;
}


M
Michal Privoznik 已提交
3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143
int
qemuDomainAttachWatchdog(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         virDomainWatchdogDefPtr watchdog)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_WATCHDOG, { .watchdog = watchdog } };
    virDomainWatchdogAction actualAction = watchdog->action;
    const char *actionStr = NULL;
    char *watchdogstr = NULL;
    bool releaseAddress = false;
    int rv;

    if (vm->def->watchdog) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain already has a watchdog"));
        return -1;
    }

    if (qemuAssignDeviceWatchdogAlias(watchdog) < 0)
        return -1;

    if (watchdog->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) {
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
            goto cleanup;
        releaseAddress = true;
    } else {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("hotplug of watchdog of model %s is not supported"),
                       virDomainWatchdogModelTypeToString(watchdog->model));
        goto cleanup;
    }

3144 3145 3146
    if (!(watchdogstr = qemuBuildWatchdogDevStr(vm->def, watchdog, priv->qemuCaps)))
        goto cleanup;

M
Michal Privoznik 已提交
3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175
    /* QEMU doesn't have a 'dump' action; we tell qemu to 'pause', then
       libvirt listens for the watchdog event, and we perform the dump
       ourselves. so convert 'dump' to 'pause' for the qemu cli */
    if (actualAction == VIR_DOMAIN_WATCHDOG_ACTION_DUMP)
        actualAction = VIR_DOMAIN_WATCHDOG_ACTION_PAUSE;

    actionStr = virDomainWatchdogActionTypeToString(actualAction);

    qemuDomainObjEnterMonitor(driver, vm);

    rv = qemuMonitorSetWatchdogAction(priv->mon, actionStr);

    if (rv >= 0)
        rv = qemuMonitorAddDevice(priv->mon, watchdogstr);

    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseAddress = false;
        goto cleanup;
    }

    if (rv < 0)
        goto cleanup;

    releaseAddress = false;
    vm->def->watchdog = watchdog;
    ret = 0;

 cleanup:
    if (releaseAddress)
3176
        qemuDomainReleaseDeviceAddress(vm, &watchdog->info);
M
Michal Privoznik 已提交
3177 3178 3179 3180 3181
    VIR_FREE(watchdogstr);
    return ret;
}


J
Ján Tomko 已提交
3182 3183 3184 3185 3186 3187 3188 3189 3190 3191
int
qemuDomainAttachInputDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainInputDefPtr input)
{
    int ret = -1;
    char *devstr = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_INPUT,
                               { .input = input } };
3192
    virErrorPtr originalError = NULL;
J
Ján Tomko 已提交
3193
    bool releaseaddr = false;
3194 3195 3196
    bool teardowndevice = false;
    bool teardownlabel = false;
    bool teardowncgroup = false;
J
Ján Tomko 已提交
3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209

    if (input->bus != VIR_DOMAIN_INPUT_BUS_USB &&
        input->bus != VIR_DOMAIN_INPUT_BUS_VIRTIO) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("input device on bus '%s' cannot be hot plugged."),
                       virDomainInputBusTypeToString(input->bus));
        return -1;
    }

    if (input->bus == VIR_DOMAIN_INPUT_BUS_VIRTIO) {
        if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, "input") < 0)
            return -1;
    } else if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
3210 3211 3212
        if (virDomainUSBAddressEnsure(priv->usbaddrs, &input->info) < 0)
            goto cleanup;
        releaseaddr = true;
J
Ján Tomko 已提交
3213 3214 3215 3216 3217 3218 3219 3220
    }

    if (qemuAssignDeviceInputAlias(vm->def, input, -1) < 0)
        goto cleanup;

    if (qemuBuildInputDevStr(&devstr, vm->def, input, priv->qemuCaps) < 0)
        goto cleanup;

3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232
    if (qemuDomainNamespaceSetupInput(vm, input) < 0)
        goto cleanup;
    teardowndevice = true;

    if (qemuSetupInputCgroup(vm, input) < 0)
        goto cleanup;
    teardowncgroup = true;

    if (qemuSecuritySetInputLabel(vm, input) < 0)
        goto cleanup;
    teardownlabel = true;

J
Ján Tomko 已提交
3233 3234 3235 3236
    if (VIR_REALLOC_N(vm->def->inputs, vm->def->ninputs + 1) < 0)
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);
3237 3238

    if (qemuDomainAttachExtensionDevice(priv->mon, &input->info) < 0)
J
Ján Tomko 已提交
3239 3240
        goto exit_monitor;

3241 3242 3243 3244 3245
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &input->info));
        goto exit_monitor;
    }

J
Ján Tomko 已提交
3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseaddr = false;
        goto cleanup;
    }

    VIR_APPEND_ELEMENT_COPY_INPLACE(vm->def->inputs, vm->def->ninputs, input);

    ret = 0;

 audit:
    virDomainAuditInput(vm, input, "attach", ret == 0);

 cleanup:
3259 3260 3261 3262 3263 3264 3265 3266 3267
    if (ret < 0) {
        virErrorPreserveLast(&originalError);
        if (teardownlabel)
            qemuSecurityRestoreInputLabel(vm, input);
        if (teardowncgroup)
            qemuTeardownInputCgroup(vm, input);
        if (teardowndevice)
            qemuDomainNamespaceTeardownInput(vm, input);
        if (releaseaddr)
3268
            qemuDomainReleaseDeviceAddress(vm, &input->info);
3269 3270
        virErrorRestore(&originalError);
    }
J
Ján Tomko 已提交
3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283

    VIR_FREE(devstr);
    return ret;

 exit_monitor:
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseaddr = false;
        goto cleanup;
    }
    goto audit;
}


J
Ján Tomko 已提交
3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321
int
qemuDomainAttachVsockDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainVsockDefPtr vsock)
{
    qemuDomainVsockPrivatePtr vsockPriv = (qemuDomainVsockPrivatePtr)vsock->privateData;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_VSOCK,
                               { .vsock = vsock } };
    virErrorPtr originalError = NULL;
    const char *fdprefix = "vsockfd";
    bool releaseaddr = false;
    char *fdname = NULL;
    char *devstr = NULL;
    int ret = -1;

    if (vm->def->vsock) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("the domain already has a vsock device"));
        return -1;
    }

    if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, "vsock") < 0)
        return -1;

    if (qemuAssignDeviceVsockAlias(vsock) < 0)
        goto cleanup;

    if (qemuProcessOpenVhostVsock(vsock) < 0)
        goto cleanup;

    if (virAsprintf(&fdname, "%s%u", fdprefix, vsockPriv->vhostfd) < 0)
        goto cleanup;

    if (!(devstr = qemuBuildVsockDevStr(vm->def, vsock, priv->qemuCaps, fdprefix)))
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);
3322 3323 3324 3325 3326 3327

    if (qemuDomainAttachExtensionDevice(priv->mon, &vsock->info) < 0)
        goto exit_monitor;

    if (qemuMonitorAddDeviceWithFd(priv->mon, devstr, vsockPriv->vhostfd, fdname) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &vsock->info));
J
Ján Tomko 已提交
3328
        goto exit_monitor;
3329
    }
J
Ján Tomko 已提交
3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343

    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseaddr = false;
        goto cleanup;
    }

    VIR_STEAL_PTR(vm->def->vsock, vsock);

    ret = 0;

 cleanup:
    if (ret < 0) {
        virErrorPreserveLast(&originalError);
        if (releaseaddr)
3344
            qemuDomainReleaseDeviceAddress(vm, &vsock->info);
J
Ján Tomko 已提交
3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358
        virErrorRestore(&originalError);
    }

    VIR_FREE(devstr);
    VIR_FREE(fdname);
    return ret;

 exit_monitor:
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        releaseaddr = false;
    goto cleanup;
}


3359 3360 3361 3362 3363 3364
int
qemuDomainAttachLease(virQEMUDriverPtr driver,
                      virDomainObjPtr vm,
                      virDomainLeaseDefPtr lease)
{
    int ret = -1;
3365
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383

    if (virDomainLeaseInsertPreAlloc(vm->def) < 0)
        goto cleanup;

    if (virDomainLockLeaseAttach(driver->lockManager, cfg->uri,
                                 vm, lease) < 0) {
        virDomainLeaseInsertPreAlloced(vm->def, NULL);
        goto cleanup;
    }

    virDomainLeaseInsertPreAlloced(vm->def, lease);
    ret = 0;

 cleanup:
    return ret;
}


3384
static int
3385
qemuDomainChangeNetBridge(virDomainObjPtr vm,
3386 3387
                          virDomainNetDefPtr olddev,
                          virDomainNetDefPtr newdev)
3388 3389
{
    int ret = -1;
3390 3391
    const char *oldbridge = virDomainNetGetActualBridgeName(olddev);
    const char *newbridge = virDomainNetGetActualBridgeName(newdev);
3392

3393 3394
    if (!oldbridge || !newbridge) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
3395
        goto cleanup;
3396
    }
3397 3398 3399 3400 3401

    VIR_DEBUG("Change bridge for interface %s: %s -> %s",
              olddev->ifname, oldbridge, newbridge);

    if (virNetDevExists(newbridge) != 1) {
3402 3403
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("bridge %s doesn't exist"), newbridge);
3404
        goto cleanup;
3405 3406
    }

3407 3408 3409 3410 3411 3412 3413 3414 3415
    ret = virNetDevBridgeRemovePort(oldbridge, olddev->ifname);
    virDomainAuditNet(vm, olddev, NULL, "detach", ret == 0);
    if (ret < 0) {
        /* warn but continue - possibly the old network
         * had been destroyed and reconstructed, leaving the
         * tap device orphaned.
         */
        VIR_WARN("Unable to detach device %s from bridge %s",
                 olddev->ifname, oldbridge);
3416 3417 3418
    }

    ret = virNetDevBridgeAddPort(newbridge, olddev->ifname);
3419
    virDomainAuditNet(vm, NULL, newdev, "attach", ret == 0);
3420 3421 3422 3423
    if (ret < 0) {
        ret = virNetDevBridgeAddPort(oldbridge, olddev->ifname);
        virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
        if (ret < 0) {
3424
            virReportError(VIR_ERR_OPERATION_FAILED,
3425
                           _("unable to recover former state by adding port "
3426
                             "to bridge %s"), oldbridge);
3427
        }
3428
        goto cleanup;
3429
    }
3430 3431
    /* caller will replace entire olddev with newdev in domain nets list */
    ret = 0;
3432
 cleanup:
3433
    return ret;
3434 3435
}

3436
static int
3437
qemuDomainChangeNetFilter(virDomainObjPtr vm,
3438 3439 3440 3441 3442 3443 3444
                          virDomainNetDefPtr olddev,
                          virDomainNetDefPtr newdev)
{
    /* make sure this type of device supports filters. */
    switch (virDomainNetGetActualType(newdev)) {
    case VIR_DOMAIN_NET_TYPE_ETHERNET:
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
3445
    case VIR_DOMAIN_NET_TYPE_NETWORK:
3446
        break;
3447 3448 3449 3450 3451 3452 3453 3454 3455
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_DIRECT:
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
    case VIR_DOMAIN_NET_TYPE_UDP:
3456 3457 3458 3459
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("filters not supported on interfaces of type %s"),
                       virDomainNetTypeToString(virDomainNetGetActualType(newdev)));
        return -1;
3460 3461 3462 3463 3464
    case VIR_DOMAIN_NET_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainNetType,
                                virDomainNetGetActualType(newdev));
        return -1;
3465 3466 3467 3468
    }

    virDomainConfNWFilterTeardown(olddev);

3469
    if (newdev->filter &&
3470
        virDomainConfNWFilterInstantiate(vm->def->name,
3471
                                         vm->def->uuid, newdev, false) < 0) {
3472 3473 3474 3475 3476 3477
        virErrorPtr errobj;

        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to add new filter rules to '%s' "
                         "- attempting to restore old rules"),
                       olddev->ifname);
3478
        virErrorPreserveLast(&errobj);
3479
        ignore_value(virDomainConfNWFilterInstantiate(vm->def->name,
3480
                                                      vm->def->uuid, olddev, false));
3481
        virErrorRestore(&errobj);
3482 3483 3484 3485 3486
        return -1;
    }
    return 0;
}

3487
int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver,
3488 3489 3490 3491 3492 3493 3494 3495
                                 virDomainObjPtr vm,
                                 virDomainNetDefPtr dev,
                                 int linkstate)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if (!dev->info.alias) {
3496 3497
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("can't change link state: device alias not found"));
3498 3499 3500
        return -1;
    }

3501 3502
    VIR_DEBUG("dev: %s, state: %d", dev->info.alias, linkstate);

3503
    qemuDomainObjEnterMonitor(driver, vm);
3504 3505 3506 3507 3508 3509 3510 3511

    ret = qemuMonitorSetLink(priv->mon, dev->info.alias, linkstate);
    if (ret < 0)
        goto cleanup;

    /* modify the device configuration */
    dev->linkstate = linkstate;

3512
 cleanup:
3513 3514
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        return -1;
3515 3516 3517 3518

    return ret;
}

3519
int
3520
qemuDomainChangeNet(virQEMUDriverPtr driver,
3521 3522
                    virDomainObjPtr vm,
                    virDomainDeviceDefPtr dev)
3523
{
3524
    qemuDomainObjPrivatePtr priv = vm->privateData;
3525
    virDomainNetDefPtr newdev = dev->data.net;
3526
    virDomainNetDefPtr *devslot = NULL;
3527
    virDomainNetDefPtr olddev;
3528
    virDomainNetType oldType, newType;
3529 3530
    bool needReconnect = false;
    bool needBridgeChange = false;
3531
    bool needFilterChange = false;
3532 3533
    bool needLinkStateChange = false;
    bool needReplaceDevDef = false;
3534
    bool needBandwidthSet = false;
3535
    bool needCoalesceChange = false;
3536
    bool needVlanUpdate = false;
3537
    int ret = -1;
3538
    int changeidx = -1;
3539
    virConnectPtr conn = NULL;
3540
    virErrorPtr save_err = NULL;
3541 3542 3543 3544

    if ((changeidx = virDomainNetFindIdx(vm->def, newdev)) < 0)
        goto cleanup;
    devslot = &vm->def->nets[changeidx];
3545
    olddev = *devslot;
3546 3547 3548 3549

    oldType = virDomainNetGetActualType(olddev);
    if (oldType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* no changes are possible to a type='hostdev' interface */
3550
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572
                       _("cannot change config of '%s' network type"),
                       virDomainNetTypeToString(oldType));
        goto cleanup;
    }

    /* Check individual attributes for changes that can't be done to a
     * live netdev. These checks *mostly* go in order of the
     * declarations in virDomainNetDef in order to assure nothing is
     * omitted. (exceptiong where noted in comments - in particular,
     * some things require that a new "actual device" be allocated
     * from the network driver first, but we delay doing that until
     * after we've made as many other checks as possible)
     */

    /* type: this can change (with some restrictions), but the actual
     * type of the new device connection isn't known until after we
     * allocate the "actual" device.
     */

    if (virMacAddrCmp(&olddev->mac, &newdev->mac)) {
        char oldmac[VIR_MAC_STRING_BUFLEN], newmac[VIR_MAC_STRING_BUFLEN];

3573
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3574 3575 3576 3577 3578 3579 3580
                       _("cannot change network interface mac address "
                         "from %s to %s"),
                       virMacAddrFormat(&olddev->mac, oldmac),
                       virMacAddrFormat(&newdev->mac, newmac));
        goto cleanup;
    }

3581 3582
    if (STRNEQ_NULLABLE(virDomainNetGetModelString(olddev),
                        virDomainNetGetModelString(newdev))) {
3583
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3584
                       _("cannot modify network device model from %s to %s"),
3585 3586
                       NULLSTR(virDomainNetGetModelString(olddev)),
                       NULLSTR(virDomainNetGetModelString(newdev)));
3587
        goto cleanup;
3588 3589
    }

3590 3591 3592 3593 3594 3595 3596 3597
    if (olddev->model != newdev->model) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("cannot modify network device model from %s to %s"),
                       virDomainNetModelTypeToString(olddev->model),
                       virDomainNetModelTypeToString(newdev->model));
        goto cleanup;
    }

3598
    if (virDomainNetIsVirtioModel(olddev) &&
3599 3600 3601
        (olddev->driver.virtio.name != newdev->driver.virtio.name ||
         olddev->driver.virtio.txmode != newdev->driver.virtio.txmode ||
         olddev->driver.virtio.ioeventfd != newdev->driver.virtio.ioeventfd ||
3602
         olddev->driver.virtio.event_idx != newdev->driver.virtio.event_idx ||
3603
         olddev->driver.virtio.queues != newdev->driver.virtio.queues ||
3604 3605
         olddev->driver.virtio.rx_queue_size != newdev->driver.virtio.rx_queue_size ||
         olddev->driver.virtio.tx_queue_size != newdev->driver.virtio.tx_queue_size ||
3606 3607 3608 3609 3610 3611
         olddev->driver.virtio.host.csum != newdev->driver.virtio.host.csum ||
         olddev->driver.virtio.host.gso != newdev->driver.virtio.host.gso ||
         olddev->driver.virtio.host.tso4 != newdev->driver.virtio.host.tso4 ||
         olddev->driver.virtio.host.tso6 != newdev->driver.virtio.host.tso6 ||
         olddev->driver.virtio.host.ecn != newdev->driver.virtio.host.ecn ||
         olddev->driver.virtio.host.ufo != newdev->driver.virtio.host.ufo ||
J
Ján Tomko 已提交
3612
         olddev->driver.virtio.host.mrg_rxbuf != newdev->driver.virtio.host.mrg_rxbuf ||
3613 3614 3615 3616 3617
         olddev->driver.virtio.guest.csum != newdev->driver.virtio.guest.csum ||
         olddev->driver.virtio.guest.tso4 != newdev->driver.virtio.guest.tso4 ||
         olddev->driver.virtio.guest.tso6 != newdev->driver.virtio.guest.tso6 ||
         olddev->driver.virtio.guest.ecn != newdev->driver.virtio.guest.ecn ||
         olddev->driver.virtio.guest.ufo != newdev->driver.virtio.guest.ufo)) {
3618
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3619 3620 3621 3622 3623 3624 3625 3626 3627 3628
                       _("cannot modify virtio network device driver attributes"));
        goto cleanup;
    }

    /* data: this union will be examined later, after allocating new actualdev */
    /* virtPortProfile: will be examined later, after allocating new actualdev */

    if (olddev->tune.sndbuf_specified != newdev->tune.sndbuf_specified ||
        olddev->tune.sndbuf != newdev->tune.sndbuf) {
        needReconnect = true;
3629 3630
    }

3631
    if (STRNEQ_NULLABLE(olddev->script, newdev->script)) {
3632
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3633 3634
                       _("cannot modify network device script attribute"));
        goto cleanup;
3635 3636
    }

3637
    /* ifname: check if it's set in newdev. If not, retain the autogenerated one */
3638
    if (!newdev->ifname && VIR_STRDUP(newdev->ifname, olddev->ifname) < 0)
3639 3640
        goto cleanup;
    if (STRNEQ_NULLABLE(olddev->ifname, newdev->ifname)) {
3641
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3642 3643 3644
                       _("cannot modify network device tap name"));
        goto cleanup;
    }
3645

3646 3647
    /* info: Nothing is allowed to change. First fill the missing newdev->info
     * from olddev and then check for changes.
3648
     */
3649 3650 3651 3652 3653 3654 3655 3656 3657 3658
    /* if pci addr is missing or is invalid we overwrite it from olddev */
    if (newdev->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
        !virDomainDeviceAddressIsValid(&newdev->info,
                                       newdev->info.type)) {
        newdev->info.type = olddev->info.type;
        newdev->info.addr = olddev->info.addr;
    }
    if (olddev->info.type != newdev->info.type) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot modify network device address type"));
3659
    }
3660
    if (!virPCIDeviceAddressEqual(&olddev->info.addr.pci,
3661
                                  &newdev->info.addr.pci)) {
3662
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3663 3664 3665 3666
                       _("cannot modify network device guest PCI address"));
        goto cleanup;
    }
    /* grab alias from olddev if not set in newdev */
3667 3668
    if (!newdev->info.alias &&
        VIR_STRDUP(newdev->info.alias, olddev->info.alias) < 0)
3669
        goto cleanup;
3670 3671 3672

    /* device alias is checked already in virDomainDefCompatibleDevice */

3673 3674
    if (newdev->info.rombar == VIR_TRISTATE_BOOL_ABSENT)
        newdev->info.rombar = olddev->info.rombar;
3675
    if (olddev->info.rombar != newdev->info.rombar) {
3676
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3677 3678 3679
                       _("cannot modify network device rom bar setting"));
        goto cleanup;
    }
3680 3681 3682 3683

    if (!newdev->info.romfile &&
        VIR_STRDUP(newdev->info.romfile, olddev->info.romfile) < 0)
        goto cleanup;
3684
    if (STRNEQ_NULLABLE(olddev->info.romfile, newdev->info.romfile)) {
3685
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3686 3687 3688
                       _("cannot modify network rom file"));
        goto cleanup;
    }
3689 3690 3691

    if (newdev->info.bootIndex == 0)
        newdev->info.bootIndex = olddev->info.bootIndex;
3692
    if (olddev->info.bootIndex != newdev->info.bootIndex) {
3693
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3694 3695 3696
                       _("cannot modify network device boot index setting"));
        goto cleanup;
    }
3697 3698 3699

    if (newdev->info.romenabled == VIR_TRISTATE_BOOL_ABSENT)
        newdev->info.romenabled = olddev->info.romenabled;
3700 3701 3702 3703 3704
    if (olddev->info.romenabled != newdev->info.romenabled) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot modify network device rom enabled setting"));
        goto cleanup;
    }
3705
    /* (end of device info checks) */
3706

3707 3708 3709 3710
    if (STRNEQ_NULLABLE(olddev->filter, newdev->filter) ||
        !virNWFilterHashTableEqual(olddev->filterparams, newdev->filterparams)) {
        needFilterChange = true;
    }
3711

3712 3713 3714 3715
    /* bandwidth can be modified, and will be checked later */
    /* vlan can be modified, and will be checked later */
    /* linkstate can be modified */

3716 3717 3718 3719 3720 3721
    if (olddev->mtu != newdev->mtu) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot modify MTU"));
        goto cleanup;
    }

3722 3723 3724
    /* allocate new actual device to compare to old - we will need to
     * free it if we fail for any reason
     */
3725 3726 3727 3728 3729
    if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        if (!(conn = virGetConnectNetwork()))
            goto cleanup;
        if (virDomainNetAllocateActualDevice(conn, vm->def, newdev) < 0)
            goto cleanup;
3730 3731
    }

3732 3733 3734 3735
    /* final validation now that we have full info on the type */
    if (qemuDomainValidateActualNetDef(newdev, priv->qemuCaps) < 0)
        goto cleanup;

3736 3737 3738 3739
    newType = virDomainNetGetActualType(newdev);

    if (newType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* can't turn it into a type='hostdev' interface */
3740
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3741 3742 3743 3744 3745 3746
                       _("cannot change network interface type to '%s'"),
                       virDomainNetTypeToString(newType));
        goto cleanup;
    }

    if (olddev->type == newdev->type && oldType == newType) {
3747

3748 3749 3750 3751 3752 3753
        /* if type hasn't changed, check the relevant fields for the type */
        switch (newdev->type) {
        case VIR_DOMAIN_NET_TYPE_USER:
            break;

        case VIR_DOMAIN_NET_TYPE_ETHERNET:
3754
            break;
3755

3756 3757 3758
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
3759
        case VIR_DOMAIN_NET_TYPE_UDP:
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
            if (STRNEQ_NULLABLE(olddev->data.socket.address,
                                newdev->data.socket.address) ||
                olddev->data.socket.port != newdev->data.socket.port) {
                needReconnect = true;
            }
            break;

        case VIR_DOMAIN_NET_TYPE_NETWORK:
            if (STRNEQ(olddev->data.network.name, newdev->data.network.name)) {
                if (virDomainNetGetActualVirtPortProfile(newdev))
                    needReconnect = true;
                else
                    needBridgeChange = true;
            }
            /* other things handled in common code directly below this switch */
            break;

        case VIR_DOMAIN_NET_TYPE_BRIDGE:
            /* all handled in bridge name checked in common code below */
            break;

        case VIR_DOMAIN_NET_TYPE_INTERNAL:
            if (STRNEQ_NULLABLE(olddev->data.internal.name,
                                newdev->data.internal.name)) {
                needReconnect = true;
            }
            break;

        case VIR_DOMAIN_NET_TYPE_DIRECT:
            /* all handled in common code directly below this switch */
            break;

3792 3793
        case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
3794
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3795 3796
                           _("unable to change config on '%s' network type"),
                           virDomainNetTypeToString(newdev->type));
3797 3798 3799 3800 3801
            goto cleanup;
        case VIR_DOMAIN_NET_TYPE_LAST:
        default:
            virReportEnumRangeError(virDomainNetType, newdev->type);
            goto cleanup;
3802
        }
3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833
    } else {
        /* interface type has changed. There are a few special cases
         * where this can only require a minor (or even no) change,
         * but in most cases we need to do a full reconnection.
         *
         * If we switch (in either direction) between type='bridge'
         * and type='network' (for a traditional managed virtual
         * network that uses a host bridge, i.e. forward
         * mode='route|nat'), we just need to change the bridge.
         */
        if ((oldType == VIR_DOMAIN_NET_TYPE_NETWORK &&
             newType == VIR_DOMAIN_NET_TYPE_BRIDGE) ||
            (oldType == VIR_DOMAIN_NET_TYPE_BRIDGE &&
             newType == VIR_DOMAIN_NET_TYPE_NETWORK)) {

            needBridgeChange = true;

        } else if (oldType == VIR_DOMAIN_NET_TYPE_DIRECT &&
                   newType == VIR_DOMAIN_NET_TYPE_DIRECT) {

            /* this is the case of switching from type='direct' to
             * type='network' for a network that itself uses direct
             * (macvtap) devices. If the physical device and mode are
             * the same, this doesn't require any actual setup
             * change. If the physical device or mode *does* change,
             * that will be caught in the common section below */

        } else {

            /* for all other combinations, we'll need a full reconnect */
            needReconnect = true;
3834 3835

        }
3836
    }
3837

3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848
    /* now several things that are in multiple (but not all)
     * different types, and can be safely compared even for those
     * cases where they don't apply to a particular type.
     */
    if (STRNEQ_NULLABLE(virDomainNetGetActualBridgeName(olddev),
                        virDomainNetGetActualBridgeName(newdev))) {
        if (virDomainNetGetActualVirtPortProfile(newdev))
            needReconnect = true;
        else
            needBridgeChange = true;
    }
3849

3850 3851
    if (STRNEQ_NULLABLE(virDomainNetGetActualDirectDev(olddev),
                        virDomainNetGetActualDirectDev(newdev)) ||
3852
        virDomainNetGetActualDirectMode(olddev) != virDomainNetGetActualDirectMode(newdev) ||
3853
        !virNetDevVPortProfileEqual(virDomainNetGetActualVirtPortProfile(olddev),
3854
                                    virDomainNetGetActualVirtPortProfile(newdev))) {
3855
        needReconnect = true;
3856 3857
    }

3858 3859 3860 3861 3862
    if (!virNetDevVlanEqual(virDomainNetGetActualVlan(olddev),
                             virDomainNetGetActualVlan(newdev))) {
        needVlanUpdate = true;
    }

3863 3864 3865
    if (olddev->linkstate != newdev->linkstate)
        needLinkStateChange = true;

3866 3867 3868 3869
    if (!virNetDevBandwidthEqual(virDomainNetGetActualBandwidth(olddev),
                                 virDomainNetGetActualBandwidth(newdev)))
        needBandwidthSet = true;

3870 3871
    if (!!olddev->coalesce != !!newdev->coalesce ||
        (olddev->coalesce && newdev->coalesce &&
3872 3873
         memcmp(olddev->coalesce, newdev->coalesce,
                sizeof(*olddev->coalesce))))
3874 3875
        needCoalesceChange = true;

3876 3877 3878
    /* FINALLY - actually perform the required actions */

    if (needReconnect) {
3879
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3880 3881 3882
                       _("unable to change config on '%s' network type"),
                       virDomainNetTypeToString(newdev->type));
        goto cleanup;
3883 3884
    }

3885
    if (needBandwidthSet) {
3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898
        virNetDevBandwidthPtr newb = virDomainNetGetActualBandwidth(newdev);

        if (newb) {
            if (virNetDevBandwidthSet(newdev->ifname, newb, false,
                                      !virDomainNetTypeSharesHostView(newdev)) < 0)
                goto cleanup;
        } else {
            /*
             * virNetDevBandwidthSet() doesn't clear any existing
             * setting unless something new is being set.
             */
            virNetDevBandwidthClear(newdev->ifname);
        }
3899 3900 3901
        needReplaceDevDef = true;
    }

3902
    if (needBridgeChange) {
3903
        if (qemuDomainChangeNetBridge(vm, olddev, newdev) < 0)
3904 3905 3906
            goto cleanup;
        /* we successfully switched to the new bridge, and we've
         * determined that the rest of newdev is equivalent to olddev,
3907 3908 3909 3910 3911
         * so move newdev into place */
        needReplaceDevDef = true;
    }

    if (needFilterChange) {
3912
        if (qemuDomainChangeNetFilter(vm, olddev, newdev) < 0)
3913 3914 3915 3916
            goto cleanup;
        /* we successfully switched to the new filter, and we've
         * determined that the rest of newdev is equivalent to olddev,
         * so move newdev into place */
3917
        needReplaceDevDef = true;
3918 3919
    }

3920 3921 3922 3923 3924 3925
    if (needCoalesceChange) {
        if (virNetDevSetCoalesce(newdev->ifname, newdev->coalesce, true) < 0)
            goto cleanup;
        needReplaceDevDef = true;
    }

3926 3927 3928
    if (needLinkStateChange &&
        qemuDomainChangeNetLinkState(driver, vm, olddev, newdev->linkstate) < 0) {
        goto cleanup;
3929 3930
    }

3931 3932 3933 3934 3935 3936
    if (needVlanUpdate) {
        if (virNetDevOpenvswitchUpdateVlan(newdev->ifname, &newdev->vlan) < 0)
            goto cleanup;
        needReplaceDevDef = true;
    }

3937 3938 3939 3940
    if (needReplaceDevDef) {
        /* the changes above warrant replacing olddev with newdev in
         * the domain's nets list.
         */
3941 3942 3943

        /* this function doesn't work with HOSTDEV networks yet, thus
         * no need to change the pointer in the hostdev structure */
3944 3945 3946 3947 3948 3949
        if (olddev->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            if (conn || (conn = virGetConnectNetwork()))
                virDomainNetReleaseActualDevice(conn, vm->def, olddev);
            else
                VIR_WARN("Unable to release network device '%s'", NULLSTR(olddev->ifname));
        }
3950 3951 3952 3953 3954 3955 3956 3957
        virDomainNetDefFree(olddev);
        /* move newdev into the nets list, and NULL it out from the
         * virDomainDeviceDef that we were given so that the caller
         * won't delete it on return.
         */
        *devslot = newdev;
        newdev = dev->data.net = NULL;
        dev->type = VIR_DOMAIN_DEVICE_NONE;
3958 3959
    }

3960
    ret = 0;
3961
 cleanup:
3962
    virErrorPreserveLast(&save_err);
3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980
    /* When we get here, we will be in one of these two states:
     *
     * 1) newdev has been moved into the domain's list of nets and
     *    newdev set to NULL, and dev->data.net will be NULL (and
     *    dev->type is NONE). olddev will have been completely
     *    released and freed. (aka success) In this case no extra
     *    cleanup is needed.
     *
     * 2) newdev has *not* been moved into the domain's list of nets,
     *    and dev->data.net == newdev (and dev->type == NET). In this *
     *    case, we need to at least release the "actual device" from *
     *    newdev (the caller will free dev->data.net a.k.a. newdev, and
     *    the original olddev is still in used)
     *
     * Note that case (2) isn't necessarily a failure. It may just be
     * that the changes were minor enough that we didn't need to
     * replace the entire device object.
     */
3981 3982 3983
    if (newdev && newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK && conn)
        virDomainNetReleaseActualDevice(conn, vm->def, newdev);
    virObjectUnref(conn);
3984
    virErrorRestore(&save_err);
3985

3986 3987 3988
    return ret;
}

3989 3990 3991
static virDomainGraphicsDefPtr
qemuDomainFindGraphics(virDomainObjPtr vm,
                       virDomainGraphicsDefPtr dev)
3992
{
3993
    size_t i;
3994

3995
    for (i = 0; i < vm->def->ngraphics; i++) {
3996 3997 3998 3999 4000 4001 4002
        if (vm->def->graphics[i]->type == dev->type)
            return vm->def->graphics[i];
    }

    return NULL;
}

4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016
int
qemuDomainFindGraphicsIndex(virDomainDefPtr def,
                            virDomainGraphicsDefPtr dev)
{
    size_t i;

    for (i = 0; i < def->ngraphics; i++) {
        if (def->graphics[i]->type == dev->type)
            return i;
    }

    return -1;
}

4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071

int
qemuDomainChangeGraphicsPasswords(virQEMUDriverPtr driver,
                                  virDomainObjPtr vm,
                                  int type,
                                  virDomainGraphicsAuthDefPtr auth,
                                  const char *defaultPasswd,
                                  int asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    time_t now = time(NULL);
    const char *expire;
    char *validTo = NULL;
    const char *connected = NULL;
    const char *password;
    int ret = -1;

    if (!auth->passwd && !defaultPasswd) {
        ret = 0;
        goto cleanup;
    }
    password = auth->passwd ? auth->passwd : defaultPasswd;

    if (auth->connected)
        connected = virDomainGraphicsAuthConnectedTypeToString(auth->connected);

    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;
    ret = qemuMonitorSetPassword(priv->mon, type, password, connected);

    if (ret != 0)
        goto end_job;

    if (password[0] == '\0' ||
        (auth->expires && auth->validTo <= now)) {
        expire = "now";
    } else if (auth->expires) {
        if (virAsprintf(&validTo, "%lu", (unsigned long)auth->validTo) < 0)
            goto end_job;
        expire = validTo;
    } else {
        expire = "never";
    }

    ret = qemuMonitorExpirePassword(priv->mon, type, expire);

 end_job:
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;
 cleanup:
    VIR_FREE(validTo);
    return ret;
}


4072
int
4073
qemuDomainChangeGraphics(virQEMUDriverPtr driver,
4074 4075 4076 4077
                         virDomainObjPtr vm,
                         virDomainGraphicsDefPtr dev)
{
    virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
4078
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
4079
    const char *type = virDomainGraphicsTypeToString(dev->type);
4080
    size_t i;
4081
    int ret = -1;
4082 4083

    if (!olddev) {
4084
        virReportError(VIR_ERR_DEVICE_MISSING,
4085 4086
                       _("cannot find existing graphics device to modify of "
                         "type '%s'"), type);
4087
        goto cleanup;
4088 4089
    }

4090
    if (dev->nListens != olddev->nListens) {
4091 4092 4093
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("cannot change the number of listen addresses "
                         "on '%s' graphics"), type);
4094 4095 4096 4097
        goto cleanup;
    }

    for (i = 0; i < dev->nListens; i++) {
J
Jim Fehlig 已提交
4098
        virDomainGraphicsListenDefPtr newlisten = &dev->listens[i];
4099 4100
        virDomainGraphicsListenDefPtr oldlisten = &olddev->listens[i];

J
Jim Fehlig 已提交
4101
        if (newlisten->type != oldlisten->type) {
4102 4103 4104
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                           _("cannot change the type of listen address "
                             "on '%s' graphics"), type);
4105 4106 4107
            goto cleanup;
        }

4108
        switch (newlisten->type) {
4109
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
J
Jim Fehlig 已提交
4110
            if (STRNEQ_NULLABLE(newlisten->address, oldlisten->address)) {
4111 4112 4113
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen address setting "
                                 "on '%s' graphics"), type);
4114 4115
                goto cleanup;
            }
4116

4117 4118 4119
            break;

        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
J
Jim Fehlig 已提交
4120
            if (STRNEQ_NULLABLE(newlisten->network, oldlisten->network)) {
4121 4122 4123
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen address setting "
                                 "on '%s' graphics"), type);
4124 4125
                goto cleanup;
            }
4126

4127 4128
            break;

4129 4130 4131 4132 4133 4134 4135 4136 4137
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET:
            if (STRNEQ_NULLABLE(newlisten->socket, oldlisten->socket)) {
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen socket setting "
                                 "on '%s' graphics"), type);
                goto cleanup;
            }
            break;

4138 4139 4140 4141 4142 4143
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE:
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST:
            /* nada */
            break;
        }
    }
4144

4145 4146
    switch (dev->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
4147 4148 4149
        if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
            (!dev->data.vnc.autoport &&
             (olddev->data.vnc.port != dev->data.vnc.port))) {
4150
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4151
                           _("cannot change port settings on vnc graphics"));
4152
            goto cleanup;
4153 4154
        }
        if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
4155
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4156
                           _("cannot change keymap setting on vnc graphics"));
4157
            goto cleanup;
4158 4159
        }

4160 4161 4162
        /* If a password lifetime was, or is set, or action if connected has
         * changed, then we must always run, even if new password matches
         * old password */
4163 4164
        if (olddev->data.vnc.auth.expires ||
            dev->data.vnc.auth.expires ||
4165
            olddev->data.vnc.auth.connected != dev->data.vnc.auth.connected ||
E
Eric Blake 已提交
4166 4167 4168
            STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd,
                            dev->data.vnc.auth.passwd)) {
            VIR_DEBUG("Updating password on VNC server %p %p",
4169
                      dev->data.vnc.auth.passwd, cfg->vncPassword);
E
Eric Blake 已提交
4170 4171 4172
            ret = qemuDomainChangeGraphicsPasswords(driver, vm,
                                                    VIR_DOMAIN_GRAPHICS_TYPE_VNC,
                                                    &dev->data.vnc.auth,
4173 4174
                                                    cfg->vncPassword,
                                                    QEMU_ASYNC_JOB_NONE);
4175
            if (ret < 0)
4176
                goto cleanup;
4177 4178 4179 4180 4181

            /* Steal the new dev's  char * reference */
            VIR_FREE(olddev->data.vnc.auth.passwd);
            olddev->data.vnc.auth.passwd = dev->data.vnc.auth.passwd;
            dev->data.vnc.auth.passwd = NULL;
4182 4183
            olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo;
            olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires;
4184
            olddev->data.vnc.auth.connected = dev->data.vnc.auth.connected;
4185 4186 4187 4188 4189
        } else {
            ret = 0;
        }
        break;

4190
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
4191 4192 4193 4194 4195
        if ((olddev->data.spice.autoport != dev->data.spice.autoport) ||
            (!dev->data.spice.autoport &&
             (olddev->data.spice.port != dev->data.spice.port)) ||
            (!dev->data.spice.autoport &&
             (olddev->data.spice.tlsPort != dev->data.spice.tlsPort))) {
4196
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4197
                           _("cannot change port settings on spice graphics"));
4198
            goto cleanup;
4199
        }
E
Eric Blake 已提交
4200 4201
        if (STRNEQ_NULLABLE(olddev->data.spice.keymap,
                            dev->data.spice.keymap)) {
4202
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4203
                            _("cannot change keymap setting on spice graphics"));
4204
            goto cleanup;
4205 4206
        }

4207 4208 4209 4210 4211
        /* We must reset the password if it has changed but also if:
         * - password lifetime is or was set
         * - the requested action has changed
         * - the action is "disconnect"
         */
4212 4213
        if (olddev->data.spice.auth.expires ||
            dev->data.spice.auth.expires ||
4214
            olddev->data.spice.auth.connected != dev->data.spice.auth.connected ||
4215 4216
            dev->data.spice.auth.connected ==
            VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DISCONNECT ||
E
Eric Blake 已提交
4217 4218 4219
            STRNEQ_NULLABLE(olddev->data.spice.auth.passwd,
                            dev->data.spice.auth.passwd)) {
            VIR_DEBUG("Updating password on SPICE server %p %p",
4220
                      dev->data.spice.auth.passwd, cfg->spicePassword);
E
Eric Blake 已提交
4221 4222 4223
            ret = qemuDomainChangeGraphicsPasswords(driver, vm,
                                                    VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
                                                    &dev->data.spice.auth,
4224 4225
                                                    cfg->spicePassword,
                                                    QEMU_ASYNC_JOB_NONE);
E
Eric Blake 已提交
4226

4227
            if (ret < 0)
4228
                goto cleanup;
4229

E
Eric Blake 已提交
4230
            /* Steal the new dev's char * reference */
4231 4232 4233 4234 4235
            VIR_FREE(olddev->data.spice.auth.passwd);
            olddev->data.spice.auth.passwd = dev->data.spice.auth.passwd;
            dev->data.spice.auth.passwd = NULL;
            olddev->data.spice.auth.validTo = dev->data.spice.auth.validTo;
            olddev->data.spice.auth.expires = dev->data.spice.auth.expires;
4236
            olddev->data.spice.auth.connected = dev->data.spice.auth.connected;
4237
        } else {
4238
            VIR_DEBUG("Not updating since password didn't change");
4239 4240
            ret = 0;
        }
E
Eric Blake 已提交
4241
        break;
4242

4243 4244 4245
    case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
    case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
4246
    case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
4247
        virReportError(VIR_ERR_INTERNAL_ERROR,
4248
                       _("unable to change config on '%s' graphics type"), type);
4249
        break;
4250 4251 4252 4253
    case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainGraphicsType, dev->type);
        break;
4254 4255
    }

4256
 cleanup:
4257 4258 4259 4260
    return ret;
}


4261
static int qemuComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
4262
                                virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
4263
                                virDomainDeviceInfoPtr info1,
4264 4265
                                void *opaque)
{
4266
    virDomainDeviceInfoPtr info2 = opaque;
4267

4268 4269
    if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
        info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
4270 4271
        return 0;

4272 4273 4274
    if (info1->addr.pci.domain == info2->addr.pci.domain &&
        info1->addr.pci.bus == info2->addr.pci.bus &&
        info1->addr.pci.slot == info2->addr.pci.slot &&
4275
        info1->addr.pci.function != info2->addr.pci.function)
4276 4277 4278 4279 4280
        return -1;
    return 0;
}

static bool qemuIsMultiFunctionDevice(virDomainDefPtr def,
4281
                                      virDomainDeviceInfoPtr info)
4282
{
4283
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
4284 4285
        return false;

4286
    if (virDomainDeviceInfoIterate(def, qemuComparePCIDevice, info) < 0)
4287 4288 4289 4290
        return true;
    return false;
}

4291

4292
static int
4293 4294 4295 4296
qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainDiskDefPtr disk)
{
4297
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
4298
    VIR_AUTOPTR(qemuBlockStorageSourceChainData) diskBackend = NULL;
4299 4300
    virDomainDeviceDef dev;
    size_t i;
4301
    qemuDomainObjPrivatePtr priv = vm->privateData;
4302 4303
    VIR_AUTOFREE(char *) corAlias = NULL;
    bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
4304
    int ret = -1;
4305 4306 4307 4308

    VIR_DEBUG("Removing disk %s from domain %p %s",
              disk->info.alias, vm, vm->def->name);

4309

4310 4311 4312
    if (blockdev) {
        if (VIR_STRDUP(corAlias, diskPriv->nodeCopyOnRead) < 0)
            goto cleanup;
4313

4314 4315 4316 4317 4318 4319 4320 4321 4322
        if (diskPriv->blockjob) {
            /* the block job keeps reference to the disk chain */
            diskPriv->blockjob->disk = NULL;
            virObjectUnref(diskPriv->blockjob);
            diskPriv->blockjob = NULL;
        } else {
            if (!(diskBackend = qemuBlockStorageSourceChainDetachPrepareBlockdev(disk->src)))
                goto cleanup;
        }
4323 4324 4325 4326 4327 4328 4329 4330
    } else {
        char *driveAlias;

        if (!(driveAlias = qemuAliasDiskDriveFromDisk(disk)))
            goto cleanup;

        if (!(diskBackend = qemuBlockStorageSourceChainDetachPrepareDrive(disk->src, driveAlias)))
            goto cleanup;
4331 4332
    }

4333 4334 4335 4336 4337 4338 4339
    for (i = 0; i < vm->def->ndisks; i++) {
        if (vm->def->disks[i] == disk) {
            virDomainDiskRemove(vm->def, i);
            break;
        }
    }

4340
    qemuDomainObjEnterMonitor(driver, vm);
4341

4342 4343 4344
    if (corAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, corAlias));

4345 4346
    if (diskBackend)
        qemuBlockStorageSourceChainDetach(priv->mon, diskBackend);
4347

4348
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
4349
        goto cleanup;
4350

4351
    virDomainAuditDisk(vm, disk->src, NULL, "detach", true);
4352

4353
    qemuDomainReleaseDeviceAddress(vm, &disk->info);
4354

4355
    /* tear down disk security access */
4356 4357
    if (diskBackend)
        qemuDomainStorageSourceChainAccessRevoke(driver, vm, disk->src);
4358

4359 4360 4361 4362
    dev.type = VIR_DOMAIN_DEVICE_DISK;
    dev.data.disk = disk;
    ignore_value(qemuRemoveSharedDevice(driver, &dev, vm->def->name));

4363 4364
    if (virStorageSourceChainHasManagedPR(disk->src) &&
        qemuHotplugRemoveManagedPR(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
4365 4366
        goto cleanup;

4367 4368 4369
    ret = 0;

 cleanup:
4370
    virDomainDiskDefFree(disk);
4371
    return ret;
4372 4373 4374
}


4375
static int
4376
qemuDomainRemoveControllerDevice(virDomainObjPtr vm,
4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390
                                 virDomainControllerDefPtr controller)
{
    size_t i;

    VIR_DEBUG("Removing controller %s from domain %p %s",
              controller->info.alias, vm, vm->def->name);

    for (i = 0; i < vm->def->ncontrollers; i++) {
        if (vm->def->controllers[i] == controller) {
            virDomainControllerRemove(vm->def, i);
            break;
        }
    }

4391
    qemuDomainReleaseDeviceAddress(vm, &controller->info);
4392
    virDomainControllerDefFree(controller);
4393
    return 0;
4394 4395 4396
}


4397 4398 4399 4400 4401 4402
static int
qemuDomainRemoveMemoryDevice(virQEMUDriverPtr driver,
                             virDomainObjPtr vm,
                             virDomainMemoryDefPtr mem)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4403
    unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
4404
    unsigned long long newmem = oldmem - mem->size;
4405 4406 4407 4408 4409 4410 4411 4412
    char *backendAlias = NULL;
    int rc;
    int idx;

    VIR_DEBUG("Removing memory device %s from domain %p %s",
              mem->info.alias, vm, vm->def->name);

    if (virAsprintf(&backendAlias, "mem%s", mem->info.alias) < 0)
4413
        return -1;
4414 4415 4416

    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorDelObject(priv->mon, backendAlias);
4417 4418 4419 4420 4421 4422 4423 4424
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        rc = -1;

    VIR_FREE(backendAlias);

    virDomainAuditMemory(vm, oldmem, newmem, "update", rc == 0);
    if (rc < 0)
        return -1;
4425 4426 4427 4428

    if ((idx = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
        virDomainMemoryRemove(vm->def, idx);

M
Michal Privoznik 已提交
4429 4430 4431
    if (qemuSecurityRestoreMemoryLabel(driver, vm, mem) < 0)
        VIR_WARN("Unable to restore security label on memdev");

4432 4433 4434
    if (qemuTeardownMemoryDevicesCgroup(vm, mem) < 0)
        VIR_WARN("Unable to remove memory device cgroup ACL");

4435
    if (qemuDomainNamespaceTeardownMemory(vm, mem) <  0)
M
Michal Privoznik 已提交
4436 4437
        VIR_WARN("Unable to remove memory device from /dev");

4438 4439 4440
    if (qemuProcessDestroyMemoryBackingPath(driver, vm, mem) < 0)
        VIR_WARN("Unable to destroy memory backing path");

4441
    virDomainMemoryDefFree(mem);
4442

4443 4444 4445
    /* fix the balloon size */
    ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));

4446
    /* decrease the mlock limit after memory unplug if necessary */
4447
    ignore_value(qemuDomainAdjustMaxMemLock(vm));
4448

4449
    return 0;
4450 4451 4452
}


4453 4454 4455 4456 4457
static void
qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
{
4458
    qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
4459
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4460 4461 4462 4463
}

static void
qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver,
4464
                              virDomainObjPtr vm,
4465 4466
                              virDomainHostdevDefPtr hostdev)
{
4467
    qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
4468
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4469 4470 4471 4472 4473 4474 4475
}

static void
qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
4476
    qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
4477 4478
}

4479 4480 4481 4482 4483 4484 4485 4486
static void
qemuDomainRemoveSCSIVHostDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainHostdevDefPtr hostdev)
{
    qemuHostdevReAttachSCSIVHostDevices(driver, vm->def->name, &hostdev, 1);
}

4487 4488 4489 4490 4491 4492 4493

static void
qemuDomainRemoveMediatedDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    qemuHostdevReAttachMediatedDevices(driver, vm->def->name, &hostdev, 1);
4494
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4495 4496 4497
}


4498
static int
4499 4500 4501 4502 4503 4504
qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainHostdevDefPtr hostdev)
{
    virDomainNetDefPtr net = NULL;
    size_t i;
4505 4506
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
J
John Ferlan 已提交
4507
    char *drivealias = NULL;
4508
    char *objAlias = NULL;
4509
    bool is_vfio = false;
4510 4511 4512 4513

    VIR_DEBUG("Removing host device %s from domain %p %s",
              hostdev->info->alias, vm, vm->def->name);

4514 4515 4516 4517 4518
    if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
        int backend = hostdev->source.subsys.u.pci.backend;
        is_vfio = backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
    }

4519
    if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
4520 4521 4522
        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
        virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;

J
John Ferlan 已提交
4523
        if (!(drivealias = qemuAliasFromHostdev(hostdev)))
4524 4525
            goto cleanup;

4526 4527 4528 4529 4530
        /* Look for the markers that the iSCSI hostdev was added with a
         * secret object to manage the username/password. If present, let's
         * attempt to remove the object as well. */
        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI &&
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_ISCSI_PASSWORD_SECRET) &&
4531
            qemuDomainStorageSourceHasAuth(iscsisrc->src)) {
4532 4533 4534 4535
            if (!(objAlias = qemuDomainGetSecretAESAlias(hostdev->info->alias, false)))
                goto cleanup;
        }

4536
        qemuDomainObjEnterMonitor(driver, vm);
J
John Ferlan 已提交
4537
        qemuMonitorDriveDel(priv->mon, drivealias);
4538 4539 4540 4541 4542

        /* If it fails, then so be it - it was a best shot */
        if (objAlias)
            ignore_value(qemuMonitorDelObject(priv->mon, objAlias));

4543 4544
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            goto cleanup;
4545 4546
    }

4547
    if (hostdev->parentnet) {
4548
        net = hostdev->parentnet;
4549
        for (i = 0; i < vm->def->nnets; i++) {
4550
            if (vm->def->nets[i] == hostdev->parentnet) {
4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565
                virDomainNetRemove(vm->def, i);
                break;
            }
        }
    }

    for (i = 0; i < vm->def->nhostdevs; i++) {
        if (vm->def->hostdevs[i] == hostdev) {
            virDomainHostdevRemove(vm->def, i);
            break;
        }
    }

    virDomainAuditHostdev(vm, hostdev, "detach", true);

4566
    if (!is_vfio &&
4567
        qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
4568
        VIR_WARN("Failed to restore host device labelling");
4569

4570 4571 4572
    if (qemuTeardownHostdevCgroup(vm, hostdev) < 0)
        VIR_WARN("Failed to remove host device cgroup ACL");

4573
    if (qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
4574 4575
        VIR_WARN("Unable to remove host device from /dev");

4576
    switch ((virDomainHostdevSubsysType)hostdev->source.subsys.type) {
4577 4578
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
        qemuDomainRemovePCIHostDevice(driver, vm, hostdev);
4579 4580 4581 4582
        /* QEMU might no longer need to lock as much memory, eg. we just
         * detached the last VFIO device, so adjust the limit here */
        if (qemuDomainAdjustMaxMemLock(vm) < 0)
            VIR_WARN("Failed to adjust locked memory limit");
4583 4584 4585 4586 4587 4588 4589
        break;
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        qemuDomainRemoveUSBHostDevice(driver, vm, hostdev);
        break;
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
        qemuDomainRemoveSCSIHostDevice(driver, vm, hostdev);
        break;
4590
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
4591
        qemuDomainRemoveSCSIVHostDevice(driver, vm, hostdev);
4592
        break;
4593
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
4594
        qemuDomainRemoveMediatedDevice(driver, vm, hostdev);
4595
        break;
4596 4597 4598 4599 4600 4601 4602
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
        break;
    }

    virDomainHostdevDefFree(hostdev);

    if (net) {
4603 4604 4605 4606 4607 4608 4609 4610 4611
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            virConnectPtr conn = virGetConnectNetwork();
            if (conn) {
                virDomainNetReleaseActualDevice(conn, vm->def, net);
                virObjectUnref(conn);
            } else {
                VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
            }
        }
4612 4613
        virDomainNetDefFree(net);
    }
4614

4615 4616 4617
    ret = 0;

 cleanup:
J
John Ferlan 已提交
4618
    VIR_FREE(drivealias);
4619
    VIR_FREE(objAlias);
4620
    return ret;
4621 4622 4623
}


4624
static int
4625 4626 4627 4628
qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainNetDefPtr net)
{
4629
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
4630 4631
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *hostnet_name = NULL;
4632
    char *charDevAlias = NULL;
4633
    size_t i;
4634
    int ret = -1;
4635
    int actualType = virDomainNetGetActualType(net);
4636

4637
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
4638
        /* this function handles all hostdev and netdev cleanup */
4639 4640
        ret = qemuDomainRemoveHostDevice(driver, vm,
                                         virDomainNetGetActualHostdev(net));
4641
        goto cleanup;
4642 4643
    }

4644 4645 4646
    VIR_DEBUG("Removing network interface %s from domain %p %s",
              net->info.alias, vm, vm->def->name);

4647
    if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0 ||
4648
        !(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias)))
4649 4650
        goto cleanup;

4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661
    if (virDomainNetGetActualBandwidth(net) &&
        virNetDevSupportBandwidth(virDomainNetGetActualType(net)) &&
        virNetDevBandwidthClear(net->ifname) < 0)
        VIR_WARN("cannot clear bandwidth setting for device : %s",
                 net->ifname);

    /* deactivate the tap/macvtap device on the host, which could also
     * affect the parent device (e.g. macvtap passthrough mode sets
     * the parent device offline)
     */
    ignore_value(qemuInterfaceStopDevice(net));
4662

4663
    qemuDomainObjEnterMonitor(driver, vm);
J
Ján Tomko 已提交
4664 4665
    if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
4666
            goto cleanup;
J
Ján Tomko 已提交
4667 4668
        virDomainAuditNet(vm, net, NULL, "detach", false);
        goto cleanup;
4669
    }
4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680

    if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
        /* vhostuser has a chardev too */
        if (qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0) {
            /* well, this is a messy situation. Guest visible PCI device has
             * been removed, netdev too but chardev not. The best seems to be
             * to just ignore the error and carry on.
             */
        }
    }

4681 4682
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
4683

4684 4685 4686
    if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
        qemuSlirpStop(QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp, vm, driver, net, true);

4687 4688 4689 4690 4691 4692 4693 4694 4695
    virDomainAuditNet(vm, net, NULL, "detach", true);

    for (i = 0; i < vm->def->nnets; i++) {
        if (vm->def->nets[i] == net) {
            virDomainNetRemove(vm->def, i);
            break;
        }
    }

4696
    qemuDomainReleaseDeviceAddress(vm, &net->info);
4697 4698
    virDomainConfNWFilterTeardown(net);

4699 4700 4701 4702 4703 4704
    if (cfg->macFilter && (net->ifname != NULL)) {
        ignore_value(ebtablesRemoveForwardAllowIn(driver->ebtables,
                                                  net->ifname,
                                                  &net->mac));
    }

4705
    if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
4706 4707 4708 4709 4710 4711 4712 4713
        ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
                         net->ifname, &net->mac,
                         virDomainNetGetActualDirectDev(net),
                         virDomainNetGetActualDirectMode(net),
                         virDomainNetGetActualVirtPortProfile(net),
                         cfg->stateDir));
    }

4714
    qemuDomainNetDeviceVportRemove(net);
4715

4716 4717 4718 4719 4720 4721 4722 4723 4724
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virConnectPtr conn = virGetConnectNetwork();
        if (conn) {
            virDomainNetReleaseActualDevice(conn, vm->def, net);
            virObjectUnref(conn);
        } else {
            VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
        }
    }
4725
    virDomainNetDefFree(net);
4726
    ret = 0;
4727 4728

 cleanup:
4729
    VIR_FREE(charDevAlias);
4730 4731
    VIR_FREE(hostnet_name);
    return ret;
4732 4733 4734
}


4735
static int
4736
qemuDomainRemoveChrDevice(virQEMUDriverPtr driver,
4737
                          virDomainObjPtr vm,
4738 4739
                          virDomainChrDefPtr chr,
                          bool monitor)
4740
{
4741
    virObjectEventPtr event;
4742 4743 4744
    char *charAlias = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
4745
    int rc = 0;
4746

4747 4748 4749
    VIR_DEBUG("Removing character device %s from domain %p %s",
              chr->info.alias, vm, vm->def->name);

4750 4751
    if (!(charAlias = qemuAliasChardevFromDevAlias(chr->info.alias)))
        goto cleanup;
4752

4753
    if (monitor) {
4754 4755 4756 4757 4758
        qemuDomainObjEnterMonitor(driver, vm);
        rc = qemuMonitorDetachCharDev(priv->mon, charAlias);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            goto cleanup;
    }
4759

4760 4761
    if (rc == 0 &&
        qemuDomainDelChardevTLSObjects(driver, vm, chr->source, charAlias) < 0)
4762 4763
        goto cleanup;

4764 4765 4766 4767 4768
    virDomainAuditChardev(vm, chr, NULL, "detach", rc == 0);

    if (rc < 0)
        goto cleanup;

4769 4770 4771
    if (qemuTeardownChardevCgroup(vm, chr) < 0)
        VIR_WARN("Failed to remove chr device cgroup ACL");

4772 4773 4774
    if (qemuSecurityRestoreChardevLabel(driver, vm, chr) < 0)
        VIR_WARN("Unable to restore security label on char device");

4775
    if (qemuDomainNamespaceTeardownChardev(vm, chr) < 0)
4776 4777
        VIR_WARN("Unable to remove chr device from /dev");

4778
    qemuDomainReleaseDeviceAddress(vm, &chr->info);
4779 4780 4781 4782 4783 4784
    qemuDomainChrRemove(vm->def, chr);

    /* The caller does not emit the event, so we must do it here. Note
     * that the event should be reported only after all backend
     * teardown is completed.
     */
4785
    event = virDomainEventDeviceRemovedNewFromObj(vm, chr->info.alias);
4786
    virObjectEventStateQueue(driver->domainEventState, event);
4787

4788
    virDomainChrDefFree(chr);
4789 4790 4791 4792 4793
    ret = 0;

 cleanup:
    VIR_FREE(charAlias);
    return ret;
4794 4795 4796
}


4797 4798 4799 4800 4801 4802 4803 4804 4805 4806
static int
qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
    char *charAlias = NULL;
    char *objAlias = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ssize_t idx;
    int ret = -1;
4807
    int rc = 0;
4808 4809 4810 4811

    VIR_DEBUG("Removing RNG device %s from domain %p %s",
              rng->info.alias, vm, vm->def->name);

4812

4813 4814 4815
    if (virAsprintf(&objAlias, "obj%s", rng->info.alias) < 0)
        goto cleanup;

4816
    if (!(charAlias = qemuAliasChardevFromDevAlias(rng->info.alias)))
4817 4818 4819
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);
4820

4821 4822 4823 4824 4825 4826 4827 4828
    if (rc == 0 &&
        qemuMonitorDelObject(priv->mon, objAlias) < 0)
        rc = -1;

    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
        rc == 0 &&
        qemuMonitorDetachCharDev(priv->mon, charAlias) < 0)
        rc = -1;
4829 4830 4831 4832

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

4833 4834
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
        rc == 0 &&
4835 4836
        qemuDomainDelChardevTLSObjects(driver, vm, rng->source.chardev,
                                       charAlias) < 0)
4837
        rc = -1;
4838

4839 4840 4841 4842 4843
    virDomainAuditRNG(vm, rng, NULL, "detach", rc == 0);

    if (rc < 0)
        goto cleanup;

4844 4845 4846
    if (qemuTeardownRNGCgroup(vm, rng) < 0)
        VIR_WARN("Failed to remove RNG device cgroup ACL");

4847
    if (qemuDomainNamespaceTeardownRNG(vm, rng) < 0)
4848 4849
        VIR_WARN("Unable to remove RNG device from /dev");

4850 4851
    if ((idx = virDomainRNGFind(vm->def, rng)) >= 0)
        virDomainRNGRemove(vm->def, idx);
4852
    qemuDomainReleaseDeviceAddress(vm, &rng->info);
4853 4854 4855 4856 4857 4858 4859 4860 4861 4862
    virDomainRNGDefFree(rng);
    ret = 0;

 cleanup:
    VIR_FREE(charAlias);
    VIR_FREE(objAlias);
    return ret;
}


4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902
static int
qemuDomainRemoveShmemDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainShmemDefPtr shmem)
{
    int rc;
    int ret = -1;
    ssize_t idx = -1;
    char *charAlias = NULL;
    char *memAlias = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    VIR_DEBUG("Removing shmem device %s from domain %p %s",
              shmem->info.alias, vm, vm->def->name);

    if (shmem->server.enabled) {
        if (virAsprintf(&charAlias, "char%s", shmem->info.alias) < 0)
            return -1;
    } else {
        if (virAsprintf(&memAlias, "shmmem-%s", shmem->info.alias) < 0)
            return -1;
    }

    qemuDomainObjEnterMonitor(driver, vm);

    if (shmem->server.enabled)
        rc = qemuMonitorDetachCharDev(priv->mon, charAlias);
    else
        rc = qemuMonitorDelObject(priv->mon, memAlias);

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

    virDomainAuditShmem(vm, shmem, "detach", rc == 0);

    if (rc < 0)
        goto cleanup;

    if ((idx = virDomainShmemDefFind(vm->def, shmem)) >= 0)
        virDomainShmemDefRemove(vm->def, idx);
4903
    qemuDomainReleaseDeviceAddress(vm, &shmem->info);
4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914
    virDomainShmemDefFree(shmem);

    ret = 0;
 cleanup:
    VIR_FREE(charAlias);
    VIR_FREE(memAlias);

    return ret;
}


M
Michal Privoznik 已提交
4915
static int
4916
qemuDomainRemoveWatchdog(virDomainObjPtr vm,
M
Michal Privoznik 已提交
4917 4918 4919 4920 4921
                         virDomainWatchdogDefPtr watchdog)
{
    VIR_DEBUG("Removing watchdog %s from domain %p %s",
              watchdog->info.alias, vm, vm->def->name);

4922
    qemuDomainReleaseDeviceAddress(vm, &watchdog->info);
M
Michal Privoznik 已提交
4923 4924 4925 4926 4927 4928
    virDomainWatchdogDefFree(vm->def->watchdog);
    vm->def->watchdog = NULL;
    return 0;
}


4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941
static int
qemuDomainRemoveInputDevice(virDomainObjPtr vm,
                            virDomainInputDefPtr dev)
{
    size_t i;

    VIR_DEBUG("Removing input device %s from domain %p %s",
              dev->info.alias, vm, vm->def->name);

    for (i = 0; i < vm->def->ninputs; i++) {
        if (vm->def->inputs[i] == dev)
            break;
    }
4942
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
4943 4944 4945 4946 4947 4948 4949 4950 4951
    if (qemuSecurityRestoreInputLabel(vm, dev) < 0)
        VIR_WARN("Unable to restore security label on input device");

    if (qemuTeardownInputCgroup(vm, dev) < 0)
        VIR_WARN("Unable to remove input device cgroup ACL");

    if (qemuDomainNamespaceTeardownInput(vm, dev) < 0)
        VIR_WARN("Unable to remove input device from /dev");

4952 4953 4954 4955 4956 4957
    virDomainInputDefFree(vm->def->inputs[i]);
    VIR_DELETE_ELEMENT(vm->def->inputs, i, vm->def->ninputs);
    return 0;
}


J
Ján Tomko 已提交
4958 4959 4960 4961 4962 4963 4964
static int
qemuDomainRemoveVsockDevice(virDomainObjPtr vm,
                            virDomainVsockDefPtr dev)
{
    VIR_DEBUG("Removing vsock device %s from domain %p %s",
              dev->info.alias, vm, vm->def->name);

4965
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
J
Ján Tomko 已提交
4966 4967 4968 4969 4970 4971
    virDomainVsockDefFree(vm->def->vsock);
    vm->def->vsock = NULL;
    return 0;
}


4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003
static int
qemuDomainRemoveRedirdevDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainRedirdevDefPtr dev)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *charAlias = NULL;
    ssize_t idx;
    int ret = -1;

    VIR_DEBUG("Removing redirdev device %s from domain %p %s",
              dev->info.alias, vm, vm->def->name);

    if (!(charAlias = qemuAliasChardevFromDevAlias(dev->info.alias)))
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);
    /* DeviceDel from Detach may remove chardev,
     * so we cannot rely on return status to delete TLS chardevs.
     */
    ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));

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

    if (qemuDomainDelChardevTLSObjects(driver, vm, dev->source, charAlias) < 0)
        goto cleanup;

    virDomainAuditRedirdev(vm, dev, "detach", true);

    if ((idx = virDomainRedirdevDefFind(vm->def, dev)) >= 0)
        virDomainRedirdevDefRemove(vm->def, idx);
5004
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
5005 5006 5007 5008 5009 5010 5011 5012 5013 5014
    virDomainRedirdevDefFree(dev);

    ret = 0;

 cleanup:
    VIR_FREE(charAlias);
    return ret;
}


5015
static void
5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030
qemuDomainRemoveAuditDevice(virDomainObjPtr vm,
                            virDomainDeviceDefPtr detach,
                            bool success)
{
    switch ((virDomainDeviceType)detach->type) {
    case VIR_DOMAIN_DEVICE_DISK:
        virDomainAuditDisk(vm, detach->data.disk->src, NULL, "detach", success);
        break;
    case VIR_DOMAIN_DEVICE_NET:
        virDomainAuditNet(vm, detach->data.net, NULL, "detach", success);
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        virDomainAuditHostdev(vm, detach->data.hostdev, "detach", success);
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
5031 5032
        virDomainAuditInput(vm, detach->data.input, "detach", success);
        break;
5033
    case VIR_DOMAIN_DEVICE_CHR:
5034 5035
        virDomainAuditChardev(vm, detach->data.chr, NULL, "detach", success);
        break;
5036
    case VIR_DOMAIN_DEVICE_RNG:
5037 5038 5039 5040 5041 5042 5043 5044 5045
        virDomainAuditRNG(vm, detach->data.rng, NULL, "detach", success);
        break;
    case VIR_DOMAIN_DEVICE_MEMORY: {
        unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
        unsigned long long newmem = oldmem - detach->data.memory->size;

        virDomainAuditMemory(vm, oldmem, newmem, "update", success);
        break;
    }
5046
    case VIR_DOMAIN_DEVICE_SHMEM:
5047 5048
        virDomainAuditShmem(vm, detach->data.shmem, "detach", success);
        break;
5049
    case VIR_DOMAIN_DEVICE_REDIRDEV:
5050 5051
        virDomainAuditRedirdev(vm, detach->data.redirdev, "detach", success);
        break;
5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078

    case VIR_DOMAIN_DEVICE_LEASE:
    case VIR_DOMAIN_DEVICE_CONTROLLER:
    case VIR_DOMAIN_DEVICE_WATCHDOG:
    case VIR_DOMAIN_DEVICE_VSOCK:
        /* These devices don't have associated audit logs */
        break;

    case VIR_DOMAIN_DEVICE_FS:
    case VIR_DOMAIN_DEVICE_SOUND:
    case VIR_DOMAIN_DEVICE_VIDEO:
    case VIR_DOMAIN_DEVICE_GRAPHICS:
    case VIR_DOMAIN_DEVICE_HUB:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
    case VIR_DOMAIN_DEVICE_NVRAM:
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_TPM:
    case VIR_DOMAIN_DEVICE_PANIC:
    case VIR_DOMAIN_DEVICE_IOMMU:
    case VIR_DOMAIN_DEVICE_LAST:
        /* libvirt doesn't yet support detaching these devices */
        break;
    }
}


5079
int
5080 5081 5082 5083
qemuDomainRemoveDevice(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       virDomainDeviceDefPtr dev)
{
5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097
    virDomainDeviceInfoPtr info;
    virObjectEventPtr event;
    VIR_AUTOFREE(char *) alias = NULL;

    /*
     * save the alias to use when sending a DEVICE_REMOVED event after
     * all other teardown is complete
     */
    if ((info = virDomainDeviceGetInfo(dev)) &&
        VIR_STRDUP(alias, info->alias) < 0) {
        return -1;
    }
    info = NULL;

5098
    switch ((virDomainDeviceType)dev->type) {
5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113
    case VIR_DOMAIN_DEVICE_CHR:
        /* We must return directly after calling
         * qemuDomainRemoveChrDevice because it is called directly
         * from other places, so it must be completely self-contained
         * and can't take advantage of any common code at the end of
         * qemuDomainRemoveDevice().
         */
        return qemuDomainRemoveChrDevice(driver, vm, dev->data.chr, true);

        /*
         * all of the following qemuDomainRemove*Device() functions
         * are (and must be) only called from this function, so any
         * code that is common to them all can be pulled out and put
         * into this function.
         */
5114
    case VIR_DOMAIN_DEVICE_DISK:
5115 5116
        if (qemuDomainRemoveDiskDevice(driver, vm, dev->data.disk) < 0)
            return -1;
5117 5118
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5119 5120
        if (qemuDomainRemoveControllerDevice(vm, dev->data.controller) < 0)
            return -1;
5121 5122
        break;
    case VIR_DOMAIN_DEVICE_NET:
5123 5124
        if (qemuDomainRemoveNetDevice(driver, vm, dev->data.net) < 0)
            return -1;
5125 5126
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
5127 5128
        if (qemuDomainRemoveHostDevice(driver, vm, dev->data.hostdev) < 0)
            return -1;
5129
        break;
5130
    case VIR_DOMAIN_DEVICE_RNG:
5131 5132
        if (qemuDomainRemoveRNGDevice(driver, vm, dev->data.rng) < 0)
            return -1;
5133
        break;
5134
    case VIR_DOMAIN_DEVICE_MEMORY:
5135 5136
        if (qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory) < 0)
            return -1;
5137
        break;
5138
    case VIR_DOMAIN_DEVICE_SHMEM:
5139 5140
        if (qemuDomainRemoveShmemDevice(driver, vm, dev->data.shmem) < 0)
            return -1;
5141
        break;
5142
    case VIR_DOMAIN_DEVICE_INPUT:
5143 5144
        if (qemuDomainRemoveInputDevice(vm, dev->data.input) < 0)
            return -1;
5145
        break;
5146
    case VIR_DOMAIN_DEVICE_REDIRDEV:
5147 5148
        if (qemuDomainRemoveRedirdevDevice(driver, vm, dev->data.redirdev) < 0)
            return -1;
5149
        break;
5150
    case VIR_DOMAIN_DEVICE_WATCHDOG:
5151 5152
        if (qemuDomainRemoveWatchdog(vm, dev->data.watchdog) < 0)
            return -1;
5153
        break;
J
Ján Tomko 已提交
5154
    case VIR_DOMAIN_DEVICE_VSOCK:
5155 5156
        if (qemuDomainRemoveVsockDevice(vm, dev->data.vsock) < 0)
            return -1;
J
Ján Tomko 已提交
5157 5158
        break;

5159 5160 5161 5162 5163 5164 5165 5166 5167 5168
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_LEASE:
    case VIR_DOMAIN_DEVICE_FS:
    case VIR_DOMAIN_DEVICE_SOUND:
    case VIR_DOMAIN_DEVICE_VIDEO:
    case VIR_DOMAIN_DEVICE_GRAPHICS:
    case VIR_DOMAIN_DEVICE_HUB:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
    case VIR_DOMAIN_DEVICE_NVRAM:
5169
    case VIR_DOMAIN_DEVICE_TPM:
5170
    case VIR_DOMAIN_DEVICE_PANIC:
J
Ján Tomko 已提交
5171
    case VIR_DOMAIN_DEVICE_IOMMU:
5172 5173 5174 5175 5176 5177
    case VIR_DOMAIN_DEVICE_LAST:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("don't know how to remove a %s device"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }
5178 5179 5180 5181 5182

    event = virDomainEventDeviceRemovedNewFromObj(vm, alias);
    virObjectEventStateQueue(driver->domainEventState, event);

    return 0;
5183 5184 5185 5186
}


static void
5187 5188
qemuDomainMarkDeviceAliasForRemoval(virDomainObjPtr vm,
                                    const char *alias)
5189 5190 5191
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

5192 5193
    memset(&priv->unplug, 0, sizeof(priv->unplug));

5194
    priv->unplug.alias = alias;
5195 5196
}

5197 5198 5199 5200 5201 5202 5203 5204 5205 5206

static void
qemuDomainMarkDeviceForRemoval(virDomainObjPtr vm,
                               virDomainDeviceInfoPtr info)

{
    qemuDomainMarkDeviceAliasForRemoval(vm, info->alias);
}


5207 5208 5209 5210
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
5211
    priv->unplug.alias = NULL;
5212
    priv->unplug.eventSeen = false;
5213 5214 5215
}

/* Returns:
5216 5217
 *  -1 Unplug of the device failed
 *
5218
 *   0 removal of the device did not finish in qemuDomainRemoveDeviceWaitTime
5219 5220 5221 5222
 *
 *   1 when the caller is responsible for finishing the device removal:
 *      - DEVICE_DELETED event arrived before the timeout time
 *      - we failed to reliably wait for the event and thus use fallback behavior
5223 5224 5225 5226 5227 5228
 */
static int
qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    unsigned long long until;
5229
    int rc;
5230 5231

    if (virTimeMillisNow(&until) < 0)
5232
        return 1;
5233
    until += qemuDomainRemoveDeviceWaitTime;
5234

5235
    while (priv->unplug.alias) {
5236 5237 5238 5239 5240
        if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
            return 0;

        if (rc < 0) {
            VIR_WARN("Failed to wait on unplug condition for domain '%s' "
5241
                     "device '%s'", vm->def->name, priv->unplug.alias);
5242
            return 1;
5243 5244 5245
        }
    }

5246 5247 5248 5249 5250 5251
    if (priv->unplug.status == QEMU_DOMAIN_UNPLUGGING_DEVICE_STATUS_GUEST_REJECTED) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unplug of device was rejected by the guest"));
        return -1;
    }

5252 5253 5254
    return 1;
}

5255 5256 5257 5258 5259 5260 5261
/* Returns:
 *  true    there was a thread waiting for devAlias to be removed and this
 *          thread will take care of finishing the removal
 *  false   the thread that started the removal is already gone and delegate
 *          finishing the removal to a new thread
 */
bool
5262
qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
5263 5264
                              const char *devAlias,
                              qemuDomainUnpluggingDeviceStatus status)
5265 5266 5267
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

5268
    if (STREQ_NULLABLE(priv->unplug.alias, devAlias)) {
5269
        VIR_DEBUG("Removal of device '%s' continues in waiting thread", devAlias);
5270
        qemuDomainResetDeviceRemoval(vm);
5271
        priv->unplug.status = status;
5272
        priv->unplug.eventSeen = true;
5273
        virDomainObjBroadcast(vm);
5274
        return true;
5275
    }
5276
    return false;
5277 5278 5279
}


5280 5281 5282 5283 5284 5285
static int
qemuFindDisk(virDomainDefPtr def, const char *dst)
{
    size_t i;

    for (i = 0; i < def->ndisks; i++) {
5286
        if (STREQ(def->disks[i]->dst, dst))
5287 5288 5289 5290 5291 5292
            return i;
    }

    return -1;
}

5293
static int
5294
qemuDomainDetachPrepDisk(virDomainObjPtr vm,
5295
                         virDomainDiskDefPtr match,
5296
                         virDomainDiskDefPtr *detach)
5297 5298 5299 5300
{
    virDomainDiskDefPtr disk;
    int idx;

5301
    if ((idx = qemuFindDisk(vm->def, match->dst)) < 0) {
5302
        virReportError(VIR_ERR_OPERATION_FAILED,
5303
                       _("disk %s not found"), match->dst);
5304 5305
        return -1;
    }
5306
    *detach = disk = vm->def->disks[idx];
5307

5308
    switch ((virDomainDiskDevice) disk->device) {
5309 5310
    case VIR_DOMAIN_DISK_DEVICE_DISK:
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5311 5312 5313 5314 5315

        switch ((virDomainDiskBus) disk->bus) {
        case VIR_DOMAIN_DISK_BUS_VIRTIO:
        case VIR_DOMAIN_DISK_BUS_USB:
        case VIR_DOMAIN_DISK_BUS_SCSI:
5316
            break;
5317 5318 5319 5320 5321 5322 5323

        case VIR_DOMAIN_DISK_BUS_IDE:
        case VIR_DOMAIN_DISK_BUS_FDC:
        case VIR_DOMAIN_DISK_BUS_XEN:
        case VIR_DOMAIN_DISK_BUS_UML:
        case VIR_DOMAIN_DISK_BUS_SATA:
        case VIR_DOMAIN_DISK_BUS_SD:
5324 5325
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("This type of disk cannot be hot unplugged"));
5326
            return -1;
5327 5328 5329 5330

        case VIR_DOMAIN_DISK_BUS_LAST:
        default:
            virReportEnumRangeError(virDomainDiskBus, disk->bus);
5331
            return -1;
5332
        }
5333
        break;
5334 5335 5336

    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5337 5338 5339
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("disk device type '%s' cannot be detached"),
                       virDomainDiskDeviceTypeToString(disk->device));
5340
        return -1;
5341 5342 5343 5344

    case VIR_DOMAIN_DISK_DEVICE_LAST:
    default:
        virReportEnumRangeError(virDomainDiskDevice, disk->device);
5345
        return -1;
5346 5347
    }

5348 5349 5350
    if (qemuDomainDiskBlockJobIsActive(disk))
        return -1;

5351
    return 0;
5352 5353 5354
}


5355 5356 5357
static bool qemuDomainDiskControllerIsBusy(virDomainObjPtr vm,
                                           virDomainControllerDefPtr detach)
{
5358
    size_t i;
5359
    virDomainDiskDefPtr disk;
5360
    virDomainHostdevDefPtr hostdev;
5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382

    for (i = 0; i < vm->def->ndisks; i++) {
        disk = vm->def->disks[i];
        if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE)
            /* the disk does not use disk controller */
            continue;

        /* check whether the disk uses this type controller */
        if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE &&
            detach->type != VIR_DOMAIN_CONTROLLER_TYPE_IDE)
            continue;
        if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC &&
            detach->type != VIR_DOMAIN_CONTROLLER_TYPE_FDC)
            continue;
        if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
            detach->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
            continue;

        if (disk->info.addr.drive.controller == detach->idx)
            return true;
    }

5383 5384 5385 5386 5387 5388 5389 5390 5391
    for (i = 0; i < vm->def->nhostdevs; i++) {
        hostdev = vm->def->hostdevs[i];
        if (!virHostdevIsSCSIDevice(hostdev) ||
            detach->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
            continue;
        if (hostdev->info->addr.drive.controller == detach->idx)
            return true;
    }

5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414
    return false;
}

static bool qemuDomainControllerIsBusy(virDomainObjPtr vm,
                                       virDomainControllerDefPtr detach)
{
    switch (detach->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
    case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
        return qemuDomainDiskControllerIsBusy(vm, detach);

    case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
    case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
    default:
        /* libvirt does not support sata controller, and does not support to
         * detach virtio and smart card controller.
         */
        return true;
    }
}

5415
static int
5416
qemuDomainDetachPrepController(virDomainObjPtr vm,
5417
                               virDomainControllerDefPtr match,
5418
                               virDomainControllerDefPtr *detach)
5419
{
5420
    int idx;
5421
    virDomainControllerDefPtr controller = NULL;
5422

5423
    if (match->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
5424 5425
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot unplugged."),
5426
                       virDomainControllerTypeToString(match->type));
5427 5428 5429
        return -1;
    }

5430
    if ((idx = virDomainControllerFind(vm->def, match->type, match->idx)) < 0) {
5431
        virReportError(VIR_ERR_DEVICE_MISSING,
5432
                       _("controller %s:%d not found"),
5433 5434
                       virDomainControllerTypeToString(match->type),
                       match->idx);
5435
        return -1;
5436 5437
    }

5438
    *detach = controller = vm->def->controllers[idx];
5439

5440
    if (qemuDomainControllerIsBusy(vm, controller)) {
5441 5442
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("device cannot be detached: device is busy"));
5443
        return -1;
5444
    }
5445

5446
    return 0;
5447 5448 5449
}


5450
/* search for a hostdev matching dev and detach it */
5451
static int
5452
qemuDomainDetachPrepHostdev(virDomainObjPtr vm,
5453
                            virDomainHostdevDefPtr match,
5454
                            virDomainHostdevDefPtr *detach)
5455
{
5456
    virDomainHostdevSubsysPtr subsys = &match->source.subsys;
5457
    virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb;
5458
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
5459
    virDomainHostdevSubsysSCSIPtr scsisrc = &subsys->u.scsi;
5460
    virDomainHostdevSubsysMediatedDevPtr mdevsrc = &subsys->u.mdev;
5461
    virDomainHostdevDefPtr hostdev = NULL;
5462 5463
    int idx;

5464
    if (match->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
5465
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5466
                       _("hot unplug is not supported for hostdev mode '%s'"),
5467
                       virDomainHostdevModeTypeToString(match->mode));
5468 5469 5470
        return -1;
    }

5471 5472
    idx = virDomainHostdevFind(vm->def, match, &hostdev);
    *detach = hostdev;
5473 5474

    if (idx < 0) {
5475
        switch (subsys->type) {
5476
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
5477
            virReportError(VIR_ERR_DEVICE_MISSING,
5478 5479
                           _("host pci device " VIR_PCI_DEVICE_ADDRESS_FMT
                             " not found"),
5480 5481
                           pcisrc->addr.domain, pcisrc->addr.bus,
                           pcisrc->addr.slot, pcisrc->addr.function);
5482 5483
            break;
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
5484
            if (usbsrc->bus && usbsrc->device) {
5485
                virReportError(VIR_ERR_DEVICE_MISSING,
5486
                               _("host usb device %03d.%03d not found"),
5487
                               usbsrc->bus, usbsrc->device);
5488
            } else {
5489
                virReportError(VIR_ERR_DEVICE_MISSING,
5490
                               _("host usb device vendor=0x%.4x product=0x%.4x not found"),
5491
                               usbsrc->vendor, usbsrc->product);
5492 5493
            }
            break;
5494
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
5495 5496 5497
            if (scsisrc->protocol ==
                VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
                virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
5498
                virReportError(VIR_ERR_DEVICE_MISSING,
5499
                               _("host scsi iSCSI path %s not found"),
5500
                               iscsisrc->src->path);
5501 5502 5503
            } else {
                 virDomainHostdevSubsysSCSIHostPtr scsihostsrc =
                     &scsisrc->u.host;
5504
                 virReportError(VIR_ERR_DEVICE_MISSING,
5505
                                _("host scsi device %s:%u:%u.%llu not found"),
5506 5507 5508
                                scsihostsrc->adapter, scsihostsrc->bus,
                                scsihostsrc->target, scsihostsrc->unit);
            }
5509
            break;
5510
        }
5511 5512 5513 5514 5515
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
            virReportError(VIR_ERR_DEVICE_MISSING,
                           _("mediated device '%s' not found"),
                           mdevsrc->uuidstr);
            break;
5516 5517
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
            break;
5518
        default:
5519 5520
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"), subsys->type);
5521 5522 5523 5524 5525
            break;
        }
        return -1;
    }

5526
    return 0;
5527 5528
}

5529

5530
static int
5531
qemuDomainDetachPrepShmem(virDomainObjPtr vm,
5532
                          virDomainShmemDefPtr match,
5533
                          virDomainShmemDefPtr *detach)
5534 5535 5536 5537
{
    ssize_t idx = -1;
    virDomainShmemDefPtr shmem = NULL;

5538
    if ((idx = virDomainShmemDefFind(vm->def, match)) < 0) {
5539
        virReportError(VIR_ERR_DEVICE_MISSING,
5540 5541
                       _("model '%s' shmem device not present "
                         "in domain configuration"),
5542
                       virDomainShmemModelTypeToString(match->model));
5543 5544 5545
        return -1;
    }

5546
    *detach = shmem = vm->def->shmems[idx];
5547 5548 5549 5550 5551 5552 5553 5554 5555 5556

    switch ((virDomainShmemModel)shmem->model) {
    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN:
    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL:
        break;

    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live detach of shmem model '%s' is not supported"),
                       virDomainShmemModelTypeToString(shmem->model));
M
Marc Hartmayer 已提交
5557
        ATTRIBUTE_FALLTHROUGH;
5558 5559 5560 5561
    case VIR_DOMAIN_SHMEM_MODEL_LAST:
        return -1;
    }

5562
    return 0;
5563 5564 5565
}


5566
static int
5567
qemuDomainDetachPrepWatchdog(virDomainObjPtr vm,
5568
                             virDomainWatchdogDefPtr match,
5569
                             virDomainWatchdogDefPtr *detach)
M
Michal Privoznik 已提交
5570
{
5571 5572 5573
    virDomainWatchdogDefPtr watchdog;

    *detach = watchdog = vm->def->watchdog;
M
Michal Privoznik 已提交
5574

5575 5576 5577 5578 5579 5580
    if (!watchdog) {
        virReportError(VIR_ERR_DEVICE_MISSING, "%s",
                       _("watchdog device not present in domain configuration"));
        return -1;
    }

M
Michal Privoznik 已提交
5581 5582 5583
    /* While domains can have up to one watchdog, the one supplied by the user
     * doesn't necessarily match the one domain has. Refuse to detach in such
     * case. */
5584 5585 5586
    if (!(watchdog->model == match->model &&
          watchdog->action == match->action &&
          virDomainDeviceInfoAddressIsEqual(&match->info, &watchdog->info))) {
5587
        virReportError(VIR_ERR_DEVICE_MISSING,
5588 5589 5590
                       _("model '%s' watchdog device not present "
                         "in domain configuration"),
                       virDomainWatchdogModelTypeToString(watchdog->model));
M
Michal Privoznik 已提交
5591 5592 5593 5594 5595 5596 5597 5598 5599 5600
        return -1;
    }

    if (watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("hot unplug of watchdog of model %s is not supported"),
                       virDomainWatchdogModelTypeToString(watchdog->model));
        return -1;
    }

5601
    return 0;
M
Michal Privoznik 已提交
5602 5603 5604
}


5605
static int
5606
qemuDomainDetachPrepRedirdev(virDomainObjPtr vm,
5607
                             virDomainRedirdevDefPtr match,
5608
                             virDomainRedirdevDefPtr *detach)
5609
{
5610
    virDomainRedirdevDefPtr redirdev;
5611 5612
    ssize_t idx;

5613
    if ((idx = virDomainRedirdevDefFind(vm->def, match)) < 0) {
5614 5615 5616 5617 5618
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("no matching redirdev was not found"));
        return -1;
    }

5619
    *detach = redirdev = vm->def->redirdevs[idx];
5620

5621
    return 0;
5622 5623 5624
}


5625
static int
5626
qemuDomainDetachPrepNet(virDomainObjPtr vm,
5627
                        virDomainNetDefPtr match,
5628
                        virDomainNetDefPtr *detach)
5629
{
5630
    int detachidx;
5631
    virDomainNetDefPtr net = NULL;
5632

5633
    if ((detachidx = virDomainNetFindIdx(vm->def, match)) < 0)
5634
        return -1;
5635

5636
    *detach = net = vm->def->nets[detachidx];
5637

5638 5639
    return 0;
}
5640

5641

5642
static int
5643
qemuDomainDetachDeviceChr(virQEMUDriverPtr driver,
5644 5645 5646
                          virDomainObjPtr vm,
                          virDomainChrDefPtr chr,
                          bool async)
5647 5648 5649 5650 5651
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDefPtr vmdef = vm->def;
    virDomainChrDefPtr tmpChr;
5652
    bool guestfwd = false;
5653 5654

    if (!(tmpChr = virDomainChrFind(vmdef, chr))) {
5655
        virReportError(VIR_ERR_DEVICE_MISSING,
5656 5657 5658
                       _("chr type '%s' device not present "
                         "in domain configuration"),
                       virDomainChrDeviceTypeToString(chr->deviceType));
5659
        goto cleanup;
5660 5661
    }

5662 5663 5664 5665 5666 5667
    /* guestfwd channels are not really -device rather than
     * -netdev. We need to treat them slightly differently. */
    guestfwd = tmpChr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
               tmpChr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD;

    if (!async && !guestfwd)
5668
        qemuDomainMarkDeviceForRemoval(vm, &tmpChr->info);
5669

5670
    if (guestfwd) {
5671 5672 5673 5674 5675 5676 5677
        int rc;
        qemuDomainObjEnterMonitor(driver, vm);
        rc = qemuMonitorRemoveNetdev(priv->mon, tmpChr->info.alias);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            rc = -1;

        if (rc < 0)
5678 5679
            goto cleanup;
    } else {
5680
        if (qemuDomainDeleteDevice(vm, tmpChr->info.alias) < 0)
5681
            goto cleanup;
5682
    }
5683

5684 5685 5686
    if (guestfwd) {
        ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr, false);
    } else if (async) {
5687 5688 5689
        ret = 0;
    } else {
        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
5690
            ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr, true);
5691
    }
5692

5693
 cleanup:
5694 5695
    if (!async)
        qemuDomainResetDeviceRemoval(vm);
5696 5697
    return ret;
}
5698 5699


5700
static int
5701
qemuDomainDetachPrepRNG(virDomainObjPtr vm,
5702
                        virDomainRNGDefPtr match,
5703
                        virDomainRNGDefPtr *detach)
5704 5705
{
    ssize_t idx;
5706
    virDomainRNGDefPtr rng;
5707

5708
    if ((idx = virDomainRNGFind(vm->def, match)) < 0) {
5709
        virReportError(VIR_ERR_DEVICE_MISSING,
5710 5711
                       _("model '%s' RNG device not present "
                         "in domain configuration"),
5712
                       virDomainRNGBackendTypeToString(match->model));
5713 5714 5715
        return -1;
    }

5716
    *detach = rng = vm->def->rngs[idx];
5717

5718
    return 0;
5719
}
5720 5721


5722
static int
5723
qemuDomainDetachPrepMemory(virDomainObjPtr vm,
5724
                           virDomainMemoryDefPtr match,
5725
                           virDomainMemoryDefPtr *detach)
5726 5727 5728 5729
{
    virDomainMemoryDefPtr mem;
    int idx;

5730
    qemuDomainMemoryDeviceAlignSize(vm->def, match);
5731

5732
    if ((idx = virDomainMemoryFindByDef(vm->def, match)) < 0) {
5733
        virReportError(VIR_ERR_DEVICE_MISSING,
5734 5735
                       _("model '%s' memory device not present "
                         "in the domain configuration"),
5736
                       virDomainMemoryModelTypeToString(match->model));
5737 5738 5739
        return -1;
    }

5740
    *detach = mem = vm->def->mems[idx];
5741

5742
    return 0;
5743
}
5744 5745


5746
static int
5747 5748
qemuDomainDetachPrepInput(virDomainObjPtr vm,
                          virDomainInputDefPtr match,
5749
                          virDomainInputDefPtr *detach)
5750 5751 5752 5753
{
    virDomainInputDefPtr input;
    int idx;

5754
    if ((idx = virDomainInputDefFind(vm->def, match)) < 0) {
5755 5756 5757 5758
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("matching input device not found"));
        return -1;
    }
5759
    *detach = input = vm->def->inputs[idx];
5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775

    switch ((virDomainInputBus) input->bus) {
    case VIR_DOMAIN_INPUT_BUS_PS2:
    case VIR_DOMAIN_INPUT_BUS_XEN:
    case VIR_DOMAIN_INPUT_BUS_PARALLELS:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("input device on bus '%s' cannot be detached"),
                       virDomainInputBusTypeToString(input->bus));
        return -1;

    case VIR_DOMAIN_INPUT_BUS_LAST:
    case VIR_DOMAIN_INPUT_BUS_USB:
    case VIR_DOMAIN_INPUT_BUS_VIRTIO:
        break;
    }

5776
    return 0;
5777 5778 5779
}


5780
static int
5781 5782
qemuDomainDetachPrepVsock(virDomainObjPtr vm,
                          virDomainVsockDefPtr match,
5783
                          virDomainVsockDefPtr *detach)
5784
{
5785
    virDomainVsockDefPtr vsock;
5786

5787
    *detach = vsock = vm->def->vsock;
5788
    if (!vsock ||
5789
        !virDomainVsockDefEquals(match, vsock)) {
5790 5791 5792 5793 5794
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("matching vsock device not found"));
        return -1;
    }

5795
    return 0;
5796 5797 5798
}


5799
static int
5800 5801 5802
qemuDomainDetachDeviceLease(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainLeaseDefPtr lease)
5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822
{
    virDomainLeaseDefPtr det_lease;
    int idx;

    if ((idx = virDomainLeaseIndex(vm->def, lease)) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Lease %s in lockspace %s does not exist"),
                       lease->key, NULLSTR(lease->lockspace));
        return -1;
    }

    if (virDomainLockLeaseDetach(driver->lockManager, vm, lease) < 0)
        return -1;

    det_lease = virDomainLeaseRemoveAt(vm->def, idx);
    virDomainLeaseDefFree(det_lease);
    return 0;
}


5823 5824
int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
5825
                           virDomainDeviceDefPtr match,
5826 5827 5828
                           virQEMUDriverPtr driver,
                           bool async)
{
5829
    virDomainDeviceDef detach = { .type = match->type };
5830
    virDomainDeviceInfoPtr info = NULL;
5831 5832
    int ret = -1;

5833
    switch ((virDomainDeviceType)match->type) {
5834 5835 5836 5837 5838 5839
        /*
         * lease and chr devices don't follow the standard pattern of
         * the others, so they must have their own self-contained
         * Detach functions.
         */
    case VIR_DOMAIN_DEVICE_LEASE:
5840
        return qemuDomainDetachDeviceLease(driver, vm, match->data.lease);
5841 5842

    case VIR_DOMAIN_DEVICE_CHR:
5843
        return qemuDomainDetachDeviceChr(driver, vm, match->data.chr, async);
5844 5845 5846 5847 5848 5849 5850 5851

        /*
         * All the other device types follow a very similar pattern -
         * First we call type-specific functions to 1) locate the
         * device we want to detach (based on the prototype device in
         * match) and 2) do any device-type-specific validation to
         * assure it is okay to detach the device.
         */
5852
    case VIR_DOMAIN_DEVICE_DISK:
5853 5854
        if (qemuDomainDetachPrepDisk(vm, match->data.disk,
                                     &detach.data.disk) < 0) {
5855 5856
            return -1;
        }
5857 5858
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5859 5860
        if (qemuDomainDetachPrepController(vm, match->data.controller,
                                           &detach.data.controller) < 0) {
5861 5862
            return -1;
        }
5863 5864
        break;
    case VIR_DOMAIN_DEVICE_NET:
5865 5866
        if (qemuDomainDetachPrepNet(vm, match->data.net,
                                    &detach.data.net) < 0) {
5867 5868
            return -1;
        }
5869 5870
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
5871 5872
        if (qemuDomainDetachPrepHostdev(vm, match->data.hostdev,
                                        &detach.data.hostdev) < 0) {
5873 5874
            return -1;
        }
5875 5876
        break;
    case VIR_DOMAIN_DEVICE_RNG:
5877 5878
        if (qemuDomainDetachPrepRNG(vm, match->data.rng,
                                    &detach.data.rng) < 0) {
5879 5880
            return -1;
        }
5881 5882
        break;
    case VIR_DOMAIN_DEVICE_MEMORY:
5883 5884
        if (qemuDomainDetachPrepMemory(vm, match->data.memory,
                                       &detach.data.memory) < 0) {
5885 5886
            return -1;
        }
5887 5888
        break;
    case VIR_DOMAIN_DEVICE_SHMEM:
5889 5890
        if (qemuDomainDetachPrepShmem(vm, match->data.shmem,
                                      &detach.data.shmem) < 0) {
5891 5892
            return -1;
        }
5893 5894
        break;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
5895 5896
        if (qemuDomainDetachPrepWatchdog(vm, match->data.watchdog,
                                         &detach.data.watchdog) < 0) {
5897 5898
            return -1;
        }
5899 5900
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
5901
        if (qemuDomainDetachPrepInput(vm, match->data.input,
5902
                                      &detach.data.input) < 0) {
5903 5904
            return -1;
        }
5905 5906
        break;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
5907 5908
        if (qemuDomainDetachPrepRedirdev(vm, match->data.redirdev,
                                         &detach.data.redirdev) < 0) {
5909 5910
            return -1;
        }
5911 5912
        break;
    case VIR_DOMAIN_DEVICE_VSOCK:
5913
        if (qemuDomainDetachPrepVsock(vm, match->data.vsock,
5914
                                      &detach.data.vsock) < 0) {
5915 5916
            return -1;
        }
5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933
        break;

    case VIR_DOMAIN_DEVICE_FS:
    case VIR_DOMAIN_DEVICE_SOUND:
    case VIR_DOMAIN_DEVICE_VIDEO:
    case VIR_DOMAIN_DEVICE_GRAPHICS:
    case VIR_DOMAIN_DEVICE_HUB:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
    case VIR_DOMAIN_DEVICE_NVRAM:
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_TPM:
    case VIR_DOMAIN_DEVICE_PANIC:
    case VIR_DOMAIN_DEVICE_IOMMU:
    case VIR_DOMAIN_DEVICE_LAST:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live detach of device '%s' is not supported"),
5934
                       virDomainDeviceTypeToString(match->type));
5935
        return -1;
5936 5937
    }

5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964
    /* "detach" now points to the actual device we want to detach */

    if (!(info = virDomainDeviceGetInfo(&detach))) {
        /*
         * This should never happen, since all of the device types in
         * the switch cases that end with a "break" instead of a
         * return have a virDeviceInfo in them.
         */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("device of type '%s' has no device info"),
                       virDomainDeviceTypeToString(detach.type));
        return -1;
    }


    /* Make generic validation checks common to all device types */

    if (!info->alias) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot detach %s device with no alias"),
                       virDomainDeviceTypeToString(detach.type));
        return -1;
    }

    if (qemuIsMultiFunctionDevice(vm->def, info)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("cannot hot unplug %s device with multifunction PCI guest address: "
5965
                         VIR_PCI_DEVICE_ADDRESS_FMT),
5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995
                       virDomainDeviceTypeToString(detach.type),
                       info->addr.pci.domain, info->addr.pci.bus,
                       info->addr.pci.slot, info->addr.pci.function);
        return -1;
    }

    /*
     * Issue the qemu monitor command to delete the device (based on
     * its alias), and optionally wait a short time in case the
     * DEVICE_DELETED event arrives from qemu right away.
     */
    if (!async)
        qemuDomainMarkDeviceForRemoval(vm, info);

    if (qemuDomainDeleteDevice(vm, info->alias) < 0) {
        if (virDomainObjIsActive(vm))
            qemuDomainRemoveAuditDevice(vm, &detach, false);
        goto cleanup;
    }

    if (async) {
        ret = 0;
    } else {
        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
            ret = qemuDomainRemoveDevice(driver, vm, &detach);
    }

 cleanup:
    if (!async)
        qemuDomainResetDeviceRemoval(vm);
5996

5997 5998 5999 6000
    return ret;
}


6001 6002 6003 6004 6005 6006 6007 6008 6009 6010
static int
qemuDomainRemoveVcpu(virQEMUDriverPtr driver,
                     virDomainObjPtr vm,
                     unsigned int vcpu)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
    qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
    int oldvcpus = virDomainDefGetVcpus(vm->def);
    unsigned int nvcpus = vcpupriv->vcpus;
6011
    virErrorPtr save_error = NULL;
6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035
    size_t i;

    if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
        return -1;

    /* validation requires us to set the expected state prior to calling it */
    for (i = vcpu; i < vcpu + nvcpus; i++) {
        vcpuinfo = virDomainDefGetVcpu(vm->def, i);
        vcpuinfo->online = false;
    }

    if (qemuDomainValidateVcpuInfo(vm) < 0) {
        /* rollback vcpu count if the setting has failed */
        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);

        for (i = vcpu; i < vcpu + nvcpus; i++) {
            vcpuinfo = virDomainDefGetVcpu(vm->def, i);
            vcpuinfo->online = true;
        }
        return -1;
    }

    virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", true);

6036 6037 6038 6039 6040 6041
    virErrorPreserveLast(&save_error);

    for (i = vcpu; i < vcpu + nvcpus; i++)
        ignore_value(virCgroupDelThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, i));

    virErrorRestore(&save_error);
6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067

    return 0;
}


void
qemuDomainRemoveVcpuAlias(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          const char *alias)
{
    virDomainVcpuDefPtr vcpu;
    qemuDomainVcpuPrivatePtr vcpupriv;
    size_t i;

    for (i = 0; i < virDomainDefGetVcpusMax(vm->def); i++) {
        vcpu = virDomainDefGetVcpu(vm->def, i);
        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);

        if (STREQ_NULLABLE(alias, vcpupriv->alias)) {
            qemuDomainRemoveVcpu(driver, vm, i);
            return;
        }
    }
}


6068
static int
6069
qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
6070
                         virQEMUDriverConfigPtr cfg,
6071 6072 6073 6074 6075 6076 6077 6078
                         virDomainObjPtr vm,
                         unsigned int vcpu)
{
    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
    qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
    int oldvcpus = virDomainDefGetVcpus(vm->def);
    unsigned int nvcpus = vcpupriv->vcpus;
    int rc;
6079
    int ret = -1;
6080 6081 6082 6083 6084 6085 6086 6087 6088

    if (!vcpupriv->alias) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("vcpu '%u' can't be unplugged"), vcpu);
        return -1;
    }

    qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias);

6089 6090 6091
    if (qemuDomainDeleteDevice(vm, vcpupriv->alias) < 0) {
        if (virDomainObjIsActive(vm))
            virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
6092
        goto cleanup;
6093 6094 6095 6096 6097 6098 6099
    }

    if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
        if (rc == 0)
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("vcpu unplug request timed out"));

6100
        goto cleanup;
6101 6102
    }

6103 6104 6105
    if (qemuDomainRemoveVcpu(driver, vm, vcpu) < 0)
        goto cleanup;

6106 6107 6108 6109 6110
    qemuDomainVcpuPersistOrder(vm->def);

    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
        goto cleanup;

6111 6112 6113 6114 6115
    ret = 0;

 cleanup:
    qemuDomainResetDeviceRemoval(vm);
    return ret;
6116
}
6117 6118 6119 6120


static int
qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
6121
                         virQEMUDriverConfigPtr cfg,
6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181
                         virDomainObjPtr vm,
                         unsigned int vcpu)
{
    virJSONValuePtr vcpuprops = NULL;
    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
    qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
    unsigned int nvcpus = vcpupriv->vcpus;
    bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm);
    int ret = -1;
    int rc;
    int oldvcpus = virDomainDefGetVcpus(vm->def);
    size_t i;

    if (newhotplug) {
        if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0)
            goto cleanup;

        if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo)))
            goto cleanup;
    }

    qemuDomainObjEnterMonitor(driver, vm);

    if (newhotplug) {
        rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops);
        vcpuprops = NULL;
    } else {
        rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true);
    }

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

    virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0);

    if (rc < 0)
        goto cleanup;

    /* start outputting of the new XML element to allow keeping unpluggability */
    if (newhotplug)
        vm->def->individualvcpus = true;

    if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
        goto cleanup;

    /* validation requires us to set the expected state prior to calling it */
    for (i = vcpu; i < vcpu + nvcpus; i++) {
        vcpuinfo = virDomainDefGetVcpu(vm->def, i);
        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);

        vcpuinfo->online = true;

        if (vcpupriv->tid > 0 &&
            qemuProcessSetupVcpu(vm, i) < 0)
            goto cleanup;
    }

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

6182 6183 6184 6185 6186
    qemuDomainVcpuPersistOrder(vm->def);

    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
        goto cleanup;

6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307
    ret = 0;

 cleanup:
    virJSONValueFree(vcpuprops);
    return ret;
}


/**
 * qemuDomainSelectHotplugVcpuEntities:
 *
 * @def: domain definition
 * @nvcpus: target vcpu count
 * @enable: set to true if vcpus should be enabled
 *
 * Tries to find which vcpu entities need to be enabled or disabled to reach
 * @nvcpus. This function works in order of the legacy hotplug but is able to
 * skip over entries that are added out of order.
 *
 * Returns the bitmap of vcpus to modify on success, NULL on error.
 */
static virBitmapPtr
qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def,
                                    unsigned int nvcpus,
                                    bool *enable)
{
    virBitmapPtr ret = NULL;
    virDomainVcpuDefPtr vcpu;
    qemuDomainVcpuPrivatePtr vcpupriv;
    unsigned int maxvcpus = virDomainDefGetVcpusMax(def);
    unsigned int curvcpus = virDomainDefGetVcpus(def);
    ssize_t i;

    if (!(ret = virBitmapNew(maxvcpus)))
        return NULL;

    if (nvcpus > curvcpus) {
        *enable = true;

        for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) {
            vcpu = virDomainDefGetVcpu(def, i);
            vcpupriv =  QEMU_DOMAIN_VCPU_PRIVATE(vcpu);

            if (vcpu->online)
                continue;

            if (vcpupriv->vcpus == 0)
                continue;

            curvcpus += vcpupriv->vcpus;

            if (curvcpus > nvcpus) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("target vm vcpu granularity does not allow the "
                                 "desired vcpu count"));
                goto error;
            }

            ignore_value(virBitmapSetBit(ret, i));
        }
    } else {
        *enable = false;

        for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) {
            vcpu = virDomainDefGetVcpu(def, i);
            vcpupriv =  QEMU_DOMAIN_VCPU_PRIVATE(vcpu);

            if (!vcpu->online)
                continue;

            if (vcpupriv->vcpus == 0)
                continue;

            if (!vcpupriv->alias)
                continue;

            curvcpus -= vcpupriv->vcpus;

            if (curvcpus < nvcpus) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("target vm vcpu granularity does not allow the "
                                 "desired vcpu count"));
                goto error;
            }

            ignore_value(virBitmapSetBit(ret, i));
        }
    }

    if (curvcpus != nvcpus) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("failed to find appropriate hotpluggable vcpus to "
                         "reach the desired target vcpu count"));
        goto error;
    }

    return ret;

 error:
    virBitmapFree(ret);
    return NULL;
}


static int
qemuDomainSetVcpusLive(virQEMUDriverPtr driver,
                       virQEMUDriverConfigPtr cfg,
                       virDomainObjPtr vm,
                       virBitmapPtr vcpumap,
                       bool enable)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL;
    ssize_t nextvcpu = -1;
    int ret = -1;

    if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0)
        goto cleanup;

    if (enable) {
        while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) {
6308 6309
            if (qemuDomainHotplugAddVcpu(driver, cfg, vm, nextvcpu) < 0)
                goto cleanup;
6310 6311 6312 6313 6314 6315
        }
    } else {
        for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) {
            if (!virBitmapIsBitSet(vcpumap, nextvcpu))
                continue;

6316 6317
            if (qemuDomainHotplugDelVcpu(driver, cfg, vm, nextvcpu) < 0)
                goto cleanup;
6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362
        }
    }

    ret = 0;

 cleanup:
    qemuCgroupEmulatorAllNodesRestore(emulatorCgroup);

    return ret;
}


/**
 * qemuDomainSetVcpusConfig:
 * @def: config/offline definition of a domain
 * @nvcpus: target vcpu count
 *
 * Properly handle cold(un)plug of vcpus:
 * - plug in inactive vcpus/uplug active rather than rewriting state
 * - fix hotpluggable state
 */
static void
qemuDomainSetVcpusConfig(virDomainDefPtr def,
                         unsigned int nvcpus,
                         bool hotpluggable)
{
    virDomainVcpuDefPtr vcpu;
    size_t curvcpus = virDomainDefGetVcpus(def);
    size_t maxvcpus = virDomainDefGetVcpusMax(def);
    size_t i;

    /* ordering information may become invalid, thus clear it */
    virDomainDefVcpuOrderClear(def);

    if (curvcpus == nvcpus)
        return;

    if (curvcpus < nvcpus) {
        for (i = 0; i < maxvcpus; i++) {
            vcpu = virDomainDefGetVcpu(def, i);

            if (!vcpu)
                continue;

            if (vcpu->online) {
6363
                /* non-hotpluggable vcpus need to be clustered at the beginning,
6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408
                 * thus we need to force vcpus to be hotpluggable when we find
                 * vcpus that are hotpluggable and online prior to the ones
                 * we are going to add */
                if (vcpu->hotpluggable == VIR_TRISTATE_BOOL_YES)
                    hotpluggable = true;

                continue;
            }

            vcpu->online = true;
            if (hotpluggable) {
                vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
                def->individualvcpus = true;
            } else {
                vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO;
            }

            if (++curvcpus == nvcpus)
                break;
        }
    } else {
        for (i = maxvcpus; i != 0; i--) {
            vcpu = virDomainDefGetVcpu(def, i - 1);

            if (!vcpu || !vcpu->online)
                continue;

            vcpu->online = false;
            vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;

            if (--curvcpus == nvcpus)
                break;
        }
    }
}


int
qemuDomainSetVcpusInternal(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainDefPtr def,
                           virDomainDefPtr persistentDef,
                           unsigned int nvcpus,
                           bool hotpluggable)
{
6409
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451
    virBitmapPtr vcpumap = NULL;
    bool enable;
    int ret = -1;

    if (def && nvcpus > virDomainDefGetVcpusMax(def)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the live domain: %u > %u"),
                       nvcpus, virDomainDefGetVcpusMax(def));
        goto cleanup;
    }

    if (persistentDef && nvcpus > virDomainDefGetVcpusMax(persistentDef)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the persistent domain: %u > %u"),
                       nvcpus, virDomainDefGetVcpusMax(persistentDef));
        goto cleanup;
    }

    if (def) {
        if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus,
                                                            &enable)))
            goto cleanup;

        if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0)
            goto cleanup;
    }

    if (persistentDef) {
        qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable);

        if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;

 cleanup:
    virBitmapFree(vcpumap);
    return ret;
}
6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463


static void
qemuDomainSetVcpuConfig(virDomainDefPtr def,
                        virBitmapPtr map,
                        bool state)
{
    virDomainVcpuDefPtr vcpu;
    ssize_t next = -1;

    def->individualvcpus = true;

6464 6465 6466
    /* ordering information may become invalid, thus clear it */
    virDomainDefVcpuOrderClear(def);

6467
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        vcpu->online = state;
        vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
    }
}


/**
 * qemuDomainFilterHotplugVcpuEntities:
 *
 * Returns a bitmap of hotpluggable vcpu entities that correspond to the logical
 * vcpus requested in @vcpus.
 */
static virBitmapPtr
qemuDomainFilterHotplugVcpuEntities(virDomainDefPtr def,
                                    virBitmapPtr vcpus,
                                    bool state)
{
    qemuDomainVcpuPrivatePtr vcpupriv;
    virDomainVcpuDefPtr vcpu;
    virBitmapPtr map = NULL;
    virBitmapPtr ret = NULL;
    ssize_t next = -1;
    size_t i;

    if (!(map = virBitmapNewCopy(vcpus)))
        return NULL;

    /* make sure that all selected vcpus are in the correct state */
6499
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6500 6501 6502 6503 6504
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        if (vcpu->online == state) {
            virReportError(VIR_ERR_INVALID_ARG,
6505
                           _("vcpu '%zd' is already in requested state"), next);
6506 6507 6508 6509 6510
            goto cleanup;
        }

        if (vcpu->online && !vcpu->hotpluggable) {
            virReportError(VIR_ERR_INVALID_ARG,
6511
                           _("vcpu '%zd' can't be hotunplugged"), next);
6512 6513 6514 6515 6516 6517 6518
            goto cleanup;
        }
    }

    /* Make sure that all vCPUs belonging to a single hotpluggable entity were
     * selected and then de-select any sub-threads of it. */
    next = -1;
6519
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6520 6521 6522 6523 6524 6525 6526
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);

        if (vcpupriv->vcpus == 0) {
            virReportError(VIR_ERR_INVALID_ARG,
6527
                           _("vcpu '%zd' belongs to a larger hotpluggable entity, "
6528 6529 6530 6531 6532 6533 6534 6535
                             "but siblings were not selected"), next);
            goto cleanup;
        }

        for (i = next + 1; i < next + vcpupriv->vcpus; i++) {
            if (!virBitmapIsBitSet(map, i)) {
                virReportError(VIR_ERR_INVALID_ARG,
                               _("vcpu '%zu' was not selected but it belongs to "
6536
                                 "hotpluggable entity '%zd-%zd' which was "
6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554
                                 "partially selected"),
                               i, next, next + vcpupriv->vcpus - 1);
                goto cleanup;
            }

            /* clear the subthreads */
            ignore_value(virBitmapClearBit(map, i));
        }
    }

    VIR_STEAL_PTR(ret, map);

 cleanup:
    virBitmapFree(map);
    return ret;
}


6555
static int
6556
qemuDomainVcpuValidateConfig(virDomainDefPtr def,
6557
                             virBitmapPtr map)
6558
{
6559 6560 6561
    virDomainVcpuDefPtr vcpu;
    size_t maxvcpus = virDomainDefGetVcpusMax(def);
    ssize_t next;
6562
    ssize_t firstvcpu = -1;
6563

6564 6565
    /* vcpu 0 can't be modified */
    if (virBitmapIsBitSet(map, 0)) {
6566
        virReportError(VIR_ERR_INVALID_ARG, "%s",
6567
                       _("vCPU '0' can't be modified"));
6568 6569 6570
        return -1;
    }

6571 6572 6573 6574 6575 6576
    /* non-hotpluggable vcpus need to stay clustered starting from vcpu 0 */
    for (next = virBitmapNextSetBit(map, -1) + 1; next < maxvcpus; next++) {
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        /* skip vcpus being modified */
6577 6578 6579 6580
        if (virBitmapIsBitSet(map, next)) {
            if (firstvcpu < 0)
                firstvcpu = next;

6581
            continue;
6582
        }
6583 6584 6585 6586

        if (vcpu->online && vcpu->hotpluggable == VIR_TRISTATE_BOOL_NO) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("vcpu '%zd' can't be modified as it is followed "
6587
                             "by non-hotpluggable online vcpus"), firstvcpu);
6588 6589 6590 6591
            return -1;
        }
    }

6592 6593 6594 6595
    return 0;
}


6596 6597 6598 6599 6600 6601 6602 6603
int
qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainDefPtr def,
                          virDomainDefPtr persistentDef,
                          virBitmapPtr map,
                          bool state)
{
6604
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629
    virBitmapPtr livevcpus = NULL;
    int ret = -1;

    if (def) {
        if (!qemuDomainSupportsNewVcpuHotplug(vm)) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("this qemu version does not support specific "
                             "vCPU hotplug"));
            goto cleanup;
        }

        if (!(livevcpus = qemuDomainFilterHotplugVcpuEntities(def, map, state)))
            goto cleanup;

        /* Make sure that only one hotpluggable entity is selected.
         * qemuDomainSetVcpusLive allows setting more at once but error
         * resolution in case of a partial failure is hard, so don't let users
         * do so */
        if (virBitmapCountBits(livevcpus) != 1) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("only one hotpluggable entity can be selected"));
            goto cleanup;
        }
    }

6630
    if (persistentDef) {
6631
        if (qemuDomainVcpuValidateConfig(persistentDef, map) < 0)
6632 6633 6634
            goto cleanup;
    }

6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651
    if (livevcpus &&
        qemuDomainSetVcpusLive(driver, cfg, vm, livevcpus, state) < 0)
        goto cleanup;

    if (persistentDef) {
        qemuDomainSetVcpuConfig(persistentDef, map, state);

        if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;

 cleanup:
    virBitmapFree(livevcpus);
    return ret;
}