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

#define VIR_FROM_THIS VIR_FROM_QEMU
59 60 61

VIR_LOG_INIT("qemu.qemu_hotplug");

62
#define CHANGE_MEDIA_TIMEOUT 5000
63

64 65 66 67 68 69 70
/* Timeout in miliseconds for device removal. PPC64 domains
 * can experience a bigger delay in unplug operations during
 * heavy guest activity (vcpu being the most notable case), thus
 * the timeout for PPC64 is also bigger. */
#define QEMU_UNPLUG_TIMEOUT 1000ull * 5
#define QEMU_UNPLUG_TIMEOUT_PPC64 1000ull * 10

71

72 73 74
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm);

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

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
    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;
        }
    }
132 133 134 135 136

    return rc;
}


137 138 139 140
static int
qemuDomainAttachZPCIDevice(qemuMonitorPtr mon,
                           virDomainDeviceInfoPtr info)
{
141
    g_autofree char *devstr_zpci = NULL;
142 143

    if (!(devstr_zpci = qemuBuildZPCIDevStr(info)))
144
        return -1;
145 146

    if (qemuMonitorAddDevice(mon, devstr_zpci) < 0)
147
        return -1;
148

149
    return 0;
150 151 152 153 154 155 156
}


static int
qemuDomainDetachZPCIDevice(qemuMonitorPtr mon,
                           virDomainDeviceInfoPtr info)
{
157
    g_autofree char *zpciAlias = NULL;
158

159
    zpciAlias = g_strdup_printf("zpci%d", info->addr.pci.zpci.uid);
160 161

    if (qemuMonitorDelDevice(mon, zpciAlias) < 0)
162
        return -1;
163

164
    return 0;
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
}


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


200
static int
201 202
qemuHotplugWaitForTrayEject(virDomainObjPtr vm,
                            virDomainDiskDefPtr disk)
203 204 205 206 207 208 209 210 211 212 213 214
{
    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) {
215 216
            /* the caller called qemuMonitorEjectMedia which usually reports an
             * error. Report the failure in an off-chance that it didn't. */
217
            if (virGetLastErrorCode() == VIR_ERR_OK) {
218 219 220
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("timed out waiting to open tray of '%s'"),
                               disk->dst);
221
            }
222 223 224 225 226 227 228 229
            return -1;
        }
    }

    return 0;
}


230
/**
231
 * qemuDomainChangeMediaLegacy:
232 233 234 235 236 237 238 239 240 241 242 243 244
 * @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
 */
245 246 247 248 249 250
static int
qemuDomainChangeMediaLegacy(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainDiskDefPtr disk,
                            virStorageSourcePtr newsrc,
                            bool force)
251
{
252
    int rc;
253
    g_autofree char *driveAlias = NULL;
254
    qemuDomainObjPrivatePtr priv = vm->privateData;
255
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
256
    const char *format = NULL;
257
    g_autofree char *sourcestr = NULL;
258

259
    if (!disk->info.alias) {
260
        virReportError(VIR_ERR_INTERNAL_ERROR,
261
                       _("missing disk device alias name for %s"), disk->dst);
262
        return -1;
263 264
    }

265
    if (!(driveAlias = qemuAliasDiskDriveFromDisk(disk)))
266
        return -1;
267

268 269 270
    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
271
        return -1;
272

273 274
    /* If the tray is present wait for it to open. */
    if (!force && diskPriv->tray) {
275
        rc = qemuHotplugWaitForTrayEject(vm, disk);
276
        if (rc < 0)
277
            return -1;
278 279 280 281 282

        /* 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)
283
            return -1;
284

285 286 287
    } else  {
        /* otherwise report possible errors from the attempt to eject the media*/
        if (rc < 0)
288
            return -1;
289
    }
290

291
    if (!virStorageSourceIsEmpty(newsrc)) {
292
        if (qemuGetDriveSourceString(newsrc, NULL, &sourcestr) < 0)
293
            return -1;
294

295 296 297
        if (virStorageSourceGetActualType(newsrc) != VIR_STORAGE_TYPE_DIR)
            format = virStorageFileFormatTypeToString(newsrc->format);

298
        qemuDomainObjEnterMonitor(driver, vm);
299 300 301 302 303
        rc = qemuMonitorChangeMedia(priv->mon,
                                    driveAlias,
                                    sourcestr,
                                    format);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
304
            return -1;
305
    }
306

307
    if (rc < 0)
308
        return -1;
309

310
    return 0;
311 312
}

313

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

338
    if (priv->prDaemonRunning ||
339
        !virStorageSourceChainHasManagedPR(src))
340 341
        return 0;

342
    if (!(props = qemuBuildPRManagedManagerInfoProps(priv)))
343 344
        return -1;

345 346
    if (qemuProcessStartManagedPRDaemon(vm) < 0)
        goto cleanup;
347

348 349 350 351 352 353 354 355 356 357
    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;

358
    ret = 0;
359

360
 cleanup:
361 362
    if (ret < 0 && daemonStarted)
        qemuProcessKillManagedPRDaemon(vm);
363 364
    virJSONValueFree(props);
    return ret;
365 366 367
}


368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
/**
 * 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;
384
    int ret = -1;
385

386
    if (qemuDomainDefHasManagedPR(vm))
387 388
        return 0;

389 390
    virErrorPreserveLast(&orig_err);

391
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
392
        goto cleanup;
393 394
    ignore_value(qemuMonitorDelObject(priv->mon, qemuDomainGetManagedPRAlias()));
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
395
        goto cleanup;
396 397 398

    qemuProcessKillManagedPRDaemon(vm);

399 400 401 402
    ret = 0;
 cleanup:
    virErrorRestore(&orig_err);
    return ret;
403 404 405
}


M
Marc-André Lureau 已提交
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
/**
 * 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;
J
Ján Tomko 已提交
426
    g_autoptr(virJSONValue) props = NULL;
M
Marc-André Lureau 已提交
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
    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;
467
    g_autofree char *alias = qemuAliasDBusVMStateFromId(id);
M
Marc-André Lureau 已提交
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
    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;
}


483 484 485 486 487
/**
 * qemuDomainChangeMediaBlockdev:
 * @driver: qemu driver structure
 * @vm: domain definition
 * @disk: disk definition to change the source of
488
 * @oldsrc: old source definition
489 490 491 492 493 494 495 496 497 498 499 500 501 502
 * @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,
503
                              virStorageSourcePtr oldsrc,
504 505 506 507 508
                              virStorageSourcePtr newsrc,
                              bool force)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
J
Ján Tomko 已提交
509 510
    g_autoptr(qemuBlockStorageSourceChainData) newbackend = NULL;
    g_autoptr(qemuBlockStorageSourceChainData) oldbackend = NULL;
511
    g_autofree char *nodename = NULL;
512 513
    int rc;

514
    if (!virStorageSourceIsEmpty(oldsrc) &&
515
        !(oldbackend = qemuBlockStorageSourceChainDetachPrepareBlockdev(oldsrc)))
516
        return -1;
517

518
    if (!virStorageSourceIsEmpty(newsrc)) {
519 520
        if (!(newbackend = qemuBuildStorageSourceChainAttachPrepareBlockdev(newsrc,
                                                                            priv->qemuCaps)))
521
            return -1;
522 523

        if (qemuDomainDiskGetBackendAlias(disk, priv->qemuCaps, &nodename) < 0)
524
            return -1;
525 526 527 528 529 530
    }

    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)
531
            return -1;
532 533

        if (!force && qemuHotplugWaitForTrayEject(vm, disk) < 0)
534
            return -1;
535 536 537 538 539 540 541
    }

    qemuDomainObjEnterMonitor(driver, vm);

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

    if (rc == 0 && oldbackend)
542
        qemuBlockStorageSourceChainDetach(priv->mon, oldbackend);
543 544 545

    if (newbackend && nodename) {
        if (rc == 0)
546
            rc = qemuBlockStorageSourceChainAttach(priv->mon, newbackend);
547 548 549 550 551 552 553 554 555

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

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

556 557 558
    if (rc < 0 && newbackend)
        qemuBlockStorageSourceChainDetach(priv->mon, newbackend);

559
    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
560
        return -1;
561

562
    return 0;
563 564 565
}


566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
/**
 * 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
 */
581
int
582 583 584 585 586 587
qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainDiskDefPtr disk,
                               virStorageSourcePtr newsrc,
                               bool force)
{
588
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
589
    qemuDomainObjPrivatePtr priv = vm->privateData;
590
    virStorageSourcePtr oldsrc = disk->src;
591
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
592
    bool sharedAdded = false;
593 594 595
    int ret = -1;
    int rc;

596 597 598 599 600 601
    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;
    }

602 603
    disk->src = newsrc;

604 605 606 607 608 609 610 611
    if (virDomainDiskTranslateSourcePool(disk) < 0)
        goto cleanup;

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

    sharedAdded = true;

612
    if (qemuDomainDetermineDiskChain(driver, vm, disk, NULL, true) < 0)
613 614
        goto cleanup;

615 616 617
    if (qemuDomainPrepareDiskSource(disk, priv, cfg) < 0)
        goto cleanup;

618
    if (qemuDomainStorageSourceChainAccessAllow(driver, vm, newsrc) < 0)
619 620
        goto cleanup;

621 622 623
    if (qemuHotplugAttachManagedPR(driver, vm, newsrc, QEMU_ASYNC_JOB_NONE) < 0)
        goto cleanup;

624
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
625
        rc = qemuDomainChangeMediaBlockdev(driver, vm, disk, oldsrc, newsrc, force);
626 627
    else
        rc = qemuDomainChangeMediaLegacy(driver, vm, disk, newsrc, force);
628

629
    virDomainAuditDisk(vm, oldsrc, newsrc, "update", rc >= 0);
630

631
    if (rc < 0)
632 633 634
        goto cleanup;

    /* remove the old source from shared device list */
635
    disk->src = oldsrc;
636
    ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));
637
    ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, oldsrc));
638

639
    /* media was changed, so we can remove the old media definition now */
640
    virObjectUnref(oldsrc);
641 642
    oldsrc = NULL;
    disk->src = newsrc;
643

644 645 646
    ret = 0;

 cleanup:
647 648 649 650 651
    /* undo changes to the new disk */
    if (ret < 0) {
        if (sharedAdded)
            ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));

652
        ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, newsrc));
653 654 655 656 657 658
    }

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

    /* revert old image do the disk definition */
659 660 661
    if (oldsrc)
        disk->src = oldsrc;

662 663 664 665
    return ret;
}


666 667 668 669 670
/**
 * 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. */
671
static int
672
qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
673 674
                            virDomainObjPtr vm,
                            virDomainDiskDefPtr disk)
675
{
J
Ján Tomko 已提交
676
    g_autoptr(qemuBlockStorageSourceChainData) data = NULL;
677
    int ret = -1;
678
    qemuDomainObjPrivatePtr priv = vm->privateData;
679
    g_autofree char *devstr = NULL;
680
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
J
Ján Tomko 已提交
681
    g_autoptr(virJSONValue) corProps = NULL;
682
    g_autofree char *corAlias = NULL;
683
    bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
684

685
    if (qemuDomainStorageSourceChainAccessAllow(driver, vm, disk->src) < 0)
686
        goto cleanup;
687

688
    if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
689
        goto error;
690

691 692 693
    if (qemuDomainPrepareDiskSource(disk, priv, cfg) < 0)
        goto error;

694
    if (blockdev) {
695 696 697 698
        if (disk->copy_on_read == VIR_TRISTATE_SWITCH_ON &&
            !(corProps = qemuBlockStorageGetCopyOnReadProps(disk)))
        goto cleanup;

699 700 701 702 703 704 705 706
        if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdev(disk->src,
                                                                      priv->qemuCaps)))
            goto cleanup;
    } else {
        if (!(data = qemuBuildStorageSourceChainAttachPrepareDrive(disk,
                                                                   priv->qemuCaps)))
            goto cleanup;
    }
707

708
    if (!(devstr = qemuBuildDiskDeviceStr(vm->def, disk, 0, priv->qemuCaps)))
709
        goto error;
710

711
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
712 713
        goto error;

714 715
    if (qemuHotplugAttachManagedPR(driver, vm, disk->src, QEMU_ASYNC_JOB_NONE) < 0)
        goto error;
716

717
    qemuDomainObjEnterMonitor(driver, vm);
718

719
    if (qemuBlockStorageSourceChainAttach(priv->mon, data) < 0)
720
        goto exit_monitor;
721

722 723 724 725
    if (corProps &&
        qemuMonitorAddObject(priv->mon, &corProps, &corAlias) < 0)
        goto exit_monitor;

726 727 728 729 730
    if (qemuDomainAttachExtensionDevice(priv->mon, &disk->info) < 0)
        goto exit_monitor;

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &disk->info));
731
        goto exit_monitor;
732
    }
733

734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
    /* 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);
    }

749
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
750
        ret = -2;
751
        goto error;
752
    }
753

754
    virDomainAuditDisk(vm, NULL, disk->src, "attach", true);
755 756

    virDomainDiskInsertPreAlloced(vm->def, disk);
757
    ret = 0;
758

759
 cleanup:
760
    qemuDomainSecretDiskDestroy(disk);
761
    return ret;
762

763
 exit_monitor:
764 765
    if (corAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, corAlias));
766
    qemuBlockStorageSourceChainDetach(priv->mon, data);
767

768
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
769
        ret = -2;
770 771 772

    if (virStorageSourceChainHasManagedPR(disk->src) &&
        qemuHotplugRemoveManagedPR(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
773
        ret = -2;
774 775 776

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

777
 error:
778
    ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, disk->src));
779
    goto cleanup;
780 781 782
}


783
static int
784
qemuDomainAttachVirtioDiskDevice(virQEMUDriverPtr driver,
785 786 787 788 789 790 791 792 793 794
                                 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;

795
    if ((rv = qemuDomainAttachDiskGeneric(driver, vm, disk)) < 0) {
796
        if (rv == -1 && releaseaddr)
797
            qemuDomainReleaseDeviceAddress(vm, &disk->info);
798 799 800 801 802 803 804 805

        return -1;
    }

    return 0;
}


806 807 808
int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
                                     virDomainObjPtr vm,
                                     virDomainControllerDefPtr controller)
809 810 811
{
    int ret = -1;
    const char* type = virDomainControllerTypeToString(controller->type);
812
    g_autofree char *devstr = NULL;
813
    qemuDomainObjPrivatePtr priv = vm->privateData;
814 815
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CONTROLLER,
                               { .controller = controller } };
816
    bool releaseaddr = false;
817

818 819 820 821 822 823 824
    if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
                       virDomainControllerTypeToString(controller->type));
        return -1;
    }

825 826 827 828 829 830 831 832
    /* 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);

833
    if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) {
834 835 836 837
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target %s:%d already exists"),
                       type, controller->idx);
        return -1;
838 839
    }

840 841
    if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, "controller") < 0)
        return -1;
842

843 844 845
    if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, controller) < 0)
        goto cleanup;

846
    if (qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, &devstr) < 0)
847 848 849
        goto cleanup;

    if (!devstr)
850
        goto cleanup;
851

852
    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0)
853 854
        goto cleanup;

855
    qemuDomainObjEnterMonitor(driver, vm);
856 857 858 859 860 861 862 863 864 865

    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:
866 867 868 869 870
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseaddr = false;
        ret = -1;
        goto cleanup;
    }
871

872
    if (ret == 0)
873 874
        virDomainControllerInsertPreAlloced(vm->def, controller);

875
 cleanup:
876
    if (ret != 0 && releaseaddr)
877
        qemuDomainReleaseDeviceAddress(vm, &controller->info);
878 879 880 881 882

    return ret;
}

static virDomainControllerDefPtr
883
qemuDomainFindOrCreateSCSIDiskController(virQEMUDriverPtr driver,
884
                                         virDomainObjPtr vm,
885
                                         int controller)
886
{
887
    size_t i;
888
    virDomainControllerDefPtr cont;
889
    qemuDomainObjPrivatePtr priv = vm->privateData;
890
    int model = -1;
891

892
    for (i = 0; i < vm->def->ncontrollers; i++) {
893 894 895 896 897 898 899
        cont = vm->def->controllers[i];

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

        if (cont->idx == controller)
            return cont;
900 901 902 903 904 905 906 907 908 909

        /* 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;
910 911 912 913
    }

    /* No SCSI controller present, for backward compatibility we
     * now hotplug a controller */
914
    if (VIR_ALLOC(cont) < 0)
915 916
        return NULL;
    cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
917
    cont->idx = controller;
918
    if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT)
919 920 921
        cont->model = qemuDomainGetSCSIControllerModel(vm->def, cont, priv->qemuCaps);
    else
        cont->model = model;
922

923
    VIR_INFO("No SCSI controller present, hotplugging one model=%s",
924
             virDomainControllerModelSCSITypeToString(cont->model));
925
    if (qemuDomainAttachControllerDevice(driver, vm, cont) < 0) {
926 927 928 929 930
        VIR_FREE(cont);
        return NULL;
    }

    if (!virDomainObjIsActive(vm)) {
931 932
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
933 934 935 936 937 938 939 940 941
        /* cont doesn't need freeing here, since the reference
         * now held in def->controllers */
        return NULL;
    }

    return cont;
}


942
static int
943
qemuDomainAttachSCSIDisk(virQEMUDriverPtr driver,
944 945
                         virDomainObjPtr vm,
                         virDomainDiskDefPtr disk)
946
{
947
    size_t i;
948 949 950

    /* We should have an address already, so make sure */
    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
951 952 953
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk address type %s"),
                       virDomainDeviceAddressTypeToString(disk->info.type));
954
        return -1;
955 956
    }

957 958 959 960 961 962
    if (virDomainSCSIDriveAddressIsUsed(vm->def, &disk->info.addr.drive)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain already contains a disk with that address"));
        return -1;
    }

963 964 965 966 967 968 969 970 971
    /* 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))
972
            return -1;
973
    }
974

975
    if (qemuDomainAttachDiskGeneric(driver, vm, disk) < 0)
976
        return -1;
977

978
    return 0;
979 980 981
}


982
static int
983
qemuDomainAttachUSBMassStorageDevice(virQEMUDriverPtr driver,
984 985
                                     virDomainObjPtr vm,
                                     virDomainDiskDefPtr disk)
986 987
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
988

989 990
    if (virDomainUSBAddressEnsure(priv->usbaddrs, &disk->info) < 0)
        return -1;
991

992
    if (qemuDomainAttachDiskGeneric(driver, vm, disk) < 0) {
993
        virDomainUSBAddressRelease(priv->usbaddrs, &disk->info);
994
        return -1;
995
    }
996

997
    return 0;
998 999 1000
}


1001 1002 1003 1004
static int
qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriverPtr driver,
                                       virDomainObjPtr vm,
                                       virDomainDeviceDefPtr dev)
1005
{
1006
    size_t i;
1007 1008 1009
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

1010 1011 1012 1013 1014 1015 1016
    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;
    }

1017
    if (virDomainDiskTranslateSourcePool(disk) < 0)
1018
        goto cleanup;
1019 1020

    if (qemuAddSharedDevice(driver, dev, vm->def->name) < 0)
1021
        goto cleanup;
1022 1023

    if (qemuSetUnprivSGIO(dev) < 0)
1024
        goto cleanup;
1025

1026
    if (qemuDomainDetermineDiskChain(driver, vm, disk, NULL, true) < 0)
1027
        goto cleanup;
1028

1029 1030 1031 1032
    for (i = 0; i < vm->def->ndisks; i++) {
        if (virDomainDiskDefCheckDuplicateInfo(vm->def->disks[i], disk) < 0)
            goto cleanup;
    }
1033

1034 1035 1036 1037 1038
    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"));
1039
            break;
1040
        }
1041
        ret = qemuDomainAttachUSBMassStorageDevice(driver, vm, disk);
1042
        break;
1043

1044 1045
    case VIR_DOMAIN_DISK_BUS_VIRTIO:
        ret = qemuDomainAttachVirtioDiskDevice(driver, vm, disk);
1046
        break;
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064

    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));
1065 1066
    }

1067
 cleanup:
1068 1069 1070 1071 1072 1073
    if (ret != 0)
        ignore_value(qemuRemoveSharedDevice(driver, dev, vm->def->name));
    return ret;
}


1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
/**
 * 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)
{
1089 1090 1091 1092 1093 1094 1095
    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) &&
1096
        (orig_disk = virDomainDiskByTarget(vm->def, disk->dst))) {
1097 1098 1099 1100 1101 1102 1103 1104
        if (qemuDomainChangeEjectableMedia(driver, vm, orig_disk,
                                           disk->src, false) < 0)
            return -1;

        disk->src = NULL;
        return 0;
    }

1105 1106 1107 1108
    return qemuDomainAttachDeviceDiskLiveInternal(driver, vm, dev);
}


1109 1110 1111
static void
qemuDomainNetDeviceVportRemove(virDomainNetDefPtr net)
{
1112
    const virNetDevVPortProfile *vport = virDomainNetGetActualVirtPortProfile(net);
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
    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));
    }
}


1127 1128 1129 1130
int
qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainNetDefPtr net)
1131 1132
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1133
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_NET, { .net = net } };
1134
    virErrorPtr originalError = NULL;
1135
    g_autofree char *slirpfdName = NULL;
1136
    int slirpfd = -1;
1137 1138
    char **tapfdName = NULL;
    int *tapfd = NULL;
1139
    size_t tapfdSize = 0;
1140 1141
    char **vhostfdName = NULL;
    int *vhostfd = NULL;
1142
    size_t vhostfdSize = 0;
1143
    size_t queueSize = 0;
1144 1145
    g_autofree char *nicstr = NULL;
    g_autofree char *netstr = NULL;
1146
    int ret = -1;
1147
    bool releaseaddr = false;
1148
    bool iface_connected = false;
1149
    virDomainNetType actualType;
1150
    const virNetDevBandwidth *actualBandwidth;
1151
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
1152
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
1153
    size_t i;
1154
    g_autofree char *charDevAlias = NULL;
1155 1156
    bool charDevPlugged = false;
    bool netdevPlugged = false;
1157
    g_autofree char *netdev_name = NULL;
1158
    g_autoptr(virConnect) conn = NULL;
1159
    virErrorPtr save_err = NULL;
1160

1161
    /* preallocate new slot for device */
1162
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
1163
        goto cleanup;
1164

1165 1166 1167 1168
    /* 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.
     */
1169 1170 1171 1172 1173 1174
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        if (!(conn = virGetConnectNetwork()))
            goto cleanup;
        if (virDomainNetAllocateActualDevice(conn, vm->def, net) < 0)
            goto cleanup;
    }
1175

1176 1177
    /* final validation now that we have full info on the type */
    if (qemuDomainValidateActualNetDef(net, priv->qemuCaps) < 0)
1178 1179
        return -1;

1180
    actualType = virDomainNetGetActualType(net);
1181

1182 1183 1184
    if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
        goto cleanup;

1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* 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.
         */
        ret = qemuDomainAttachHostDevice(driver, vm,
                                         virDomainNetGetActualHostdev(net));
        goto cleanup;
    }

1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
    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;

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

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

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
1257 1258 1259
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1260
        queueSize = tapfdSize;
1261
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1262
            goto cleanup;
1263 1264 1265 1266 1267
        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,
1268
                                         tapfd, tapfdSize) < 0)
1269 1270
            goto cleanup;
        iface_connected = true;
J
Ján Tomko 已提交
1271
        if (qemuInterfaceOpenVhostNet(vm->def, net, vhostfd, &vhostfdSize) < 0)
1272
            goto cleanup;
1273 1274 1275
        break;

    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
1276 1277 1278
        queueSize = net->driver.virtio.queues;
        if (!queueSize)
            queueSize = 1;
1279
        if (!qemuDomainSupportsNicdev(vm->def, net)) {
1280
            virReportError(VIR_ERR_INTERNAL_ERROR,
1281
                           "%s", _("Nicdev support unavailable"));
1282 1283 1284
            goto cleanup;
        }

1285
        if (!(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias)))
1286
            goto cleanup;
1287 1288 1289 1290 1291

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

1292 1293 1294
        break;

    case VIR_DOMAIN_NET_TYPE_USER:
1295
        if (!priv->disableSlirp &&
1296
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DBUS_VMSTATE)) {
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311
            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);
1312
            slirpfdName = g_strdup_printf("slirpfd-%s", net->info.alias);
1313
        }
1314 1315
        break;

1316 1317 1318 1319
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
        /* hostdev interfaces were handled earlier in this function */
        break;

1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
    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;
1330 1331
    }

1332 1333
    /* Set device online immediately */
    if (qemuInterfaceStartDevice(net) < 0)
1334
        goto cleanup;
1335

1336 1337 1338 1339
    /* Set bandwidth or warn if requested and not supported. */
    actualBandwidth = virDomainNetGetActualBandwidth(net);
    if (actualBandwidth) {
        if (virNetDevSupportBandwidth(actualType)) {
1340 1341
            if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false,
                                      !virDomainNetTypeSharesHostView(net)) < 0)
1342 1343 1344 1345 1346 1347 1348
                goto cleanup;
        } else {
            VIR_WARN("setting bandwidth on interfaces of "
                     "type '%s' is not implemented yet",
                     virDomainNetTypeToString(actualType));
        }
    }
1349

1350 1351 1352 1353
    if (net->mtu &&
        virNetDevSetMTU(net->ifname, net->mtu) < 0)
        goto cleanup;

M
Michal Privoznik 已提交
1354
    for (i = 0; i < tapfdSize; i++) {
1355 1356
        if (qemuSecuritySetTapFDLabel(driver->securityManager,
                                      vm->def, tapfd[i]) < 0)
M
Michal Privoznik 已提交
1357 1358 1359
            goto cleanup;
    }

1360
    if (VIR_ALLOC_N(tapfdName, tapfdSize) < 0 ||
1361
        VIR_ALLOC_N(vhostfdName, vhostfdSize) < 0)
1362 1363
        goto cleanup;

1364 1365
    for (i = 0; i < tapfdSize; i++)
        tapfdName[i] = g_strdup_printf("fd-%s%zu", net->info.alias, i);
1366

1367 1368
    for (i = 0; i < vhostfdSize; i++)
        vhostfdName[i] = g_strdup_printf("vhostfd-%s%zu", net->info.alias, i);
1369

1370
    if (!(netstr = qemuBuildHostNetStr(net,
J
Ján Tomko 已提交
1371
                                       tapfdName, tapfdSize,
1372
                                       vhostfdName, vhostfdSize,
1373
                                       slirpfdName)))
J
Ján Tomko 已提交
1374
        goto cleanup;
1375

1376
    qemuDomainObjEnterMonitor(driver, vm);
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386

    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 已提交
1387 1388
    if (qemuMonitorAddNetdev(priv->mon, netstr,
                             tapfd, tapfdName, tapfdSize,
1389 1390
                             vhostfd, vhostfdName, vhostfdSize,
                             slirpfd, slirpfdName) < 0) {
J
Ján Tomko 已提交
1391 1392 1393
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto try_remove;
1394
    }
J
Ján Tomko 已提交
1395
    netdevPlugged = true;
1396

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

1400 1401 1402 1403
    for (i = 0; i < tapfdSize; i++)
        VIR_FORCE_CLOSE(tapfd[i]);
    for (i = 0; i < vhostfdSize; i++)
        VIR_FORCE_CLOSE(vhostfd[i]);
1404

1405
    if (!(nicstr = qemuBuildNicDevStr(vm->def, net, 0,
1406
                                      queueSize, priv->qemuCaps)))
1407
        goto try_remove;
1408

1409
    qemuDomainObjEnterMonitor(driver, vm);
1410 1411 1412 1413 1414 1415 1416

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

1417
    if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
1418
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &net->info));
1419 1420 1421
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto try_remove;
1422
    }
1423 1424
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
1425

1426 1427 1428
    /* set link state */
    if (net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
        if (!net->info.alias) {
1429 1430
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("device alias not found: cannot set link state to down"));
1431
        } else {
1432
            qemuDomainObjEnterMonitor(driver, vm);
1433

J
Ján Tomko 已提交
1434 1435 1436 1437
            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;
1438 1439
            }

1440 1441
            if (qemuDomainObjExitMonitor(driver, vm) < 0)
                goto cleanup;
1442 1443 1444 1445
        }
        /* link set to down */
    }

1446
    virDomainAuditNet(vm, NULL, net, "attach", true);
1447 1448 1449

    ret = 0;

1450
 cleanup:
1451 1452 1453
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else {
1454
        virErrorPreserveLast(&save_err);
1455
        if (releaseaddr)
1456
            qemuDomainReleaseDeviceAddress(vm, &net->info);
1457

1458
        if (iface_connected) {
1459
            virErrorPreserveLast(&originalError);
1460
            virDomainConfNWFilterTeardown(net);
1461
            virErrorRestore(&originalError);
1462

1463 1464 1465 1466 1467 1468 1469 1470 1471
            if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
                ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
                                 net->ifname, &net->mac,
                                 virDomainNetGetActualDirectDev(net),
                                 virDomainNetGetActualDirectMode(net),
                                 virDomainNetGetActualVirtPortProfile(net),
                                 cfg->stateDir));
            }

1472
            qemuDomainNetDeviceVportRemove(net);
1473
        }
A
Ansis Atteka 已提交
1474

1475 1476
        virDomainNetRemoveHostdev(vm->def, net);

1477 1478 1479 1480 1481 1482
        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));
        }
1483
        virErrorRestore(&save_err);
1484
    }
1485

1486
    for (i = 0; tapfd && i < tapfdSize; i++) {
1487
        VIR_FORCE_CLOSE(tapfd[i]);
1488 1489
        if (tapfdName)
            VIR_FREE(tapfdName[i]);
1490 1491 1492
    }
    VIR_FREE(tapfd);
    VIR_FREE(tapfdName);
1493
    for (i = 0; vhostfd && i < vhostfdSize; i++) {
1494
        VIR_FORCE_CLOSE(vhostfd[i]);
1495 1496
        if (vhostfdName)
            VIR_FREE(vhostfdName[i]);
1497 1498 1499
    }
    VIR_FREE(vhostfd);
    VIR_FREE(vhostfdName);
1500
    virDomainCCWAddressSetFree(ccwaddrs);
1501
    VIR_FORCE_CLOSE(slirpfd);
1502 1503 1504

    return ret;

1505
 try_remove:
1506 1507 1508
    if (!virDomainObjIsActive(vm))
        goto cleanup;

1509
    virErrorPreserveLast(&originalError);
1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
    netdev_name = g_strdup_printf("host%s", net->info.alias);
    if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
        qemuSlirpStop(QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp, vm, driver, net, true);
    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));
1522
    virErrorRestore(&originalError);
1523 1524 1525 1526
    goto cleanup;
}


1527
static int
1528
qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
1529 1530
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
1531 1532
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1533 1534
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                               { .hostdev = hostdev } };
1535
    virDomainDeviceInfoPtr info = hostdev->info;
1536
    int ret;
1537
    g_autofree char *devstr = NULL;
1538
    bool releaseaddr = false;
1539
    bool teardowncgroup = false;
1540
    bool teardownlabel = false;
1541
    bool teardowndevice = false;
1542
    bool teardownmemlock = false;
1543
    int backend;
1544
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
1545
    unsigned int flags = 0;
1546

1547
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
1548
        return -1;
1549

1550 1551
    if (!cfg->relaxedACS)
        flags |= VIR_HOSTDEV_STRICT_ACS_CHECK;
1552
    if (qemuHostdevPreparePCIDevices(driver, vm->def->name, vm->def->uuid,
1553
                                     &hostdev, 1, priv->qemuCaps, flags) < 0)
1554
        return -1;
1555

1556
    /* this could have been changed by qemuHostdevPreparePCIDevices */
1557 1558
    backend = hostdev->source.subsys.u.pci.backend;

1559
    switch ((virDomainHostdevSubsysPCIBackendType)backend) {
1560
    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
1561 1562 1563 1564 1565 1566
        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;
        }
1567 1568
        break;

1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
    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;
1579
        break;
1580 1581
    }

1582
    if (qemuDomainAdjustMaxMemLockHostdev(vm, hostdev) < 0)
1583
        goto error;
1584
    teardownmemlock = true;
1585

1586
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
1587 1588 1589
        goto error;
    teardowndevice = true;

1590
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
1591 1592 1593
        goto error;
    teardowncgroup = true;

1594
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
1595
        goto error;
1596 1597
    if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
        teardownlabel = true;
1598

1599
    if (qemuAssignDeviceHostdevAlias(vm->def, &info->alias, -1) < 0)
1600
        goto error;
1601 1602 1603 1604 1605 1606 1607

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

1608
    if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
1609 1610
        goto error;
    releaseaddr = true;
1611

1612 1613 1614 1615 1616
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit during hotplug"));
        goto error;
    }
1617

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

1621
    qemuDomainObjEnterMonitor(driver, vm);
1622 1623 1624 1625

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

M
Michal Privoznik 已提交
1626
    if ((ret = qemuMonitorAddDevice(priv->mon, devstr)) < 0)
1627 1628 1629
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, hostdev->info));

 exit_monitor:
1630 1631
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto error;
1632

1633
    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
1634 1635 1636 1637 1638 1639 1640
    if (ret < 0)
        goto error;

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

    return 0;

1641
 error:
1642 1643
    if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
        VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
1644
    if (teardownlabel &&
1645
        qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
1646
        VIR_WARN("Unable to restore host device labelling on hotplug fail");
1647
    if (teardowndevice &&
1648
        qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
1649
        VIR_WARN("Unable to remove host device from /dev");
1650 1651
    if (teardownmemlock && qemuDomainAdjustMaxMemLock(vm) < 0)
        VIR_WARN("Unable to reset maximum locked memory on hotplug fail");
1652

1653
    if (releaseaddr)
1654
        qemuDomainReleaseDeviceAddress(vm, info);
1655

1656
    qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
1657 1658 1659 1660 1661

    return -1;
}


1662 1663 1664
void
qemuDomainDelTLSObjects(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
1665
                        qemuDomainAsyncJob asyncJob,
1666 1667 1668 1669 1670 1671 1672 1673 1674
                        const char *secAlias,
                        const char *tlsAlias)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virErrorPtr orig_err;

    if (!tlsAlias && !secAlias)
        return;

1675
    virErrorPreserveLast(&orig_err);
1676

1677 1678
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;
1679 1680 1681 1682 1683 1684 1685 1686 1687

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

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

    ignore_value(qemuDomainObjExitMonitor(driver, vm));

1688
 cleanup:
1689
    virErrorRestore(&orig_err);
1690 1691 1692 1693 1694 1695
}


int
qemuDomainAddTLSObjects(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
1696
                        qemuDomainAsyncJob asyncJob,
1697 1698 1699 1700 1701
                        virJSONValuePtr *secProps,
                        virJSONValuePtr *tlsProps)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virErrorPtr orig_err;
1702
    g_autofree char *secAlias = NULL;
1703

1704
    if (!tlsProps && !secProps)
1705 1706
        return 0;

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

1710
    if (secProps && *secProps &&
1711 1712
        qemuMonitorAddObject(priv->mon, secProps, &secAlias) < 0)
        goto error;
1713

1714 1715 1716
    if (tlsProps &&
        qemuMonitorAddObject(priv->mon, tlsProps, NULL) < 0)
        goto error;
1717 1718 1719 1720

    return qemuDomainObjExitMonitor(driver, vm);

 error:
1721
    virErrorPreserveLast(&orig_err);
1722
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
1723
    virErrorRestore(&orig_err);
1724
    qemuDomainDelTLSObjects(driver, vm, asyncJob, secAlias, NULL);
1725 1726 1727 1728 1729

    return -1;
}


1730 1731 1732 1733 1734 1735
int
qemuDomainGetTLSObjects(virQEMUCapsPtr qemuCaps,
                        qemuDomainSecretInfoPtr secinfo,
                        const char *tlsCertdir,
                        bool tlsListen,
                        bool tlsVerify,
1736
                        const char *alias,
1737
                        virJSONValuePtr *tlsProps,
1738
                        virJSONValuePtr *secProps)
1739
{
1740 1741
    const char *secAlias = NULL;

1742 1743
    if (secinfo) {
        if (qemuBuildSecretInfoProps(secinfo, secProps) < 0)
1744 1745
            return -1;

1746
        secAlias = secinfo->s.aes.alias;
1747 1748
    }

1749
    if (qemuBuildTLSx509BackendProps(tlsCertdir, tlsListen, tlsVerify,
1750
                                     alias, secAlias, qemuCaps, tlsProps) < 0)
1751 1752 1753 1754 1755 1756
        return -1;

    return 0;
}


1757
static int
1758
qemuDomainAddChardevTLSObjects(virQEMUDriverPtr driver,
1759 1760
                               virDomainObjPtr vm,
                               virDomainChrSourceDefPtr dev,
1761
                               char *devAlias,
1762 1763
                               char *charAlias,
                               char **tlsAlias,
1764
                               const char **secAlias)
1765 1766
{
    int ret = -1;
1767
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
1768
    qemuDomainObjPrivatePtr priv = vm->privateData;
1769 1770
    qemuDomainChrSourcePrivatePtr chrSourcePriv;
    qemuDomainSecretInfoPtr secinfo = NULL;
1771 1772 1773
    virJSONValuePtr tlsProps = NULL;
    virJSONValuePtr secProps = NULL;

1774 1775 1776
    /* NB: This may alter haveTLS based on cfg */
    qemuDomainPrepareChardevSourceTLS(dev, cfg);

1777
    if (dev->type != VIR_DOMAIN_CHR_TYPE_TCP ||
1778 1779 1780 1781
        dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_YES) {
        ret = 0;
        goto cleanup;
    }
1782

1783
    if (qemuDomainSecretChardevPrepare(cfg, priv, devAlias, dev) < 0)
1784 1785
        goto cleanup;

1786 1787 1788
    if ((chrSourcePriv = QEMU_DOMAIN_CHR_SOURCE_PRIVATE(dev)))
        secinfo = chrSourcePriv->secinfo;

1789 1790 1791
    if (secinfo)
        *secAlias = secinfo->s.aes.alias;

1792 1793 1794
    if (!(*tlsAlias = qemuAliasTLSObjFromSrcAlias(charAlias)))
        goto cleanup;

1795 1796 1797 1798
    if (qemuDomainGetTLSObjects(priv->qemuCaps, secinfo,
                                cfg->chardevTLSx509certdir,
                                dev->data.tcp.listen,
                                cfg->chardevTLSx509verify,
1799
                                *tlsAlias, &tlsProps, &secProps) < 0)
1800
        goto cleanup;
1801
    dev->data.tcp.tlscreds = true;
1802

1803
    if (qemuDomainAddTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
1804
                                &secProps, &tlsProps) < 0)
1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816
        goto cleanup;

    ret = 0;

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

    return ret;
}


1817 1818 1819
static int
qemuDomainDelChardevTLSObjects(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
1820
                               virDomainChrSourceDefPtr dev,
1821 1822
                               const char *inAlias)
{
1823
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
1824
    qemuDomainObjPrivatePtr priv = vm->privateData;
1825 1826
    g_autofree char *tlsAlias = NULL;
    g_autofree char *secAlias = NULL;
1827

1828 1829
    if (dev->type != VIR_DOMAIN_CHR_TYPE_TCP ||
        dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_YES) {
1830
        return 0;
1831 1832
    }

1833
    if (!(tlsAlias = qemuAliasTLSObjFromSrcAlias(inAlias)))
1834
        return -1;
1835 1836 1837 1838 1839 1840 1841

    /* 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)))
1842
        return -1;
1843 1844 1845 1846 1847 1848 1849 1850

    qemuDomainObjEnterMonitor(driver, vm);

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

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

1853
    return 0;
1854 1855 1856
}


1857
int qemuDomainAttachRedirdevDevice(virQEMUDriverPtr driver,
1858 1859 1860
                                   virDomainObjPtr vm,
                                   virDomainRedirdevDefPtr redirdev)
{
1861
    int ret = -1;
1862
    qemuDomainObjPrivatePtr priv = vm->privateData;
1863
    virDomainDefPtr def = vm->def;
1864 1865
    g_autofree char *charAlias = NULL;
    g_autofree char *devstr = NULL;
1866
    bool chardevAdded = false;
1867
    g_autofree char *tlsAlias = NULL;
1868
    const char *secAlias = NULL;
1869
    bool need_release = false;
1870
    virErrorPtr orig_err;
1871

1872
    if (qemuAssignDeviceRedirdevAlias(def, redirdev, -1) < 0)
1873 1874
        goto cleanup;

1875
    if (!(charAlias = qemuAliasChardevFromDevAlias(redirdev->info.alias)))
1876 1877
        goto cleanup;

1878
    if ((virDomainUSBAddressEnsure(priv->usbaddrs, &redirdev->info)) < 0)
1879
        goto cleanup;
1880
    need_release = true;
1881

1882
    if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, priv->qemuCaps)))
1883
        goto cleanup;
1884

1885
    if (VIR_REALLOC_N(def->redirdevs, def->nredirdevs+1) < 0)
1886
        goto cleanup;
1887

1888
    if (qemuDomainAddChardevTLSObjects(driver, vm, redirdev->source,
1889 1890
                                       redirdev->info.alias, charAlias,
                                       &tlsAlias, &secAlias) < 0)
1891
        goto audit;
1892

1893
    qemuDomainObjEnterMonitor(driver, vm);
1894

1895 1896
    if (qemuMonitorAttachCharDev(priv->mon,
                                 charAlias,
1897
                                 redirdev->source) < 0)
1898 1899
        goto exit_monitor;
    chardevAdded = true;
1900

1901 1902
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
        goto exit_monitor;
1903

1904 1905
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto audit;
1906

1907
    def->redirdevs[def->nredirdevs++] = redirdev;
1908 1909 1910 1911
    ret = 0;
 audit:
    virDomainAuditRedirdev(vm, redirdev, "attach", ret == 0);
 cleanup:
1912
    if (ret < 0 && need_release)
1913
        qemuDomainReleaseDeviceAddress(vm, &redirdev->info);
1914
    return ret;
1915 1916

 exit_monitor:
1917
    virErrorPreserveLast(&orig_err);
1918 1919 1920
    /* detach associated chardev on error */
    if (chardevAdded)
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
1921
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
1922
    virErrorRestore(&orig_err);
1923 1924
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
1925
    goto audit;
1926 1927
}

1928 1929 1930
static int
qemuDomainChrPreInsert(virDomainDefPtr vmdef,
                       virDomainChrDefPtr chr)
1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944
{
    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;
    }

1945
    if (virDomainChrPreAlloc(vmdef, chr) < 0)
1946 1947
        return -1;

1948 1949 1950 1951
    /* 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.
     */
1952 1953 1954 1955 1956
    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;

1957 1958
        /* We'll be dealing with serials[0] directly, so NULL is fine here. */
        if (!(vmdef->consoles[0] = virDomainChrDefNew(NULL))) {
1959
            VIR_FREE(vmdef->consoles);
1960 1961
            return -1;
        }
1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973
        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) {
1974 1975 1976 1977 1978 1979
        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;
    }
1980 1981 1982 1983 1984 1985 1986 1987 1988
}

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) {
1989
        virDomainChrDefFree(vmdef->consoles[0]);
1990 1991 1992 1993
        VIR_FREE(vmdef->consoles);
        vmdef->nconsoles = 0;
    }
}
1994

1995 1996 1997 1998 1999 2000 2001 2002 2003
int
qemuDomainChrInsert(virDomainDefPtr vmdef,
                    virDomainChrDefPtr chr)
{
    if (qemuDomainChrPreInsert(vmdef, chr) < 0) {
        qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
        return -1;
    }
    qemuDomainChrInsertPreAlloced(vmdef, chr);
2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039
    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;
}
2040

2041 2042 2043 2044
/* Returns  1 if the address will need to be released later,
 *         -1 on error
 *          0 otherwise
 */
2045
static int
2046
qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm,
2047 2048
                                    virDomainChrDefPtr chr,
                                    virQEMUDriverPtr driver)
2049
{
2050 2051
    virDomainDefPtr def = vm->def;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2052
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CHR, { .chr = chr } };
2053

2054 2055
    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
2056
        if (virDomainVirtioSerialAddrAutoAssign(def, &chr->info, true) < 0)
2057
            return -1;
2058
        return 0;
2059 2060 2061

    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
               chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) {
2062
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
2063 2064
            return -1;
        return 1;
2065

2066
    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
2067 2068
               chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB) {
        if (virDomainUSBAddressEnsure(priv->usbaddrs, &chr->info) < 0)
2069 2070
            return -1;
        return 1;
2071

2072 2073
    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
               chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
2074
        if (virDomainVirtioSerialAddrAutoAssign(def, &chr->info, false) < 0)
2075
            return -1;
2076
        return 0;
2077 2078 2079 2080 2081 2082
    }

    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"));
2083
        return -1;
2084 2085
    }

2086
    return 0;
2087 2088
}

2089
int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
2090 2091 2092
                              virDomainObjPtr vm,
                              virDomainChrDefPtr chr)
{
2093
    int ret = -1, rc;
2094
    qemuDomainObjPrivatePtr priv = vm->privateData;
2095
    virErrorPtr orig_err;
2096
    virDomainDefPtr vmdef = vm->def;
2097
    g_autofree char *devstr = NULL;
2098
    virDomainChrSourceDefPtr dev = chr->source;
2099
    g_autofree char *charAlias = NULL;
2100
    bool chardevAttached = false;
2101
    bool teardowncgroup = false;
2102
    bool teardowndevice = false;
2103
    bool teardownlabel = false;
2104
    g_autofree char *tlsAlias = NULL;
2105
    const char *secAlias = NULL;
2106
    bool need_release = false;
2107
    bool guestfwd = false;
2108

2109 2110 2111 2112 2113 2114
    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;
    }
2115

2116
    if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0)
2117
        goto cleanup;
2118

2119
    if ((rc = qemuDomainAttachChrDeviceAssignAddr(vm, chr, driver)) < 0)
2120 2121 2122
        goto cleanup;
    if (rc == 1)
        need_release = true;
2123

2124
    if (qemuDomainNamespaceSetupChardev(vm, chr) < 0)
2125 2126 2127
        goto cleanup;
    teardowndevice = true;

2128 2129 2130 2131
    if (qemuSecuritySetChardevLabel(driver, vm, chr) < 0)
        goto cleanup;
    teardownlabel = true;

2132 2133 2134 2135
    if (qemuSetupChardevCgroup(vm, chr) < 0)
        goto cleanup;
    teardowncgroup = true;

2136
    if (qemuBuildChrDeviceStr(&devstr, vmdef, chr, priv->qemuCaps) < 0)
2137
        goto cleanup;
2138

2139
    if (!(charAlias = qemuAliasChardevFromDevAlias(chr->info.alias)))
2140 2141
        goto cleanup;

2142
    if (qemuDomainChrPreInsert(vmdef, chr) < 0)
2143 2144
        goto cleanup;

2145
    if (qemuDomainAddChardevTLSObjects(driver, vm, dev,
2146
                                       chr->info.alias, charAlias,
2147
                                       &tlsAlias, &secAlias) < 0)
2148
        goto audit;
2149

2150
    qemuDomainObjEnterMonitor(driver, vm);
2151

2152
    if (qemuMonitorAttachCharDev(priv->mon, charAlias, chr->source) < 0)
2153 2154
        goto exit_monitor;
    chardevAttached = true;
2155

2156 2157
    if (guestfwd) {
        if (qemuMonitorAddNetdev(priv->mon, devstr,
2158
                                 NULL, NULL, 0, NULL, NULL, 0, -1, NULL) < 0)
2159 2160 2161 2162 2163
            goto exit_monitor;
    } else {
        if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
            goto exit_monitor;
    }
2164

2165 2166
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto audit;
2167

2168
    qemuDomainChrInsertPreAlloced(vmdef, chr);
2169
    ret = 0;
2170 2171
 audit:
    virDomainAuditChardev(vm, NULL, chr, "attach", ret == 0);
2172
 cleanup:
2173 2174 2175 2176
    if (ret < 0) {
        if (virDomainObjIsActive(vm))
            qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
        if (need_release)
2177
            qemuDomainReleaseDeviceAddress(vm, &chr->info);
2178 2179
        if (teardowncgroup && qemuTeardownChardevCgroup(vm, chr) < 0)
            VIR_WARN("Unable to remove chr device cgroup ACL on hotplug fail");
2180 2181
        if (teardownlabel && qemuSecurityRestoreChardevLabel(driver, vm, chr) < 0)
            VIR_WARN("Unable to restore security label on char device");
2182
        if (teardowndevice && qemuDomainNamespaceTeardownChardev(vm, chr) < 0)
2183
            VIR_WARN("Unable to remove chr device from /dev");
2184
    }
2185
    return ret;
2186

2187
 exit_monitor:
2188
    virErrorPreserveLast(&orig_err);
2189
    /* detach associated chardev on error */
2190 2191
    if (chardevAttached)
        qemuMonitorDetachCharDev(priv->mon, charAlias);
2192
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2193
    virErrorRestore(&orig_err);
2194

2195 2196
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2197
    goto audit;
2198 2199
}

2200 2201

int
2202
qemuDomainAttachRNGDevice(virQEMUDriverPtr driver,
2203 2204 2205 2206
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2207
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_RNG, { .rng = rng } };
2208
    virErrorPtr orig_err;
2209 2210 2211 2212
    g_autofree char *devstr = NULL;
    g_autofree char *charAlias = NULL;
    g_autofree char *objAlias = NULL;
    g_autofree char *tlsAlias = NULL;
2213
    const char *secAlias = NULL;
2214
    bool releaseaddr = false;
2215
    bool teardowncgroup = false;
2216
    bool teardowndevice = false;
2217
    bool chardevAdded = false;
2218 2219 2220
    virJSONValuePtr props = NULL;
    int ret = -1;

2221
    if (qemuAssignDeviceRNGAlias(vm->def, rng) < 0)
2222
        goto cleanup;
2223 2224 2225

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

2228 2229
    if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, "rng") < 0)
        return -1;
2230

2231
    if (qemuDomainNamespaceSetupRNG(vm, rng) < 0)
2232 2233 2234
        goto cleanup;
    teardowndevice = true;

2235 2236 2237 2238
    if (qemuSetupRNGCgroup(vm, rng) < 0)
        goto cleanup;
    teardowncgroup = true;

2239 2240 2241 2242
    /* build required metadata */
    if (!(devstr = qemuBuildRNGDevStr(vm->def, rng, priv->qemuCaps)))
        goto cleanup;

2243
    if (qemuBuildRNGBackendProps(rng, priv->qemuCaps, &props) < 0)
2244 2245
        goto cleanup;

2246
    if (!(charAlias = qemuAliasChardevFromDevAlias(rng->info.alias)))
2247 2248
        goto cleanup;

2249
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD) {
2250
        if (qemuDomainAddChardevTLSObjects(driver, vm,
2251 2252 2253
                                           rng->source.chardev,
                                           rng->info.alias, charAlias,
                                           &tlsAlias, &secAlias) < 0)
2254
            goto audit;
2255 2256
    }

2257
    qemuDomainObjEnterMonitor(driver, vm);
2258

2259 2260 2261
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
        qemuMonitorAttachCharDev(priv->mon, charAlias,
                                 rng->source.chardev) < 0)
2262 2263
        goto exit_monitor;
    chardevAdded = true;
2264

2265
    if (qemuMonitorAddObject(priv->mon, &props, &objAlias) < 0)
2266
        goto exit_monitor;
2267

2268
    if (qemuDomainAttachExtensionDevice(priv->mon, &rng->info) < 0)
2269
        goto exit_monitor;
2270

2271 2272 2273 2274 2275
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &rng->info));
        goto exit_monitor;
    }

2276
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
2277
        releaseaddr = false;
2278 2279 2280
        goto cleanup;
    }

2281
    VIR_APPEND_ELEMENT_INPLACE(vm->def->rngs, vm->def->nrngs, rng);
2282 2283 2284 2285 2286 2287

    ret = 0;

 audit:
    virDomainAuditRNG(vm, NULL, rng, "attach", ret == 0);
 cleanup:
2288
    virJSONValueFree(props);
2289 2290
    if (ret < 0) {
        if (releaseaddr)
2291
            qemuDomainReleaseDeviceAddress(vm, &rng->info);
2292 2293
        if (teardowncgroup && qemuTeardownRNGCgroup(vm, rng) < 0)
            VIR_WARN("Unable to remove RNG device cgroup ACL on hotplug fail");
2294
        if (teardowndevice && qemuDomainNamespaceTeardownRNG(vm, rng) < 0)
2295
            VIR_WARN("Unable to remove chr device from /dev");
2296 2297
    }

2298 2299
    return ret;

2300
 exit_monitor:
2301
    virErrorPreserveLast(&orig_err);
2302
    if (objAlias)
2303 2304
        ignore_value(qemuMonitorDelObject(priv->mon, objAlias));
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD && chardevAdded)
2305
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
2306 2307
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        releaseaddr = false;
2308
    virErrorRestore(&orig_err);
2309

2310 2311
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2312 2313 2314 2315
    goto audit;
}


2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331
/**
 * 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;
2332
    virErrorPtr orig_err;
2333
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
2334
    unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
2335
    unsigned long long newmem = oldmem + mem->size;
2336 2337
    g_autofree char *devstr = NULL;
    g_autofree char *objalias = NULL;
2338
    bool objAdded = false;
M
Michal Privoznik 已提交
2339
    bool teardownlabel = false;
2340
    bool teardowncgroup = false;
M
Michal Privoznik 已提交
2341
    bool teardowndevice = false;
2342
    virJSONValuePtr props = NULL;
2343
    virObjectEventPtr event;
2344 2345 2346
    int id;
    int ret = -1;

2347 2348 2349
    qemuDomainMemoryDeviceAlignSize(vm->def, mem);

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

2352 2353 2354
    if (qemuDomainAssignMemoryDeviceSlot(vm->def, mem) < 0)
        goto cleanup;

2355 2356 2357
    /* 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)
2358 2359
        goto cleanup;

2360
    objalias = g_strdup_printf("mem%s", mem->info.alias);
2361

2362
    if (!(devstr = qemuBuildMemoryDeviceStr(mem, priv)))
2363 2364
        goto cleanup;

2365
    if (qemuBuildMemoryBackendProps(&props, objalias, cfg,
2366
                                    priv, vm->def, mem, true) < 0)
2367 2368
        goto cleanup;

2369
    if (qemuProcessBuildDestroyMemoryPaths(driver, vm, mem, true) < 0)
2370 2371
        goto cleanup;

2372
    if (qemuDomainNamespaceSetupMemory(vm, mem) < 0)
M
Michal Privoznik 已提交
2373 2374 2375
        goto cleanup;
    teardowndevice = true;

2376 2377 2378 2379
    if (qemuSetupMemoryDevicesCgroup(vm, mem) < 0)
        goto cleanup;
    teardowncgroup = true;

M
Michal Privoznik 已提交
2380
    if (qemuSecuritySetMemoryLabel(driver, vm, mem) < 0)
2381
        goto cleanup;
M
Michal Privoznik 已提交
2382
    teardownlabel = true;
2383

M
Michal Privoznik 已提交
2384 2385 2386 2387
    if (virDomainMemoryInsert(vm->def, mem) < 0)
        goto cleanup;

    if (qemuDomainAdjustMaxMemLock(vm) < 0)
2388 2389
        goto removedef;

2390
    qemuDomainObjEnterMonitor(driver, vm);
2391
    if (qemuMonitorAddObject(priv->mon, &props, NULL) < 0)
2392
        goto exit_monitor;
2393
    objAdded = true;
2394

2395
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2396
        goto exit_monitor;
2397 2398 2399 2400

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

2404
    event = virDomainEventDeviceAddedNewFromObj(vm, objalias);
2405
    virObjectEventStateQueue(driver->domainEventState, event);
2406

2407 2408
    /* fix the balloon size */
    ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));
2409

2410 2411 2412 2413 2414 2415 2416 2417 2418
    /* 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;

2419 2420
 audit:
    virDomainAuditMemory(vm, oldmem, newmem, "update", ret == 0);
2421
 cleanup:
M
Michal Privoznik 已提交
2422
    if (mem && ret < 0) {
2423 2424
        if (teardowncgroup && qemuTeardownMemoryDevicesCgroup(vm, mem) < 0)
            VIR_WARN("Unable to remove memory device cgroup ACL on hotplug fail");
M
Michal Privoznik 已提交
2425 2426
        if (teardownlabel && qemuSecurityRestoreMemoryLabel(driver, vm, mem) < 0)
            VIR_WARN("Unable to restore security label on memdev");
M
Michal Privoznik 已提交
2427
        if (teardowndevice &&
2428
            qemuDomainNamespaceTeardownMemory(vm, mem) <  0)
M
Michal Privoznik 已提交
2429
            VIR_WARN("Unable to remove memory device from /dev");
M
Michal Privoznik 已提交
2430 2431 2432
    }

    virJSONValueFree(props);
2433 2434 2435
    virDomainMemoryDefFree(mem);
    return ret;

2436
 exit_monitor:
2437
    virErrorPreserveLast(&orig_err);
2438 2439
    if (objAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, objalias));
2440 2441
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        mem = NULL;
2442 2443 2444 2445

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

2446
    virErrorRestore(&orig_err);
2447
    if (!mem)
2448
        goto audit;
2449

2450
 removedef:
2451 2452 2453 2454 2455
    if ((id = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
        mem = virDomainMemoryRemove(vm->def, id);
    else
        mem = NULL;

2456
    /* reset the mlock limit */
2457
    virErrorPreserveLast(&orig_err);
2458
    ignore_value(qemuDomainAdjustMaxMemLock(vm));
2459
    virErrorRestore(&orig_err);
2460

2461
    goto audit;
2462 2463 2464
}


2465
static int
2466
qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
2467 2468
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
2469 2470
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2471
    g_autofree char *devstr = NULL;
2472
    bool added = false;
2473
    bool teardowncgroup = false;
2474
    bool teardownlabel = false;
2475
    bool teardowndevice = false;
2476 2477
    int ret = -1;

2478 2479
    if (virDomainUSBAddressEnsure(priv->usbaddrs, hostdev->info) < 0)
        return -1;
2480

2481
    if (qemuHostdevPrepareUSBDevices(driver, vm->def->name, &hostdev, 1, 0) < 0)
2482 2483 2484
        goto cleanup;

    added = true;
2485

2486
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2487 2488 2489
        goto cleanup;
    teardowndevice = true;

2490
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
2491 2492 2493
        goto cleanup;
    teardowncgroup = true;

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

2498 2499 2500 2501
    if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
        goto cleanup;
    if (!(devstr = qemuBuildUSBHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
        goto cleanup;
2502

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

2506
    qemuDomainObjEnterMonitor(driver, vm);
2507
    ret = qemuMonitorAddDevice(priv->mon, devstr);
2508 2509 2510 2511
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        ret = -1;
        goto cleanup;
    }
2512
    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
2513
    if (ret < 0)
2514
        goto cleanup;
2515 2516 2517

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

2518
    ret = 0;
2519
 cleanup:
2520 2521 2522 2523
    if (ret < 0) {
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
        if (teardownlabel &&
2524
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2525
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2526
        if (teardowndevice &&
2527
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2528
            VIR_WARN("Unable to remove host device from /dev");
2529
        if (added)
2530
            qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
2531
        virDomainUSBAddressRelease(priv->usbaddrs, hostdev->info);
2532
    }
2533
    return ret;
2534 2535
}

2536

2537
static int
2538
qemuDomainAttachHostSCSIDevice(virQEMUDriverPtr driver,
2539 2540 2541
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
2542
    size_t i;
2543 2544
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2545
    virErrorPtr orig_err;
2546 2547 2548 2549
    g_autofree char *devstr = NULL;
    g_autofree char *drvstr = NULL;
    g_autofree char *drivealias = NULL;
    g_autofree char *secobjAlias = NULL;
2550
    bool teardowncgroup = false;
2551
    bool teardownlabel = false;
2552
    bool teardowndevice = false;
2553
    bool driveAdded = false;
2554 2555
    virJSONValuePtr secobjProps = NULL;
    virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
2556
    qemuDomainSecretInfoPtr secinfo = NULL;
2557

2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568
    /* 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;
    }
2569

2570
    if (qemuHostdevPrepareSCSIDevices(driver, vm->def->name, &hostdev, 1) < 0)
2571 2572
        return -1;

2573
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2574 2575 2576
        goto cleanup;
    teardowndevice = true;

2577
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
2578 2579 2580
        goto cleanup;
    teardowncgroup = true;

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

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

2588
    if (qemuDomainSecretHostdevPrepare(priv, hostdev) < 0)
2589 2590
        goto cleanup;

2591 2592 2593
    if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
        qemuDomainStorageSourcePrivatePtr srcPriv =
            QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(scsisrc->u.iscsi.src);
2594 2595
        if (srcPriv)
            secinfo = srcPriv->secinfo;
2596 2597
    }

2598 2599 2600 2601 2602 2603
    if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
        if (qemuBuildSecretInfoProps(secinfo, &secobjProps) < 0)
            goto cleanup;
    }

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

2606 2607 2608
    if (!(drivealias = qemuAliasFromHostdev(hostdev)))
        goto cleanup;

2609
    if (!(devstr = qemuBuildSCSIHostdevDevStr(vm->def, hostdev)))
2610 2611
        goto cleanup;

2612
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
2613 2614 2615 2616
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);

2617 2618 2619
    if (secobjProps &&
        qemuMonitorAddObject(priv->mon, &secobjProps, &secobjAlias) < 0)
        goto exit_monitor;
2620

2621
    if (qemuMonitorAddDrive(priv->mon, drvstr) < 0)
2622 2623
        goto exit_monitor;
    driveAdded = true;
2624 2625

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2626
        goto exit_monitor;
2627 2628

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

    virDomainAuditHostdev(vm, hostdev, "attach", true);
2632 2633 2634 2635

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

    ret = 0;
2636

2637
 cleanup:
2638
    if (ret < 0) {
2639
        qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
2640 2641
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
2642
        if (teardownlabel &&
2643
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2644
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2645
        if (teardowndevice &&
2646
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2647
            VIR_WARN("Unable to remove host device from /dev");
2648
    }
2649 2650
    qemuDomainSecretHostdevDestroy(hostdev);
    virJSONValueFree(secobjProps);
2651
    return ret;
2652

2653
 exit_monitor:
2654
    virErrorPreserveLast(&orig_err);
2655
    if (driveAdded && qemuMonitorDriveDel(priv->mon, drivealias) < 0) {
2656 2657 2658
        VIR_WARN("Unable to remove drive %s (%s) after failed "
                 "qemuMonitorAddDevice",
                 drvstr, devstr);
2659
    }
2660 2661
    if (secobjAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, secobjAlias));
2662
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2663
    virErrorRestore(&orig_err);
2664 2665 2666 2667

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

    goto cleanup;
2668 2669
}

2670 2671 2672 2673 2674 2675 2676 2677 2678 2679
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;
2680
    g_autofree char *vhostfdName = NULL;
2681
    int vhostfd = -1;
2682
    g_autofree char *devstr = NULL;
2683 2684
    bool teardowncgroup = false;
    bool teardownlabel = false;
2685
    bool teardowndevice = false;
2686 2687
    bool releaseaddr = false;

2688
    if (qemuHostdevPrepareSCSIVHostDevices(driver, vm->def->name, &hostdev, 1) < 0)
2689 2690
        return -1;

2691
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2692 2693 2694
        goto cleanup;
    teardowndevice = true;

2695 2696 2697 2698
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
        goto cleanup;
    teardowncgroup = true;

2699
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
2700 2701 2702 2703 2704 2705
        goto cleanup;
    teardownlabel = true;

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

2706
    vhostfdName = g_strdup_printf("vhostfd-%d", vhostfd);
2707 2708

    if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
2709
        if (qemuDomainIsS390CCW(vm->def) &&
2710
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CCW))
2711 2712 2713 2714 2715
            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) {
2716
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
2717 2718
            goto cleanup;
    } else if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
2719
        if (!(ccwaddrs = virDomainCCWAddressSetCreateFromDomain(vm->def)))
2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740
            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);

2741 2742 2743 2744 2745 2746 2747 2748
    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;
    }
2749

2750
 exit_monitor:
2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764
    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 &&
2765
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2766
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2767
        if (teardowndevice &&
2768
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2769
            VIR_WARN("Unable to remove host device from /dev");
2770
        if (releaseaddr)
2771
            qemuDomainReleaseDeviceAddress(vm, hostdev->info);
2772 2773 2774 2775 2776 2777 2778 2779
    }

    virDomainCCWAddressSetFree(ccwaddrs);

    VIR_FORCE_CLOSE(vhostfd);
    return ret;
}

2780

2781 2782 2783 2784 2785 2786
static int
qemuDomainAttachMediatedDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    int ret = -1;
2787
    g_autofree char *devstr = NULL;
2788 2789 2790 2791
    bool added = false;
    bool teardowncgroup = false;
    bool teardownlabel = false;
    bool teardowndevice = false;
2792
    bool teardownmemlock = false;
2793 2794 2795 2796
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                                { .hostdev = hostdev } };

2797 2798 2799 2800 2801
    switch (hostdev->source.subsys.u.mdev.model) {
    case VIR_MDEV_MODEL_TYPE_VFIO_PCI:
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
            return -1;
        break;
2802 2803 2804 2805 2806 2807 2808
    case VIR_MDEV_MODEL_TYPE_VFIO_CCW: {
        const char *devName = hostdev->source.subsys.u.mdev.uuidstr;
        bool releaseaddr = false;

        if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, devName) < 0)
            return -1;
    }   break;
2809 2810 2811
    case VIR_MDEV_MODEL_TYPE_LAST:
        break;
    }
2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841

    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;

2842 2843 2844 2845
    if (qemuDomainAdjustMaxMemLockHostdev(vm, hostdev) < 0)
        goto cleanup;
    teardownmemlock = true;

2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860
    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) {
2861 2862
        if (teardownmemlock && qemuDomainAdjustMaxMemLock(vm) < 0)
            VIR_WARN("Unable to reset maximum locked memory on hotplug fail");
2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875
        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);
2876
        qemuDomainReleaseDeviceAddress(vm, hostdev->info);
2877 2878 2879 2880 2881
    }
    return ret;
}


2882
int
2883
qemuDomainAttachHostDevice(virQEMUDriverPtr driver,
2884 2885
                           virDomainObjPtr vm,
                           virDomainHostdevDefPtr hostdev)
2886 2887
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
2888
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2889
                       _("hotplug is not supported for hostdev mode '%s'"),
2890
                       virDomainHostdevModeTypeToString(hostdev->mode));
2891 2892 2893 2894 2895
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
2896
        if (qemuDomainAttachHostPCIDevice(driver, vm,
2897
                                          hostdev) < 0)
2898 2899 2900 2901
            goto error;
        break;

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
2902
        if (qemuDomainAttachHostUSBDevice(driver, vm,
2903
                                          hostdev) < 0)
2904 2905 2906
            goto error;
        break;

2907
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
2908
        if (qemuDomainAttachHostSCSIDevice(driver, vm,
2909 2910 2911 2912
                                           hostdev) < 0)
            goto error;
        break;

2913 2914 2915 2916
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
        if (qemuDomainAttachSCSIVHostDevice(driver, vm, hostdev) < 0)
            goto error;
        break;
2917 2918 2919 2920
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
        if (qemuDomainAttachMediatedDevice(driver, vm, hostdev) < 0)
            goto error;
        break;
2921

2922
    default:
2923
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2924
                       _("hotplug is not supported for hostdev subsys type '%s'"),
2925
                       virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
2926 2927 2928 2929 2930
        goto error;
    }

    return 0;

2931
 error:
2932 2933 2934
    return -1;
}

2935 2936 2937 2938 2939 2940 2941

int
qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainShmemDefPtr shmem)
{
    int ret = -1;
2942 2943 2944
    g_autofree char *shmstr = NULL;
    g_autofree char *charAlias = NULL;
    g_autofree char *memAlias = NULL;
2945 2946 2947 2948 2949
    bool release_backing = false;
    bool release_address = true;
    virErrorPtr orig_err = NULL;
    virJSONValuePtr props = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2950
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_SHMEM, { .shmem = shmem } };
2951 2952 2953 2954 2955 2956 2957 2958 2959 2960

    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));
2961
        G_GNUC_FALLTHROUGH;
2962 2963 2964 2965 2966 2967 2968
    case VIR_DOMAIN_SHMEM_MODEL_LAST:
        return -1;
    }

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

2969
    qemuDomainPrepareShmemChardev(shmem);
2970 2971 2972 2973 2974 2975

    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) &&
2976
        (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0))
2977 2978 2979 2980 2981 2982
        return -1;

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

    if (shmem->server.enabled) {
2983
        charAlias = g_strdup_printf("char%s", shmem->info.alias);
2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996
    } 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 {
2997
        if (qemuMonitorAddObject(priv->mon, &props, &memAlias) < 0)
2998 2999 3000 3001 3002
            goto exit_monitor;
    }

    release_backing = true;

3003 3004 3005 3006 3007
    if (qemuDomainAttachExtensionDevice(priv->mon, &shmem->info) < 0)
        goto exit_monitor;

    if (qemuMonitorAddDevice(priv->mon, shmstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &shmem->info));
3008
        goto exit_monitor;
3009
    }
3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027

    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)
3028
        qemuDomainReleaseDeviceAddress(vm, &shmem->info);
3029 3030 3031 3032 3033 3034

    virJSONValueFree(props);

    return ret;

 exit_monitor:
3035
    virErrorPreserveLast(&orig_err);
3036 3037 3038 3039 3040 3041 3042
    if (release_backing) {
        if (shmem->server.enabled)
            ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
        else
            ignore_value(qemuMonitorDelObject(priv->mon, memAlias));
    }

3043 3044 3045
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        release_address = false;

3046
    virErrorRestore(&orig_err);
3047 3048 3049 3050 3051

    goto audit;
}


M
Michal Privoznik 已提交
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061
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;
3062
    g_autofree char *watchdogstr = NULL;
M
Michal Privoznik 已提交
3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085
    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;
    }

3086 3087 3088
    if (!(watchdogstr = qemuBuildWatchdogDevStr(vm->def, watchdog, priv->qemuCaps)))
        goto cleanup;

M
Michal Privoznik 已提交
3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117
    /* 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)
3118
        qemuDomainReleaseDeviceAddress(vm, &watchdog->info);
M
Michal Privoznik 已提交
3119 3120 3121 3122
    return ret;
}


J
Ján Tomko 已提交
3123 3124 3125 3126 3127 3128
int
qemuDomainAttachInputDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainInputDefPtr input)
{
    int ret = -1;
3129
    g_autofree char *devstr = NULL;
J
Ján Tomko 已提交
3130 3131 3132
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_INPUT,
                               { .input = input } };
3133
    virErrorPtr originalError = NULL;
J
Ján Tomko 已提交
3134
    bool releaseaddr = false;
3135 3136 3137
    bool teardowndevice = false;
    bool teardownlabel = false;
    bool teardowncgroup = false;
J
Ján Tomko 已提交
3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150

    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) {
3151 3152 3153
        if (virDomainUSBAddressEnsure(priv->usbaddrs, &input->info) < 0)
            goto cleanup;
        releaseaddr = true;
J
Ján Tomko 已提交
3154 3155 3156 3157 3158 3159 3160 3161
    }

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

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

3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173
    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 已提交
3174 3175 3176 3177
    if (VIR_REALLOC_N(vm->def->inputs, vm->def->ninputs + 1) < 0)
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);
3178 3179

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

3182 3183 3184 3185 3186
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &input->info));
        goto exit_monitor;
    }

J
Ján Tomko 已提交
3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199
    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:
3200 3201 3202 3203 3204 3205 3206 3207 3208
    if (ret < 0) {
        virErrorPreserveLast(&originalError);
        if (teardownlabel)
            qemuSecurityRestoreInputLabel(vm, input);
        if (teardowncgroup)
            qemuTeardownInputCgroup(vm, input);
        if (teardowndevice)
            qemuDomainNamespaceTeardownInput(vm, input);
        if (releaseaddr)
3209
            qemuDomainReleaseDeviceAddress(vm, &input->info);
3210 3211
        virErrorRestore(&originalError);
    }
J
Ján Tomko 已提交
3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223

    return ret;

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


J
Ján Tomko 已提交
3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235
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;
3236 3237
    g_autofree char *fdname = NULL;
    g_autofree char *devstr = NULL;
J
Ján Tomko 已提交
3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254
    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;

3255
    fdname = g_strdup_printf("%s%u", fdprefix, vsockPriv->vhostfd);
J
Ján Tomko 已提交
3256 3257 3258 3259 3260

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

    qemuDomainObjEnterMonitor(driver, vm);
3261 3262 3263 3264 3265 3266

    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 已提交
3267
        goto exit_monitor;
3268
    }
J
Ján Tomko 已提交
3269 3270 3271 3272 3273 3274

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

3275
    vm->def->vsock = g_steal_pointer(&vsock);
J
Ján Tomko 已提交
3276 3277 3278 3279 3280 3281 3282

    ret = 0;

 cleanup:
    if (ret < 0) {
        virErrorPreserveLast(&originalError);
        if (releaseaddr)
3283
            qemuDomainReleaseDeviceAddress(vm, &vsock->info);
J
Ján Tomko 已提交
3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295
        virErrorRestore(&originalError);
    }

    return ret;

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


3296 3297 3298 3299 3300
int
qemuDomainAttachLease(virQEMUDriverPtr driver,
                      virDomainObjPtr vm,
                      virDomainLeaseDefPtr lease)
{
3301
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
3302 3303

    if (virDomainLeaseInsertPreAlloc(vm->def) < 0)
3304
        return -1;
3305 3306 3307 3308

    if (virDomainLockLeaseAttach(driver->lockManager, cfg->uri,
                                 vm, lease) < 0) {
        virDomainLeaseInsertPreAlloced(vm->def, NULL);
3309
        return -1;
3310 3311 3312
    }

    virDomainLeaseInsertPreAlloced(vm->def, lease);
3313
    return 0;
3314 3315 3316
}


3317
static int
3318
qemuDomainChangeNetBridge(virDomainObjPtr vm,
3319 3320
                          virDomainNetDefPtr olddev,
                          virDomainNetDefPtr newdev)
3321 3322
{
    int ret = -1;
3323 3324
    const char *oldbridge = virDomainNetGetActualBridgeName(olddev);
    const char *newbridge = virDomainNetGetActualBridgeName(newdev);
3325

3326 3327
    if (!oldbridge || !newbridge) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
3328
        return -1;
3329
    }
3330 3331 3332 3333 3334

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

    if (virNetDevExists(newbridge) != 1) {
3335 3336
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("bridge %s doesn't exist"), newbridge);
3337
        return -1;
3338 3339
    }

3340 3341 3342 3343 3344 3345 3346 3347 3348
    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);
3349 3350 3351
    }

    ret = virNetDevBridgeAddPort(newbridge, olddev->ifname);
3352
    virDomainAuditNet(vm, NULL, newdev, "attach", ret == 0);
3353 3354 3355 3356
    if (ret < 0) {
        ret = virNetDevBridgeAddPort(oldbridge, olddev->ifname);
        virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
        if (ret < 0) {
3357
            virReportError(VIR_ERR_OPERATION_FAILED,
3358
                           _("unable to recover former state by adding port "
3359
                             "to bridge %s"), oldbridge);
3360
        }
3361
        return ret;
3362
    }
3363
    /* caller will replace entire olddev with newdev in domain nets list */
3364
    return 0;
3365 3366
}

3367
static int
3368
qemuDomainChangeNetFilter(virDomainObjPtr vm,
3369 3370 3371 3372 3373 3374 3375
                          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:
3376
    case VIR_DOMAIN_NET_TYPE_NETWORK:
3377
        break;
3378 3379 3380 3381 3382 3383 3384 3385 3386
    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:
3387 3388 3389 3390
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("filters not supported on interfaces of type %s"),
                       virDomainNetTypeToString(virDomainNetGetActualType(newdev)));
        return -1;
3391 3392 3393 3394 3395
    case VIR_DOMAIN_NET_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainNetType,
                                virDomainNetGetActualType(newdev));
        return -1;
3396 3397 3398 3399
    }

    virDomainConfNWFilterTeardown(olddev);

3400
    if (newdev->filter &&
3401
        virDomainConfNWFilterInstantiate(vm->def->name,
3402
                                         vm->def->uuid, newdev, false) < 0) {
3403 3404 3405 3406 3407 3408
        virErrorPtr errobj;

        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to add new filter rules to '%s' "
                         "- attempting to restore old rules"),
                       olddev->ifname);
3409
        virErrorPreserveLast(&errobj);
3410
        ignore_value(virDomainConfNWFilterInstantiate(vm->def->name,
3411
                                                      vm->def->uuid, olddev, false));
3412
        virErrorRestore(&errobj);
3413 3414 3415 3416 3417
        return -1;
    }
    return 0;
}

3418
int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver,
3419 3420 3421 3422 3423 3424 3425 3426
                                 virDomainObjPtr vm,
                                 virDomainNetDefPtr dev,
                                 int linkstate)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if (!dev->info.alias) {
3427 3428
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("can't change link state: device alias not found"));
3429 3430 3431
        return -1;
    }

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

3434
    qemuDomainObjEnterMonitor(driver, vm);
3435 3436 3437 3438 3439 3440 3441 3442

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

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

3443
 cleanup:
3444 3445
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        return -1;
3446 3447 3448 3449

    return ret;
}

3450
int
3451
qemuDomainChangeNet(virQEMUDriverPtr driver,
3452 3453
                    virDomainObjPtr vm,
                    virDomainDeviceDefPtr dev)
3454
{
3455
    qemuDomainObjPrivatePtr priv = vm->privateData;
3456
    virDomainNetDefPtr newdev = dev->data.net;
3457
    virDomainNetDefPtr *devslot = NULL;
3458
    virDomainNetDefPtr olddev;
3459
    virDomainNetType oldType, newType;
3460 3461
    bool needReconnect = false;
    bool needBridgeChange = false;
3462
    bool needFilterChange = false;
3463 3464
    bool needLinkStateChange = false;
    bool needReplaceDevDef = false;
3465
    bool needBandwidthSet = false;
3466
    bool needCoalesceChange = false;
3467
    bool needVlanUpdate = false;
3468
    int ret = -1;
3469
    int changeidx = -1;
3470
    g_autoptr(virConnect) conn = NULL;
3471
    virErrorPtr save_err = NULL;
3472 3473 3474 3475

    if ((changeidx = virDomainNetFindIdx(vm->def, newdev)) < 0)
        goto cleanup;
    devslot = &vm->def->nets[changeidx];
3476
    olddev = *devslot;
3477 3478 3479 3480

    oldType = virDomainNetGetActualType(olddev);
    if (oldType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* no changes are possible to a type='hostdev' interface */
3481
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503
                       _("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];

3504
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3505 3506 3507 3508 3509 3510 3511
                       _("cannot change network interface mac address "
                         "from %s to %s"),
                       virMacAddrFormat(&olddev->mac, oldmac),
                       virMacAddrFormat(&newdev->mac, newmac));
        goto cleanup;
    }

3512 3513
    if (STRNEQ_NULLABLE(virDomainNetGetModelString(olddev),
                        virDomainNetGetModelString(newdev))) {
3514
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3515
                       _("cannot modify network device model from %s to %s"),
3516 3517
                       NULLSTR(virDomainNetGetModelString(olddev)),
                       NULLSTR(virDomainNetGetModelString(newdev)));
3518
        goto cleanup;
3519 3520
    }

3521 3522 3523 3524 3525 3526 3527 3528
    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;
    }

3529
    if (virDomainNetIsVirtioModel(olddev) &&
3530 3531 3532
        (olddev->driver.virtio.name != newdev->driver.virtio.name ||
         olddev->driver.virtio.txmode != newdev->driver.virtio.txmode ||
         olddev->driver.virtio.ioeventfd != newdev->driver.virtio.ioeventfd ||
3533
         olddev->driver.virtio.event_idx != newdev->driver.virtio.event_idx ||
3534
         olddev->driver.virtio.queues != newdev->driver.virtio.queues ||
3535 3536
         olddev->driver.virtio.rx_queue_size != newdev->driver.virtio.rx_queue_size ||
         olddev->driver.virtio.tx_queue_size != newdev->driver.virtio.tx_queue_size ||
3537 3538 3539 3540 3541 3542
         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 已提交
3543
         olddev->driver.virtio.host.mrg_rxbuf != newdev->driver.virtio.host.mrg_rxbuf ||
3544 3545 3546 3547 3548
         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)) {
3549
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3550 3551 3552 3553 3554 3555 3556 3557 3558 3559
                       _("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;
3560 3561
    }

3562
    if (STRNEQ_NULLABLE(olddev->script, newdev->script)) {
3563
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3564 3565
                       _("cannot modify network device script attribute"));
        goto cleanup;
3566 3567
    }

3568
    /* ifname: check if it's set in newdev. If not, retain the autogenerated one */
3569 3570
    if (!newdev->ifname)
        newdev->ifname = g_strdup(olddev->ifname);
3571
    if (STRNEQ_NULLABLE(olddev->ifname, newdev->ifname)) {
3572
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3573 3574 3575
                       _("cannot modify network device tap name"));
        goto cleanup;
    }
3576

3577 3578
    /* info: Nothing is allowed to change. First fill the missing newdev->info
     * from olddev and then check for changes.
3579
     */
3580 3581 3582 3583 3584 3585 3586 3587 3588 3589
    /* 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"));
3590
    }
3591
    if (!virPCIDeviceAddressEqual(&olddev->info.addr.pci,
3592
                                  &newdev->info.addr.pci)) {
3593
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3594 3595 3596 3597
                       _("cannot modify network device guest PCI address"));
        goto cleanup;
    }
    /* grab alias from olddev if not set in newdev */
3598 3599
    if (!newdev->info.alias)
        newdev->info.alias = g_strdup(olddev->info.alias);
3600 3601 3602

    /* device alias is checked already in virDomainDefCompatibleDevice */

3603 3604
    if (newdev->info.rombar == VIR_TRISTATE_BOOL_ABSENT)
        newdev->info.rombar = olddev->info.rombar;
3605
    if (olddev->info.rombar != newdev->info.rombar) {
3606
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3607 3608 3609
                       _("cannot modify network device rom bar setting"));
        goto cleanup;
    }
3610

3611 3612
    if (!newdev->info.romfile)
        newdev->info.romfile = g_strdup(olddev->info.romfile);
3613
    if (STRNEQ_NULLABLE(olddev->info.romfile, newdev->info.romfile)) {
3614
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3615 3616 3617
                       _("cannot modify network rom file"));
        goto cleanup;
    }
3618 3619 3620

    if (newdev->info.bootIndex == 0)
        newdev->info.bootIndex = olddev->info.bootIndex;
3621
    if (olddev->info.bootIndex != newdev->info.bootIndex) {
3622
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3623 3624 3625
                       _("cannot modify network device boot index setting"));
        goto cleanup;
    }
3626 3627 3628

    if (newdev->info.romenabled == VIR_TRISTATE_BOOL_ABSENT)
        newdev->info.romenabled = olddev->info.romenabled;
3629 3630 3631 3632 3633
    if (olddev->info.romenabled != newdev->info.romenabled) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot modify network device rom enabled setting"));
        goto cleanup;
    }
3634
    /* (end of device info checks) */
3635

3636 3637 3638 3639
    if (STRNEQ_NULLABLE(olddev->filter, newdev->filter) ||
        !virNWFilterHashTableEqual(olddev->filterparams, newdev->filterparams)) {
        needFilterChange = true;
    }
3640

3641 3642 3643 3644
    /* bandwidth can be modified, and will be checked later */
    /* vlan can be modified, and will be checked later */
    /* linkstate can be modified */

3645 3646 3647 3648 3649 3650
    if (olddev->mtu != newdev->mtu) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot modify MTU"));
        goto cleanup;
    }

3651 3652 3653
    /* allocate new actual device to compare to old - we will need to
     * free it if we fail for any reason
     */
3654 3655 3656 3657 3658
    if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        if (!(conn = virGetConnectNetwork()))
            goto cleanup;
        if (virDomainNetAllocateActualDevice(conn, vm->def, newdev) < 0)
            goto cleanup;
3659 3660
    }

3661 3662 3663 3664
    /* final validation now that we have full info on the type */
    if (qemuDomainValidateActualNetDef(newdev, priv->qemuCaps) < 0)
        goto cleanup;

3665 3666 3667 3668
    newType = virDomainNetGetActualType(newdev);

    if (newType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* can't turn it into a type='hostdev' interface */
3669
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3670 3671 3672 3673 3674 3675
                       _("cannot change network interface type to '%s'"),
                       virDomainNetTypeToString(newType));
        goto cleanup;
    }

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

3677 3678 3679 3680 3681 3682
        /* 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:
3683
            break;
3684

3685 3686 3687
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
3688
        case VIR_DOMAIN_NET_TYPE_UDP:
3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720
            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;

3721 3722
        case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
3723
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3724 3725
                           _("unable to change config on '%s' network type"),
                           virDomainNetTypeToString(newdev->type));
3726 3727 3728 3729 3730
            goto cleanup;
        case VIR_DOMAIN_NET_TYPE_LAST:
        default:
            virReportEnumRangeError(virDomainNetType, newdev->type);
            goto cleanup;
3731
        }
3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762
    } 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;
3763 3764

        }
3765
    }
3766

3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
    /* 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;
    }
3778

3779 3780
    if (STRNEQ_NULLABLE(virDomainNetGetActualDirectDev(olddev),
                        virDomainNetGetActualDirectDev(newdev)) ||
3781
        virDomainNetGetActualDirectMode(olddev) != virDomainNetGetActualDirectMode(newdev) ||
3782
        !virNetDevVPortProfileEqual(virDomainNetGetActualVirtPortProfile(olddev),
3783
                                    virDomainNetGetActualVirtPortProfile(newdev))) {
3784
        needReconnect = true;
3785 3786
    }

3787 3788 3789 3790 3791
    if (!virNetDevVlanEqual(virDomainNetGetActualVlan(olddev),
                             virDomainNetGetActualVlan(newdev))) {
        needVlanUpdate = true;
    }

3792 3793 3794
    if (olddev->linkstate != newdev->linkstate)
        needLinkStateChange = true;

3795 3796 3797 3798
    if (!virNetDevBandwidthEqual(virDomainNetGetActualBandwidth(olddev),
                                 virDomainNetGetActualBandwidth(newdev)))
        needBandwidthSet = true;

3799 3800
    if (!!olddev->coalesce != !!newdev->coalesce ||
        (olddev->coalesce && newdev->coalesce &&
3801 3802
         memcmp(olddev->coalesce, newdev->coalesce,
                sizeof(*olddev->coalesce))))
3803 3804
        needCoalesceChange = true;

3805 3806 3807
    /* FINALLY - actually perform the required actions */

    if (needReconnect) {
3808
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3809 3810 3811
                       _("unable to change config on '%s' network type"),
                       virDomainNetTypeToString(newdev->type));
        goto cleanup;
3812 3813
    }

3814
    if (needBandwidthSet) {
3815
        const virNetDevBandwidth *newb = virDomainNetGetActualBandwidth(newdev);
3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827

        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);
        }
3828 3829 3830
        needReplaceDevDef = true;
    }

3831
    if (needBridgeChange) {
3832
        if (qemuDomainChangeNetBridge(vm, olddev, newdev) < 0)
3833 3834 3835
            goto cleanup;
        /* we successfully switched to the new bridge, and we've
         * determined that the rest of newdev is equivalent to olddev,
3836 3837 3838 3839 3840
         * so move newdev into place */
        needReplaceDevDef = true;
    }

    if (needFilterChange) {
3841
        if (qemuDomainChangeNetFilter(vm, olddev, newdev) < 0)
3842 3843 3844 3845
            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 */
3846
        needReplaceDevDef = true;
3847 3848
    }

3849 3850 3851 3852 3853 3854
    if (needCoalesceChange) {
        if (virNetDevSetCoalesce(newdev->ifname, newdev->coalesce, true) < 0)
            goto cleanup;
        needReplaceDevDef = true;
    }

3855 3856 3857
    if (needLinkStateChange &&
        qemuDomainChangeNetLinkState(driver, vm, olddev, newdev->linkstate) < 0) {
        goto cleanup;
3858 3859
    }

3860 3861 3862 3863 3864 3865
    if (needVlanUpdate) {
        if (virNetDevOpenvswitchUpdateVlan(newdev->ifname, &newdev->vlan) < 0)
            goto cleanup;
        needReplaceDevDef = true;
    }

3866 3867 3868 3869
    if (needReplaceDevDef) {
        /* the changes above warrant replacing olddev with newdev in
         * the domain's nets list.
         */
3870 3871 3872

        /* this function doesn't work with HOSTDEV networks yet, thus
         * no need to change the pointer in the hostdev structure */
3873 3874 3875 3876 3877 3878
        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));
        }
3879 3880 3881 3882 3883 3884 3885 3886
        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;
3887 3888
    }

3889
    ret = 0;
3890
 cleanup:
3891
    virErrorPreserveLast(&save_err);
3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909
    /* 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.
     */
3910 3911
    if (newdev && newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK && conn)
        virDomainNetReleaseActualDevice(conn, vm->def, newdev);
3912
    virErrorRestore(&save_err);
3913

3914 3915 3916
    return ret;
}

3917 3918 3919
static virDomainGraphicsDefPtr
qemuDomainFindGraphics(virDomainObjPtr vm,
                       virDomainGraphicsDefPtr dev)
3920
{
3921
    size_t i;
3922

3923
    for (i = 0; i < vm->def->ngraphics; i++) {
3924 3925 3926 3927 3928 3929 3930
        if (vm->def->graphics[i]->type == dev->type)
            return vm->def->graphics[i];
    }

    return NULL;
}

3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944
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;
}

3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956

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;
3957
    g_autofree char *validTo = NULL;
3958 3959 3960 3961
    const char *connected = NULL;
    const char *password;
    int ret = -1;

3962 3963 3964
    if (!auth->passwd && !defaultPasswd)
        return 0;

3965 3966 3967 3968 3969 3970
    password = auth->passwd ? auth->passwd : defaultPasswd;

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

    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
3971
        return ret;
3972 3973 3974 3975 3976 3977 3978 3979 3980
    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) {
3981
        validTo = g_strdup_printf("%lu", (unsigned long)auth->validTo);
3982 3983 3984 3985 3986 3987 3988 3989 3990 3991
        expire = validTo;
    } else {
        expire = "never";
    }

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

 end_job:
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;
3992

3993 3994 3995 3996
    return ret;
}


3997
int
3998
qemuDomainChangeGraphics(virQEMUDriverPtr driver,
3999 4000 4001 4002
                         virDomainObjPtr vm,
                         virDomainGraphicsDefPtr dev)
{
    virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
4003
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
4004
    const char *type = virDomainGraphicsTypeToString(dev->type);
4005
    size_t i;
4006 4007

    if (!olddev) {
4008
        virReportError(VIR_ERR_DEVICE_MISSING,
4009 4010
                       _("cannot find existing graphics device to modify of "
                         "type '%s'"), type);
4011
        return -1;
4012 4013
    }

4014
    if (dev->nListens != olddev->nListens) {
4015 4016 4017
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("cannot change the number of listen addresses "
                         "on '%s' graphics"), type);
4018
        return -1;
4019 4020 4021
    }

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

J
Jim Fehlig 已提交
4025
        if (newlisten->type != oldlisten->type) {
4026 4027 4028
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                           _("cannot change the type of listen address "
                             "on '%s' graphics"), type);
4029
            return -1;
4030 4031
        }

4032
        switch (newlisten->type) {
4033
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
J
Jim Fehlig 已提交
4034
            if (STRNEQ_NULLABLE(newlisten->address, oldlisten->address)) {
4035 4036 4037
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen address setting "
                                 "on '%s' graphics"), type);
4038
                return -1;
4039
            }
4040

4041 4042 4043
            break;

        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
J
Jim Fehlig 已提交
4044
            if (STRNEQ_NULLABLE(newlisten->network, oldlisten->network)) {
4045 4046 4047
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen address setting "
                                 "on '%s' graphics"), type);
4048
                return -1;
4049
            }
4050

4051 4052
            break;

4053 4054 4055 4056 4057
        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);
4058
                return -1;
4059 4060 4061
            }
            break;

4062 4063 4064 4065 4066 4067
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE:
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST:
            /* nada */
            break;
        }
    }
4068

4069 4070
    switch (dev->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
4071 4072 4073
        if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
            (!dev->data.vnc.autoport &&
             (olddev->data.vnc.port != dev->data.vnc.port))) {
4074
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4075
                           _("cannot change port settings on vnc graphics"));
4076
            return -1;
4077 4078
        }
        if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
4079
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4080
                           _("cannot change keymap setting on vnc graphics"));
4081
            return -1;
4082 4083
        }

4084 4085 4086
        /* 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 */
4087 4088
        if (olddev->data.vnc.auth.expires ||
            dev->data.vnc.auth.expires ||
4089
            olddev->data.vnc.auth.connected != dev->data.vnc.auth.connected ||
E
Eric Blake 已提交
4090 4091 4092
            STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd,
                            dev->data.vnc.auth.passwd)) {
            VIR_DEBUG("Updating password on VNC server %p %p",
4093
                      dev->data.vnc.auth.passwd, cfg->vncPassword);
4094 4095 4096 4097 4098 4099
            if (qemuDomainChangeGraphicsPasswords(driver, vm,
                                                  VIR_DOMAIN_GRAPHICS_TYPE_VNC,
                                                  &dev->data.vnc.auth,
                                                  cfg->vncPassword,
                                                  QEMU_ASYNC_JOB_NONE) < 0)
                return -1;
4100 4101 4102 4103 4104

            /* 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;
4105 4106
            olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo;
            olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires;
4107
            olddev->data.vnc.auth.connected = dev->data.vnc.auth.connected;
4108 4109 4110
        }
        break;

4111
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
4112 4113 4114 4115 4116
        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))) {
4117
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4118
                           _("cannot change port settings on spice graphics"));
4119
            return -1;
4120
        }
E
Eric Blake 已提交
4121 4122
        if (STRNEQ_NULLABLE(olddev->data.spice.keymap,
                            dev->data.spice.keymap)) {
4123
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4124
                            _("cannot change keymap setting on spice graphics"));
4125
            return -1;
4126 4127
        }

4128 4129 4130 4131 4132
        /* 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"
         */
4133 4134
        if (olddev->data.spice.auth.expires ||
            dev->data.spice.auth.expires ||
4135
            olddev->data.spice.auth.connected != dev->data.spice.auth.connected ||
4136 4137
            dev->data.spice.auth.connected ==
            VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DISCONNECT ||
E
Eric Blake 已提交
4138 4139 4140
            STRNEQ_NULLABLE(olddev->data.spice.auth.passwd,
                            dev->data.spice.auth.passwd)) {
            VIR_DEBUG("Updating password on SPICE server %p %p",
4141
                      dev->data.spice.auth.passwd, cfg->spicePassword);
4142 4143 4144 4145 4146 4147
            if (qemuDomainChangeGraphicsPasswords(driver, vm,
                                                  VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
                                                  &dev->data.spice.auth,
                                                  cfg->spicePassword,
                                                  QEMU_ASYNC_JOB_NONE) < 0)
                return -1;
4148

E
Eric Blake 已提交
4149
            /* Steal the new dev's char * reference */
4150 4151 4152 4153 4154
            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;
4155
            olddev->data.spice.auth.connected = dev->data.spice.auth.connected;
4156
        } else {
4157
            VIR_DEBUG("Not updating since password didn't change");
4158
        }
E
Eric Blake 已提交
4159
        break;
4160

4161 4162 4163
    case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
    case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
4164
    case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
4165
        virReportError(VIR_ERR_INTERNAL_ERROR,
4166
                       _("unable to change config on '%s' graphics type"), type);
4167
        break;
4168 4169 4170 4171
    case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainGraphicsType, dev->type);
        break;
4172 4173
    }

4174
    return 0;
4175 4176 4177
}


J
Ján Tomko 已提交
4178 4179
static int qemuComparePCIDevice(virDomainDefPtr def G_GNUC_UNUSED,
                                virDomainDeviceDefPtr device G_GNUC_UNUSED,
4180
                                virDomainDeviceInfoPtr info1,
4181 4182
                                void *opaque)
{
4183
    virDomainDeviceInfoPtr info2 = opaque;
4184

4185 4186
    if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
        info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
4187 4188
        return 0;

4189 4190 4191
    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 &&
4192
        info1->addr.pci.function != info2->addr.pci.function)
4193 4194 4195 4196 4197
        return -1;
    return 0;
}

static bool qemuIsMultiFunctionDevice(virDomainDefPtr def,
4198
                                      virDomainDeviceInfoPtr info)
4199
{
4200
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
4201 4202
        return false;

4203
    if (virDomainDeviceInfoIterate(def, qemuComparePCIDevice, info) < 0)
4204 4205 4206 4207
        return true;
    return false;
}

4208

4209
static int
4210 4211 4212 4213
qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainDiskDefPtr disk)
{
4214
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
J
Ján Tomko 已提交
4215
    g_autoptr(qemuBlockStorageSourceChainData) diskBackend = NULL;
4216 4217
    virDomainDeviceDef dev;
    size_t i;
4218
    qemuDomainObjPrivatePtr priv = vm->privateData;
4219
    g_autofree char *corAlias = NULL;
4220
    bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
4221
    int ret = -1;
4222 4223 4224 4225

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

4226

4227
    if (blockdev) {
4228
        corAlias = g_strdup(diskPriv->nodeCopyOnRead);
4229

4230 4231 4232 4233 4234 4235 4236 4237 4238
        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;
        }
4239 4240 4241 4242 4243 4244 4245 4246
    } else {
        char *driveAlias;

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

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

4249 4250 4251 4252 4253 4254 4255
    for (i = 0; i < vm->def->ndisks; i++) {
        if (vm->def->disks[i] == disk) {
            virDomainDiskRemove(vm->def, i);
            break;
        }
    }

4256
    qemuDomainObjEnterMonitor(driver, vm);
4257

4258 4259 4260
    if (corAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, corAlias));

4261 4262
    if (diskBackend)
        qemuBlockStorageSourceChainDetach(priv->mon, diskBackend);
4263

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

4267
    virDomainAuditDisk(vm, disk->src, NULL, "detach", true);
4268

4269
    qemuDomainReleaseDeviceAddress(vm, &disk->info);
4270

4271
    /* tear down disk security access */
4272 4273
    if (diskBackend)
        qemuDomainStorageSourceChainAccessRevoke(driver, vm, disk->src);
4274

4275 4276 4277 4278
    dev.type = VIR_DOMAIN_DEVICE_DISK;
    dev.data.disk = disk;
    ignore_value(qemuRemoveSharedDevice(driver, &dev, vm->def->name));

4279 4280
    if (virStorageSourceChainHasManagedPR(disk->src) &&
        qemuHotplugRemoveManagedPR(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
4281 4282
        goto cleanup;

4283 4284 4285
    ret = 0;

 cleanup:
4286
    virDomainDiskDefFree(disk);
4287
    return ret;
4288 4289 4290
}


4291
static int
4292
qemuDomainRemoveControllerDevice(virDomainObjPtr vm,
4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306
                                 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;
        }
    }

4307
    qemuDomainReleaseDeviceAddress(vm, &controller->info);
4308
    virDomainControllerDefFree(controller);
4309
    return 0;
4310 4311 4312
}


4313 4314 4315 4316 4317 4318
static int
qemuDomainRemoveMemoryDevice(virQEMUDriverPtr driver,
                             virDomainObjPtr vm,
                             virDomainMemoryDefPtr mem)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4319
    unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
4320
    unsigned long long newmem = oldmem - mem->size;
4321
    g_autofree char *backendAlias = NULL;
4322 4323 4324 4325 4326 4327
    int rc;
    int idx;

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

4328
    backendAlias = g_strdup_printf("mem%s", mem->info.alias);
4329 4330 4331

    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorDelObject(priv->mon, backendAlias);
4332 4333 4334 4335 4336 4337
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        rc = -1;

    virDomainAuditMemory(vm, oldmem, newmem, "update", rc == 0);
    if (rc < 0)
        return -1;
4338 4339 4340 4341

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

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

4345 4346 4347
    if (qemuTeardownMemoryDevicesCgroup(vm, mem) < 0)
        VIR_WARN("Unable to remove memory device cgroup ACL");

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

4351 4352 4353
    if (qemuProcessDestroyMemoryBackingPath(driver, vm, mem) < 0)
        VIR_WARN("Unable to destroy memory backing path");

4354
    virDomainMemoryDefFree(mem);
4355

4356 4357 4358
    /* fix the balloon size */
    ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));

4359
    /* decrease the mlock limit after memory unplug if necessary */
4360
    ignore_value(qemuDomainAdjustMaxMemLock(vm));
4361

4362
    return 0;
4363 4364 4365
}


4366 4367 4368 4369 4370
static void
qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
{
4371
    qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
4372
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4373 4374 4375 4376
}

static void
qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver,
4377
                              virDomainObjPtr vm,
4378 4379
                              virDomainHostdevDefPtr hostdev)
{
4380
    qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
4381
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4382 4383 4384 4385 4386 4387 4388
}

static void
qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
4389
    qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
4390 4391
}

4392 4393 4394 4395 4396 4397 4398 4399
static void
qemuDomainRemoveSCSIVHostDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainHostdevDefPtr hostdev)
{
    qemuHostdevReAttachSCSIVHostDevices(driver, vm->def->name, &hostdev, 1);
}

4400 4401 4402 4403 4404 4405 4406

static void
qemuDomainRemoveMediatedDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    qemuHostdevReAttachMediatedDevices(driver, vm->def->name, &hostdev, 1);
4407
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4408 4409 4410
}


4411
static int
4412 4413 4414 4415 4416 4417
qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainHostdevDefPtr hostdev)
{
    virDomainNetDefPtr net = NULL;
    size_t i;
4418
    qemuDomainObjPrivatePtr priv = vm->privateData;
4419 4420
    g_autofree char *drivealias = NULL;
    g_autofree char *objAlias = NULL;
4421 4422 4423 4424

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

4425
    if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
4426 4427 4428
        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
        virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;

J
John Ferlan 已提交
4429
        if (!(drivealias = qemuAliasFromHostdev(hostdev)))
4430
            return -1;
4431

4432 4433 4434 4435 4436
        /* 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) &&
4437
            qemuDomainStorageSourceHasAuth(iscsisrc->src)) {
4438
            if (!(objAlias = qemuDomainGetSecretAESAlias(hostdev->info->alias, false)))
4439
                return -1;
4440 4441
        }

4442
        qemuDomainObjEnterMonitor(driver, vm);
J
John Ferlan 已提交
4443
        qemuMonitorDriveDel(priv->mon, drivealias);
4444 4445 4446 4447 4448

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

4449
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
4450
            return -1;
4451 4452
    }

4453
    if (hostdev->parentnet) {
4454
        net = hostdev->parentnet;
4455
        for (i = 0; i < vm->def->nnets; i++) {
4456
            if (vm->def->nets[i] == hostdev->parentnet) {
4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471
                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);

4472
    if (!virHostdevIsVFIODevice(hostdev) &&
4473
        qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
4474
        VIR_WARN("Failed to restore host device labelling");
4475

4476 4477 4478
    if (qemuTeardownHostdevCgroup(vm, hostdev) < 0)
        VIR_WARN("Failed to remove host device cgroup ACL");

4479
    if (qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
4480 4481
        VIR_WARN("Unable to remove host device from /dev");

4482
    switch ((virDomainHostdevSubsysType)hostdev->source.subsys.type) {
4483 4484
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
        qemuDomainRemovePCIHostDevice(driver, vm, hostdev);
4485 4486 4487 4488
        /* 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");
4489 4490 4491 4492 4493 4494 4495
        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;
4496
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
4497
        qemuDomainRemoveSCSIVHostDevice(driver, vm, hostdev);
4498
        break;
4499
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
4500
        qemuDomainRemoveMediatedDevice(driver, vm, hostdev);
4501
        break;
4502 4503 4504 4505 4506 4507 4508
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
        break;
    }

    virDomainHostdevDefFree(hostdev);

    if (net) {
4509
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4510 4511
            g_autoptr(virConnect) conn = virGetConnectNetwork();
            if (conn)
4512
                virDomainNetReleaseActualDevice(conn, vm->def, net);
4513
            else
4514 4515
                VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
        }
4516 4517
        virDomainNetDefFree(net);
    }
4518

4519
    return 0;
4520 4521 4522
}


4523
static int
4524 4525 4526 4527
qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainNetDefPtr net)
{
4528
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
4529
    qemuDomainObjPrivatePtr priv = vm->privateData;
4530 4531
    g_autofree char *hostnet_name = NULL;
    g_autofree char *charDevAlias = NULL;
4532
    size_t i;
4533
    int actualType = virDomainNetGetActualType(net);
4534

4535
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
4536
        /* this function handles all hostdev and netdev cleanup */
4537 4538
        return qemuDomainRemoveHostDevice(driver, vm,
                                          virDomainNetGetActualHostdev(net));
4539 4540
    }

4541 4542 4543
    VIR_DEBUG("Removing network interface %s from domain %p %s",
              net->info.alias, vm, vm->def->name);

4544 4545
    hostnet_name = g_strdup_printf("host%s", net->info.alias);
    if (!(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias)))
4546
        return -1;
4547

4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558
    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));
4559

4560
    qemuDomainObjEnterMonitor(driver, vm);
J
Ján Tomko 已提交
4561 4562
    if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
4563
            return -1;
J
Ján Tomko 已提交
4564
        virDomainAuditNet(vm, net, NULL, "detach", false);
4565
        return -1;
4566
    }
4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577

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

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

4581 4582 4583
    if (QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp)
        qemuSlirpStop(QEMU_DOMAIN_NETWORK_PRIVATE(net)->slirp, vm, driver, net, true);

4584 4585 4586 4587 4588 4589 4590 4591 4592
    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;
        }
    }

4593
    qemuDomainReleaseDeviceAddress(vm, &net->info);
4594 4595
    virDomainConfNWFilterTeardown(net);

4596 4597 4598 4599 4600 4601
    if (cfg->macFilter && (net->ifname != NULL)) {
        ignore_value(ebtablesRemoveForwardAllowIn(driver->ebtables,
                                                  net->ifname,
                                                  &net->mac));
    }

4602
    if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
4603 4604 4605 4606 4607 4608 4609 4610
        ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
                         net->ifname, &net->mac,
                         virDomainNetGetActualDirectDev(net),
                         virDomainNetGetActualDirectMode(net),
                         virDomainNetGetActualVirtPortProfile(net),
                         cfg->stateDir));
    }

4611
    qemuDomainNetDeviceVportRemove(net);
4612

4613
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4614 4615
        g_autoptr(virConnect) conn = virGetConnectNetwork();
        if (conn)
4616
            virDomainNetReleaseActualDevice(conn, vm->def, net);
4617
        else
4618 4619
            VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
    }
4620
    virDomainNetDefFree(net);
4621
    return 0;
4622 4623 4624
}


4625
static int
4626
qemuDomainRemoveChrDevice(virQEMUDriverPtr driver,
4627
                          virDomainObjPtr vm,
4628 4629
                          virDomainChrDefPtr chr,
                          bool monitor)
4630
{
4631
    virObjectEventPtr event;
4632
    g_autofree char *charAlias = NULL;
4633
    qemuDomainObjPrivatePtr priv = vm->privateData;
4634
    int rc = 0;
4635

4636 4637 4638
    VIR_DEBUG("Removing character device %s from domain %p %s",
              chr->info.alias, vm, vm->def->name);

4639
    if (!(charAlias = qemuAliasChardevFromDevAlias(chr->info.alias)))
4640
        return -1;
4641

4642
    if (monitor) {
4643 4644 4645
        qemuDomainObjEnterMonitor(driver, vm);
        rc = qemuMonitorDetachCharDev(priv->mon, charAlias);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
4646
            return -1;
4647
    }
4648

4649 4650
    if (rc == 0 &&
        qemuDomainDelChardevTLSObjects(driver, vm, chr->source, charAlias) < 0)
4651
        return -1;
4652

4653 4654 4655
    virDomainAuditChardev(vm, chr, NULL, "detach", rc == 0);

    if (rc < 0)
4656
        return -1;
4657

4658 4659 4660
    if (qemuTeardownChardevCgroup(vm, chr) < 0)
        VIR_WARN("Failed to remove chr device cgroup ACL");

4661 4662 4663
    if (qemuSecurityRestoreChardevLabel(driver, vm, chr) < 0)
        VIR_WARN("Unable to restore security label on char device");

4664
    if (qemuDomainNamespaceTeardownChardev(vm, chr) < 0)
4665 4666
        VIR_WARN("Unable to remove chr device from /dev");

4667
    qemuDomainReleaseDeviceAddress(vm, &chr->info);
4668 4669 4670 4671 4672 4673
    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.
     */
4674
    event = virDomainEventDeviceRemovedNewFromObj(vm, chr->info.alias);
4675
    virObjectEventStateQueue(driver->domainEventState, event);
4676

4677
    virDomainChrDefFree(chr);
4678
    return 0;
4679 4680 4681
}


4682 4683 4684 4685 4686
static int
qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
4687 4688
    g_autofree char *charAlias = NULL;
    g_autofree char *objAlias = NULL;
4689 4690
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ssize_t idx;
4691
    int rc = 0;
4692 4693 4694 4695

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

4696

4697
    objAlias = g_strdup_printf("obj%s", rng->info.alias);
4698

4699
    if (!(charAlias = qemuAliasChardevFromDevAlias(rng->info.alias)))
4700
        return -1;
4701 4702

    qemuDomainObjEnterMonitor(driver, vm);
4703

4704 4705 4706 4707 4708 4709 4710 4711
    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;
4712 4713

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

4716 4717
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
        rc == 0 &&
4718 4719
        qemuDomainDelChardevTLSObjects(driver, vm, rng->source.chardev,
                                       charAlias) < 0)
4720
        rc = -1;
4721

4722 4723 4724
    virDomainAuditRNG(vm, rng, NULL, "detach", rc == 0);

    if (rc < 0)
4725
        return -1;
4726

4727 4728 4729
    if (qemuTeardownRNGCgroup(vm, rng) < 0)
        VIR_WARN("Failed to remove RNG device cgroup ACL");

4730
    if (qemuDomainNamespaceTeardownRNG(vm, rng) < 0)
4731 4732
        VIR_WARN("Unable to remove RNG device from /dev");

4733 4734
    if ((idx = virDomainRNGFind(vm->def, rng)) >= 0)
        virDomainRNGRemove(vm->def, idx);
4735
    qemuDomainReleaseDeviceAddress(vm, &rng->info);
4736
    virDomainRNGDefFree(rng);
4737
    return 0;
4738 4739 4740
}


4741 4742 4743 4744 4745 4746 4747
static int
qemuDomainRemoveShmemDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainShmemDefPtr shmem)
{
    int rc;
    ssize_t idx = -1;
4748 4749
    g_autofree char *charAlias = NULL;
    g_autofree char *memAlias = NULL;
4750 4751 4752 4753 4754 4755
    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) {
4756
        charAlias = g_strdup_printf("char%s", shmem->info.alias);
4757
    } else {
4758
        memAlias = g_strdup_printf("shmmem-%s", shmem->info.alias);
4759 4760 4761 4762 4763 4764 4765 4766 4767 4768
    }

    qemuDomainObjEnterMonitor(driver, vm);

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

    if (qemuDomainObjExitMonitor(driver, vm) < 0)
4769
        return -1;
4770 4771 4772 4773

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

    if (rc < 0)
4774
        return -1;
4775 4776 4777

    if ((idx = virDomainShmemDefFind(vm->def, shmem)) >= 0)
        virDomainShmemDefRemove(vm->def, idx);
4778
    qemuDomainReleaseDeviceAddress(vm, &shmem->info);
4779 4780
    virDomainShmemDefFree(shmem);

4781
    return 0;
4782 4783 4784
}


M
Michal Privoznik 已提交
4785
static int
4786
qemuDomainRemoveWatchdog(virDomainObjPtr vm,
M
Michal Privoznik 已提交
4787 4788 4789 4790 4791
                         virDomainWatchdogDefPtr watchdog)
{
    VIR_DEBUG("Removing watchdog %s from domain %p %s",
              watchdog->info.alias, vm, vm->def->name);

4792
    qemuDomainReleaseDeviceAddress(vm, &watchdog->info);
M
Michal Privoznik 已提交
4793 4794 4795 4796 4797 4798
    virDomainWatchdogDefFree(vm->def->watchdog);
    vm->def->watchdog = NULL;
    return 0;
}


4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811
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;
    }
4812
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
4813 4814 4815 4816 4817 4818 4819 4820 4821
    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");

4822 4823 4824 4825 4826 4827
    virDomainInputDefFree(vm->def->inputs[i]);
    VIR_DELETE_ELEMENT(vm->def->inputs, i, vm->def->ninputs);
    return 0;
}


J
Ján Tomko 已提交
4828 4829 4830 4831 4832 4833 4834
static int
qemuDomainRemoveVsockDevice(virDomainObjPtr vm,
                            virDomainVsockDefPtr dev)
{
    VIR_DEBUG("Removing vsock device %s from domain %p %s",
              dev->info.alias, vm, vm->def->name);

4835
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
J
Ján Tomko 已提交
4836 4837 4838 4839 4840 4841
    virDomainVsockDefFree(vm->def->vsock);
    vm->def->vsock = NULL;
    return 0;
}


4842 4843 4844 4845 4846 4847
static int
qemuDomainRemoveRedirdevDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainRedirdevDefPtr dev)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4848
    g_autofree char *charAlias = NULL;
4849 4850 4851 4852 4853 4854
    ssize_t idx;

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

    if (!(charAlias = qemuAliasChardevFromDevAlias(dev->info.alias)))
4855
        return -1;
4856 4857 4858 4859 4860 4861 4862 4863

    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)
4864
        return -1;
4865 4866

    if (qemuDomainDelChardevTLSObjects(driver, vm, dev->source, charAlias) < 0)
4867
        return -1;
4868 4869 4870 4871 4872

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

    if ((idx = virDomainRedirdevDefFind(vm->def, dev)) >= 0)
        virDomainRedirdevDefRemove(vm->def, idx);
4873
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
4874 4875
    virDomainRedirdevDefFree(dev);

4876
    return 0;
4877 4878 4879
}


4880
static void
4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895
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:
4896 4897
        virDomainAuditInput(vm, detach->data.input, "detach", success);
        break;
4898
    case VIR_DOMAIN_DEVICE_CHR:
4899 4900
        virDomainAuditChardev(vm, detach->data.chr, NULL, "detach", success);
        break;
4901
    case VIR_DOMAIN_DEVICE_RNG:
4902 4903 4904 4905 4906 4907 4908 4909 4910
        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;
    }
4911
    case VIR_DOMAIN_DEVICE_SHMEM:
4912 4913
        virDomainAuditShmem(vm, detach->data.shmem, "detach", success);
        break;
4914
    case VIR_DOMAIN_DEVICE_REDIRDEV:
4915 4916
        virDomainAuditRedirdev(vm, detach->data.redirdev, "detach", success);
        break;
4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943

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


4944
int
4945 4946 4947 4948
qemuDomainRemoveDevice(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       virDomainDeviceDefPtr dev)
{
4949 4950
    virDomainDeviceInfoPtr info;
    virObjectEventPtr event;
4951
    g_autofree char *alias = NULL;
4952 4953 4954 4955 4956

    /*
     * save the alias to use when sending a DEVICE_REMOVED event after
     * all other teardown is complete
     */
4957 4958
    if ((info = virDomainDeviceGetInfo(dev)))
        alias = g_strdup(info->alias);
4959 4960
    info = NULL;

4961
    switch ((virDomainDeviceType)dev->type) {
4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976
    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.
         */
4977
    case VIR_DOMAIN_DEVICE_DISK:
4978 4979
        if (qemuDomainRemoveDiskDevice(driver, vm, dev->data.disk) < 0)
            return -1;
4980 4981
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
4982 4983
        if (qemuDomainRemoveControllerDevice(vm, dev->data.controller) < 0)
            return -1;
4984 4985
        break;
    case VIR_DOMAIN_DEVICE_NET:
4986 4987
        if (qemuDomainRemoveNetDevice(driver, vm, dev->data.net) < 0)
            return -1;
4988 4989
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
4990 4991
        if (qemuDomainRemoveHostDevice(driver, vm, dev->data.hostdev) < 0)
            return -1;
4992
        break;
4993
    case VIR_DOMAIN_DEVICE_RNG:
4994 4995
        if (qemuDomainRemoveRNGDevice(driver, vm, dev->data.rng) < 0)
            return -1;
4996
        break;
4997
    case VIR_DOMAIN_DEVICE_MEMORY:
4998 4999
        if (qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory) < 0)
            return -1;
5000
        break;
5001
    case VIR_DOMAIN_DEVICE_SHMEM:
5002 5003
        if (qemuDomainRemoveShmemDevice(driver, vm, dev->data.shmem) < 0)
            return -1;
5004
        break;
5005
    case VIR_DOMAIN_DEVICE_INPUT:
5006 5007
        if (qemuDomainRemoveInputDevice(vm, dev->data.input) < 0)
            return -1;
5008
        break;
5009
    case VIR_DOMAIN_DEVICE_REDIRDEV:
5010 5011
        if (qemuDomainRemoveRedirdevDevice(driver, vm, dev->data.redirdev) < 0)
            return -1;
5012
        break;
5013
    case VIR_DOMAIN_DEVICE_WATCHDOG:
5014 5015
        if (qemuDomainRemoveWatchdog(vm, dev->data.watchdog) < 0)
            return -1;
5016
        break;
J
Ján Tomko 已提交
5017
    case VIR_DOMAIN_DEVICE_VSOCK:
5018 5019
        if (qemuDomainRemoveVsockDevice(vm, dev->data.vsock) < 0)
            return -1;
J
Ján Tomko 已提交
5020 5021
        break;

5022 5023 5024 5025 5026 5027 5028 5029 5030 5031
    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:
5032
    case VIR_DOMAIN_DEVICE_TPM:
5033
    case VIR_DOMAIN_DEVICE_PANIC:
J
Ján Tomko 已提交
5034
    case VIR_DOMAIN_DEVICE_IOMMU:
5035 5036 5037 5038 5039 5040
    case VIR_DOMAIN_DEVICE_LAST:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("don't know how to remove a %s device"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }
5041 5042 5043 5044 5045

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

    return 0;
5046 5047 5048 5049
}


static void
5050 5051
qemuDomainMarkDeviceAliasForRemoval(virDomainObjPtr vm,
                                    const char *alias)
5052 5053 5054
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

5055 5056
    memset(&priv->unplug, 0, sizeof(priv->unplug));

5057
    priv->unplug.alias = alias;
5058 5059
}

5060 5061 5062 5063 5064 5065 5066 5067 5068 5069

static void
qemuDomainMarkDeviceForRemoval(virDomainObjPtr vm,
                               virDomainDeviceInfoPtr info)

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


5070 5071 5072 5073
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
5074
    priv->unplug.alias = NULL;
5075
    priv->unplug.eventSeen = false;
5076 5077
}

5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088

unsigned long long
qemuDomainGetUnplugTimeout(virDomainObjPtr vm)
{
    if (qemuDomainIsPSeries(vm->def))
        return QEMU_UNPLUG_TIMEOUT_PPC64;

    return QEMU_UNPLUG_TIMEOUT;
}


5089
/* Returns:
5090 5091
 *  -1 Unplug of the device failed
 *
5092
 *   0 removal of the device did not finish in qemuDomainRemoveDeviceWaitTime
5093 5094 5095 5096
 *
 *   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
5097 5098 5099 5100 5101 5102
 */
static int
qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    unsigned long long until;
5103
    int rc;
5104 5105

    if (virTimeMillisNow(&until) < 0)
5106
        return 1;
5107
    until += qemuDomainGetUnplugTimeout(vm);
5108

5109
    while (priv->unplug.alias) {
5110 5111 5112 5113 5114
        if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
            return 0;

        if (rc < 0) {
            VIR_WARN("Failed to wait on unplug condition for domain '%s' "
5115
                     "device '%s'", vm->def->name, priv->unplug.alias);
5116
            return 1;
5117 5118 5119
        }
    }

5120 5121 5122 5123 5124 5125
    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;
    }

5126 5127 5128
    return 1;
}

5129 5130 5131 5132 5133 5134 5135
/* 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
5136
qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
5137 5138
                              const char *devAlias,
                              qemuDomainUnpluggingDeviceStatus status)
5139 5140 5141
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

5142
    if (STREQ_NULLABLE(priv->unplug.alias, devAlias)) {
5143
        VIR_DEBUG("Removal of device '%s' continues in waiting thread", devAlias);
5144
        qemuDomainResetDeviceRemoval(vm);
5145
        priv->unplug.status = status;
5146
        priv->unplug.eventSeen = true;
5147
        virDomainObjBroadcast(vm);
5148
        return true;
5149
    }
5150
    return false;
5151 5152 5153
}


5154 5155 5156 5157 5158 5159
static int
qemuFindDisk(virDomainDefPtr def, const char *dst)
{
    size_t i;

    for (i = 0; i < def->ndisks; i++) {
5160
        if (STREQ(def->disks[i]->dst, dst))
5161 5162 5163 5164 5165 5166
            return i;
    }

    return -1;
}

5167
static int
5168
qemuDomainDetachPrepDisk(virDomainObjPtr vm,
5169
                         virDomainDiskDefPtr match,
5170
                         virDomainDiskDefPtr *detach)
5171 5172 5173 5174
{
    virDomainDiskDefPtr disk;
    int idx;

5175
    if ((idx = qemuFindDisk(vm->def, match->dst)) < 0) {
5176
        virReportError(VIR_ERR_OPERATION_FAILED,
5177
                       _("disk %s not found"), match->dst);
5178 5179
        return -1;
    }
5180
    *detach = disk = vm->def->disks[idx];
5181

5182
    switch ((virDomainDiskDevice) disk->device) {
5183 5184
    case VIR_DOMAIN_DISK_DEVICE_DISK:
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5185 5186 5187 5188 5189

        switch ((virDomainDiskBus) disk->bus) {
        case VIR_DOMAIN_DISK_BUS_VIRTIO:
        case VIR_DOMAIN_DISK_BUS_USB:
        case VIR_DOMAIN_DISK_BUS_SCSI:
5190
            break;
5191 5192 5193 5194 5195 5196 5197

        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:
5198 5199
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("This type of disk cannot be hot unplugged"));
5200
            return -1;
5201 5202 5203 5204

        case VIR_DOMAIN_DISK_BUS_LAST:
        default:
            virReportEnumRangeError(virDomainDiskBus, disk->bus);
5205
            return -1;
5206
        }
5207
        break;
5208 5209 5210

    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5211 5212 5213
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("disk device type '%s' cannot be detached"),
                       virDomainDiskDeviceTypeToString(disk->device));
5214
        return -1;
5215 5216 5217 5218

    case VIR_DOMAIN_DISK_DEVICE_LAST:
    default:
        virReportEnumRangeError(virDomainDiskDevice, disk->device);
5219
        return -1;
5220 5221
    }

5222 5223 5224
    if (qemuDomainDiskBlockJobIsActive(disk))
        return -1;

5225
    return 0;
5226 5227 5228
}


5229 5230 5231
static bool qemuDomainDiskControllerIsBusy(virDomainObjPtr vm,
                                           virDomainControllerDefPtr detach)
{
5232
    size_t i;
5233
    virDomainDiskDefPtr disk;
5234
    virDomainHostdevDefPtr hostdev;
5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256

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

5257 5258 5259 5260 5261 5262 5263 5264 5265
    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;
    }

5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288
    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;
    }
}

5289
static int
5290
qemuDomainDetachPrepController(virDomainObjPtr vm,
5291
                               virDomainControllerDefPtr match,
5292
                               virDomainControllerDefPtr *detach)
5293
{
5294
    int idx;
5295
    virDomainControllerDefPtr controller = NULL;
5296

5297
    if (match->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
5298 5299
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot unplugged."),
5300
                       virDomainControllerTypeToString(match->type));
5301 5302 5303
        return -1;
    }

5304
    if ((idx = virDomainControllerFind(vm->def, match->type, match->idx)) < 0) {
5305
        virReportError(VIR_ERR_DEVICE_MISSING,
5306
                       _("controller %s:%d not found"),
5307 5308
                       virDomainControllerTypeToString(match->type),
                       match->idx);
5309
        return -1;
5310 5311
    }

5312
    *detach = controller = vm->def->controllers[idx];
5313

5314
    if (qemuDomainControllerIsBusy(vm, controller)) {
5315 5316
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("device cannot be detached: device is busy"));
5317
        return -1;
5318
    }
5319

5320
    return 0;
5321 5322 5323
}


5324
/* search for a hostdev matching dev and detach it */
5325
static int
5326
qemuDomainDetachPrepHostdev(virDomainObjPtr vm,
5327
                            virDomainHostdevDefPtr match,
5328
                            virDomainHostdevDefPtr *detach)
5329
{
5330
    virDomainHostdevSubsysPtr subsys = &match->source.subsys;
5331
    virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb;
5332
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
5333
    virDomainHostdevSubsysSCSIPtr scsisrc = &subsys->u.scsi;
5334
    virDomainHostdevSubsysMediatedDevPtr mdevsrc = &subsys->u.mdev;
5335
    virDomainHostdevDefPtr hostdev = NULL;
5336 5337
    int idx;

5338
    if (match->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
5339
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5340
                       _("hot unplug is not supported for hostdev mode '%s'"),
5341
                       virDomainHostdevModeTypeToString(match->mode));
5342 5343 5344
        return -1;
    }

5345 5346
    idx = virDomainHostdevFind(vm->def, match, &hostdev);
    *detach = hostdev;
5347 5348

    if (idx < 0) {
5349
        switch (subsys->type) {
5350
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
5351
            virReportError(VIR_ERR_DEVICE_MISSING,
5352 5353
                           _("host pci device " VIR_PCI_DEVICE_ADDRESS_FMT
                             " not found"),
5354 5355
                           pcisrc->addr.domain, pcisrc->addr.bus,
                           pcisrc->addr.slot, pcisrc->addr.function);
5356 5357
            break;
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
5358
            if (usbsrc->bus && usbsrc->device) {
5359
                virReportError(VIR_ERR_DEVICE_MISSING,
5360
                               _("host usb device %03d.%03d not found"),
5361
                               usbsrc->bus, usbsrc->device);
5362
            } else {
5363
                virReportError(VIR_ERR_DEVICE_MISSING,
5364
                               _("host usb device vendor=0x%.4x product=0x%.4x not found"),
5365
                               usbsrc->vendor, usbsrc->product);
5366 5367
            }
            break;
5368
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
5369 5370 5371
            if (scsisrc->protocol ==
                VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
                virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
5372
                virReportError(VIR_ERR_DEVICE_MISSING,
5373
                               _("host scsi iSCSI path %s not found"),
5374
                               iscsisrc->src->path);
5375 5376 5377
            } else {
                 virDomainHostdevSubsysSCSIHostPtr scsihostsrc =
                     &scsisrc->u.host;
5378
                 virReportError(VIR_ERR_DEVICE_MISSING,
5379
                                _("host scsi device %s:%u:%u.%llu not found"),
5380 5381 5382
                                scsihostsrc->adapter, scsihostsrc->bus,
                                scsihostsrc->target, scsihostsrc->unit);
            }
5383
            break;
5384
        }
5385 5386 5387 5388 5389
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
            virReportError(VIR_ERR_DEVICE_MISSING,
                           _("mediated device '%s' not found"),
                           mdevsrc->uuidstr);
            break;
5390 5391
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
            break;
5392
        default:
5393 5394
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"), subsys->type);
5395 5396 5397 5398 5399
            break;
        }
        return -1;
    }

5400
    return 0;
5401 5402
}

5403

5404
static int
5405
qemuDomainDetachPrepShmem(virDomainObjPtr vm,
5406
                          virDomainShmemDefPtr match,
5407
                          virDomainShmemDefPtr *detach)
5408 5409 5410 5411
{
    ssize_t idx = -1;
    virDomainShmemDefPtr shmem = NULL;

5412
    if ((idx = virDomainShmemDefFind(vm->def, match)) < 0) {
5413
        virReportError(VIR_ERR_DEVICE_MISSING,
5414 5415
                       _("model '%s' shmem device not present "
                         "in domain configuration"),
5416
                       virDomainShmemModelTypeToString(match->model));
5417 5418 5419
        return -1;
    }

5420
    *detach = shmem = vm->def->shmems[idx];
5421 5422 5423 5424 5425 5426 5427 5428 5429 5430

    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));
5431
        G_GNUC_FALLTHROUGH;
5432 5433 5434 5435
    case VIR_DOMAIN_SHMEM_MODEL_LAST:
        return -1;
    }

5436
    return 0;
5437 5438 5439
}


5440
static int
5441
qemuDomainDetachPrepWatchdog(virDomainObjPtr vm,
5442
                             virDomainWatchdogDefPtr match,
5443
                             virDomainWatchdogDefPtr *detach)
M
Michal Privoznik 已提交
5444
{
5445 5446 5447
    virDomainWatchdogDefPtr watchdog;

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

5449 5450 5451 5452 5453 5454
    if (!watchdog) {
        virReportError(VIR_ERR_DEVICE_MISSING, "%s",
                       _("watchdog device not present in domain configuration"));
        return -1;
    }

M
Michal Privoznik 已提交
5455 5456 5457
    /* 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. */
5458 5459 5460
    if (!(watchdog->model == match->model &&
          watchdog->action == match->action &&
          virDomainDeviceInfoAddressIsEqual(&match->info, &watchdog->info))) {
5461
        virReportError(VIR_ERR_DEVICE_MISSING,
5462 5463 5464
                       _("model '%s' watchdog device not present "
                         "in domain configuration"),
                       virDomainWatchdogModelTypeToString(watchdog->model));
M
Michal Privoznik 已提交
5465 5466 5467 5468 5469 5470 5471 5472 5473 5474
        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;
    }

5475
    return 0;
M
Michal Privoznik 已提交
5476 5477 5478
}


5479
static int
5480
qemuDomainDetachPrepRedirdev(virDomainObjPtr vm,
5481
                             virDomainRedirdevDefPtr match,
5482
                             virDomainRedirdevDefPtr *detach)
5483
{
5484
    virDomainRedirdevDefPtr redirdev;
5485 5486
    ssize_t idx;

5487
    if ((idx = virDomainRedirdevDefFind(vm->def, match)) < 0) {
5488 5489 5490 5491 5492
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("no matching redirdev was not found"));
        return -1;
    }

5493
    *detach = redirdev = vm->def->redirdevs[idx];
5494

5495
    return 0;
5496 5497 5498
}


5499
static int
5500
qemuDomainDetachPrepNet(virDomainObjPtr vm,
5501
                        virDomainNetDefPtr match,
5502
                        virDomainNetDefPtr *detach)
5503
{
5504
    int detachidx;
5505
    virDomainNetDefPtr net = NULL;
5506

5507
    if ((detachidx = virDomainNetFindIdx(vm->def, match)) < 0)
5508
        return -1;
5509

5510
    *detach = net = vm->def->nets[detachidx];
5511

5512 5513
    return 0;
}
5514

5515

5516
static int
5517
qemuDomainDetachDeviceChr(virQEMUDriverPtr driver,
5518 5519 5520
                          virDomainObjPtr vm,
                          virDomainChrDefPtr chr,
                          bool async)
5521 5522 5523 5524 5525
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDefPtr vmdef = vm->def;
    virDomainChrDefPtr tmpChr;
5526
    bool guestfwd = false;
5527 5528

    if (!(tmpChr = virDomainChrFind(vmdef, chr))) {
5529
        virReportError(VIR_ERR_DEVICE_MISSING,
5530 5531 5532
                       _("chr type '%s' device not present "
                         "in domain configuration"),
                       virDomainChrDeviceTypeToString(chr->deviceType));
5533
        goto cleanup;
5534 5535
    }

5536 5537 5538 5539 5540 5541
    /* 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)
5542
        qemuDomainMarkDeviceForRemoval(vm, &tmpChr->info);
5543

5544
    if (guestfwd) {
5545 5546 5547 5548 5549 5550 5551
        int rc;
        qemuDomainObjEnterMonitor(driver, vm);
        rc = qemuMonitorRemoveNetdev(priv->mon, tmpChr->info.alias);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            rc = -1;

        if (rc < 0)
5552 5553
            goto cleanup;
    } else {
5554
        if (qemuDomainDeleteDevice(vm, tmpChr->info.alias) < 0)
5555
            goto cleanup;
5556
    }
5557

5558 5559 5560
    if (guestfwd) {
        ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr, false);
    } else if (async) {
5561 5562 5563
        ret = 0;
    } else {
        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
5564
            ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr, true);
5565
    }
5566

5567
 cleanup:
5568 5569
    if (!async)
        qemuDomainResetDeviceRemoval(vm);
5570 5571
    return ret;
}
5572 5573


5574
static int
5575
qemuDomainDetachPrepRNG(virDomainObjPtr vm,
5576
                        virDomainRNGDefPtr match,
5577
                        virDomainRNGDefPtr *detach)
5578 5579
{
    ssize_t idx;
5580
    virDomainRNGDefPtr rng;
5581

5582
    if ((idx = virDomainRNGFind(vm->def, match)) < 0) {
5583
        virReportError(VIR_ERR_DEVICE_MISSING,
5584 5585
                       _("model '%s' RNG device not present "
                         "in domain configuration"),
5586
                       virDomainRNGBackendTypeToString(match->model));
5587 5588 5589
        return -1;
    }

5590
    *detach = rng = vm->def->rngs[idx];
5591

5592
    return 0;
5593
}
5594 5595


5596
static int
5597
qemuDomainDetachPrepMemory(virDomainObjPtr vm,
5598
                           virDomainMemoryDefPtr match,
5599
                           virDomainMemoryDefPtr *detach)
5600 5601 5602 5603
{
    virDomainMemoryDefPtr mem;
    int idx;

5604
    qemuDomainMemoryDeviceAlignSize(vm->def, match);
5605

5606
    if ((idx = virDomainMemoryFindByDef(vm->def, match)) < 0) {
5607
        virReportError(VIR_ERR_DEVICE_MISSING,
5608 5609
                       _("model '%s' memory device not present "
                         "in the domain configuration"),
5610
                       virDomainMemoryModelTypeToString(match->model));
5611 5612 5613
        return -1;
    }

5614
    *detach = mem = vm->def->mems[idx];
5615

5616
    return 0;
5617
}
5618 5619


5620
static int
5621 5622
qemuDomainDetachPrepInput(virDomainObjPtr vm,
                          virDomainInputDefPtr match,
5623
                          virDomainInputDefPtr *detach)
5624 5625 5626 5627
{
    virDomainInputDefPtr input;
    int idx;

5628
    if ((idx = virDomainInputDefFind(vm->def, match)) < 0) {
5629 5630 5631 5632
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("matching input device not found"));
        return -1;
    }
5633
    *detach = input = vm->def->inputs[idx];
5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649

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

5650
    return 0;
5651 5652 5653
}


5654
static int
5655 5656
qemuDomainDetachPrepVsock(virDomainObjPtr vm,
                          virDomainVsockDefPtr match,
5657
                          virDomainVsockDefPtr *detach)
5658
{
5659
    virDomainVsockDefPtr vsock;
5660

5661
    *detach = vsock = vm->def->vsock;
5662
    if (!vsock ||
5663
        !virDomainVsockDefEquals(match, vsock)) {
5664 5665 5666 5667 5668
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("matching vsock device not found"));
        return -1;
    }

5669
    return 0;
5670 5671 5672
}


5673
static int
5674 5675 5676
qemuDomainDetachDeviceLease(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainLeaseDefPtr lease)
5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696
{
    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;
}


5697 5698
int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
5699
                           virDomainDeviceDefPtr match,
5700 5701 5702
                           virQEMUDriverPtr driver,
                           bool async)
{
5703
    virDomainDeviceDef detach = { .type = match->type };
5704
    virDomainDeviceInfoPtr info = NULL;
5705 5706
    int ret = -1;

5707
    switch ((virDomainDeviceType)match->type) {
5708 5709 5710 5711 5712 5713
        /*
         * 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:
5714
        return qemuDomainDetachDeviceLease(driver, vm, match->data.lease);
5715 5716

    case VIR_DOMAIN_DEVICE_CHR:
5717
        return qemuDomainDetachDeviceChr(driver, vm, match->data.chr, async);
5718 5719 5720 5721 5722 5723 5724 5725

        /*
         * 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.
         */
5726
    case VIR_DOMAIN_DEVICE_DISK:
5727 5728
        if (qemuDomainDetachPrepDisk(vm, match->data.disk,
                                     &detach.data.disk) < 0) {
5729 5730
            return -1;
        }
5731 5732
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5733 5734
        if (qemuDomainDetachPrepController(vm, match->data.controller,
                                           &detach.data.controller) < 0) {
5735 5736
            return -1;
        }
5737 5738
        break;
    case VIR_DOMAIN_DEVICE_NET:
5739 5740
        if (qemuDomainDetachPrepNet(vm, match->data.net,
                                    &detach.data.net) < 0) {
5741 5742
            return -1;
        }
5743 5744
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
5745 5746
        if (qemuDomainDetachPrepHostdev(vm, match->data.hostdev,
                                        &detach.data.hostdev) < 0) {
5747 5748
            return -1;
        }
5749 5750
        break;
    case VIR_DOMAIN_DEVICE_RNG:
5751 5752
        if (qemuDomainDetachPrepRNG(vm, match->data.rng,
                                    &detach.data.rng) < 0) {
5753 5754
            return -1;
        }
5755 5756
        break;
    case VIR_DOMAIN_DEVICE_MEMORY:
5757 5758
        if (qemuDomainDetachPrepMemory(vm, match->data.memory,
                                       &detach.data.memory) < 0) {
5759 5760
            return -1;
        }
5761 5762
        break;
    case VIR_DOMAIN_DEVICE_SHMEM:
5763 5764
        if (qemuDomainDetachPrepShmem(vm, match->data.shmem,
                                      &detach.data.shmem) < 0) {
5765 5766
            return -1;
        }
5767 5768
        break;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
5769 5770
        if (qemuDomainDetachPrepWatchdog(vm, match->data.watchdog,
                                         &detach.data.watchdog) < 0) {
5771 5772
            return -1;
        }
5773 5774
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
5775
        if (qemuDomainDetachPrepInput(vm, match->data.input,
5776
                                      &detach.data.input) < 0) {
5777 5778
            return -1;
        }
5779 5780
        break;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
5781 5782
        if (qemuDomainDetachPrepRedirdev(vm, match->data.redirdev,
                                         &detach.data.redirdev) < 0) {
5783 5784
            return -1;
        }
5785 5786
        break;
    case VIR_DOMAIN_DEVICE_VSOCK:
5787
        if (qemuDomainDetachPrepVsock(vm, match->data.vsock,
5788
                                      &detach.data.vsock) < 0) {
5789 5790
            return -1;
        }
5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807
        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"),
5808
                       virDomainDeviceTypeToString(match->type));
5809
        return -1;
5810 5811
    }

5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838
    /* "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: "
5839
                         VIR_PCI_DEVICE_ADDRESS_FMT),
5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869
                       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);
5870

5871 5872 5873 5874
    return ret;
}


5875 5876 5877 5878 5879 5880 5881 5882 5883 5884
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;
5885
    virErrorPtr save_error = NULL;
5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909
    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);

5910 5911 5912 5913 5914 5915
    virErrorPreserveLast(&save_error);

    for (i = vcpu; i < vcpu + nvcpus; i++)
        ignore_value(virCgroupDelThread(priv->cgroup, VIR_CGROUP_THREAD_VCPU, i));

    virErrorRestore(&save_error);
5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941

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


5942
static int
5943
qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
5944
                         virQEMUDriverConfigPtr cfg,
5945 5946 5947 5948 5949 5950 5951 5952
                         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;
5953
    int ret = -1;
5954 5955 5956 5957 5958 5959 5960 5961 5962

    if (!vcpupriv->alias) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("vcpu '%u' can't be unplugged"), vcpu);
        return -1;
    }

    qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias);

5963 5964 5965
    if (qemuDomainDeleteDevice(vm, vcpupriv->alias) < 0) {
        if (virDomainObjIsActive(vm))
            virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
5966
        goto cleanup;
5967 5968 5969 5970
    }

    if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
        if (rc == 0)
5971 5972 5973
            virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s",
                           _("vcpu unplug request timed out. Unplug result "
                             "must be manually inspected in the domain"));
5974

5975
        goto cleanup;
5976 5977
    }

5978 5979 5980
    if (qemuDomainRemoveVcpu(driver, vm, vcpu) < 0)
        goto cleanup;

5981 5982
    qemuDomainVcpuPersistOrder(vm->def);

5983
    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
5984 5985
        goto cleanup;

5986 5987 5988 5989 5990
    ret = 0;

 cleanup:
    qemuDomainResetDeviceRemoval(vm);
    return ret;
5991
}
5992 5993 5994 5995


static int
qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
5996
                         virQEMUDriverConfigPtr cfg,
5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010
                         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) {
6011
        vcpupriv->alias = g_strdup_printf("vcpu%u", vcpu);
6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055

        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;

6056 6057
    qemuDomainVcpuPersistOrder(vm->def);

6058
    if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
6059 6060
        goto cleanup;

6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 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
    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) {
6182 6183
            if (qemuDomainHotplugAddVcpu(driver, cfg, vm, nextvcpu) < 0)
                goto cleanup;
6184 6185 6186 6187 6188 6189
        }
    } else {
        for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) {
            if (!virBitmapIsBitSet(vcpumap, nextvcpu))
                continue;

6190 6191
            if (qemuDomainHotplugDelVcpu(driver, cfg, vm, nextvcpu) < 0)
                goto cleanup;
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
        }
    }

    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) {
6237
                /* non-hotpluggable vcpus need to be clustered at the beginning,
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
                 * 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)
{
6283
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315
    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);

6316
        if (virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0)
6317 6318 6319 6320 6321 6322 6323 6324 6325
            goto cleanup;
    }

    ret = 0;

 cleanup:
    virBitmapFree(vcpumap);
    return ret;
}
6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337


static void
qemuDomainSetVcpuConfig(virDomainDefPtr def,
                        virBitmapPtr map,
                        bool state)
{
    virDomainVcpuDefPtr vcpu;
    ssize_t next = -1;

    def->individualvcpus = true;

6338 6339 6340
    /* ordering information may become invalid, thus clear it */
    virDomainDefVcpuOrderClear(def);

6341
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372
        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 */
6373
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6374 6375 6376 6377 6378
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        if (vcpu->online == state) {
            virReportError(VIR_ERR_INVALID_ARG,
6379
                           _("vcpu '%zd' is already in requested state"), next);
6380 6381 6382 6383 6384
            goto cleanup;
        }

        if (vcpu->online && !vcpu->hotpluggable) {
            virReportError(VIR_ERR_INVALID_ARG,
6385
                           _("vcpu '%zd' can't be hotunplugged"), next);
6386 6387 6388 6389 6390 6391 6392
            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;
6393
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6394 6395 6396 6397 6398 6399 6400
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);

        if (vcpupriv->vcpus == 0) {
            virReportError(VIR_ERR_INVALID_ARG,
6401
                           _("vcpu '%zd' belongs to a larger hotpluggable entity, "
6402 6403 6404 6405 6406 6407 6408 6409
                             "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 "
6410
                                 "hotpluggable entity '%zd-%zd' which was "
6411 6412 6413 6414 6415 6416 6417 6418 6419 6420
                                 "partially selected"),
                               i, next, next + vcpupriv->vcpus - 1);
                goto cleanup;
            }

            /* clear the subthreads */
            ignore_value(virBitmapClearBit(map, i));
        }
    }

6421
    ret = g_steal_pointer(&map);
6422 6423 6424 6425 6426 6427 6428

 cleanup:
    virBitmapFree(map);
    return ret;
}


6429
static int
6430
qemuDomainVcpuValidateConfig(virDomainDefPtr def,
6431
                             virBitmapPtr map)
6432
{
6433 6434 6435
    virDomainVcpuDefPtr vcpu;
    size_t maxvcpus = virDomainDefGetVcpusMax(def);
    ssize_t next;
6436
    ssize_t firstvcpu = -1;
6437

6438 6439
    /* vcpu 0 can't be modified */
    if (virBitmapIsBitSet(map, 0)) {
6440
        virReportError(VIR_ERR_INVALID_ARG, "%s",
6441
                       _("vCPU '0' can't be modified"));
6442 6443 6444
        return -1;
    }

6445 6446 6447 6448 6449 6450
    /* 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 */
6451 6452 6453 6454
        if (virBitmapIsBitSet(map, next)) {
            if (firstvcpu < 0)
                firstvcpu = next;

6455
            continue;
6456
        }
6457 6458 6459 6460

        if (vcpu->online && vcpu->hotpluggable == VIR_TRISTATE_BOOL_NO) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("vcpu '%zd' can't be modified as it is followed "
6461
                             "by non-hotpluggable online vcpus"), firstvcpu);
6462 6463 6464 6465
            return -1;
        }
    }

6466 6467 6468 6469
    return 0;
}


6470 6471 6472 6473 6474 6475 6476 6477
int
qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainDefPtr def,
                          virDomainDefPtr persistentDef,
                          virBitmapPtr map,
                          bool state)
{
6478
    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503
    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;
        }
    }

6504
    if (persistentDef) {
6505
        if (qemuDomainVcpuValidateConfig(persistentDef, map) < 0)
6506 6507 6508
            goto cleanup;
    }

6509 6510 6511 6512 6513 6514 6515
    if (livevcpus &&
        qemuDomainSetVcpusLive(driver, cfg, vm, livevcpus, state) < 0)
        goto cleanup;

    if (persistentDef) {
        qemuDomainSetVcpuConfig(persistentDef, map, state);

6516
        if (virDomainDefSave(persistentDef, driver->xmlopt, cfg->configDir) < 0)
6517 6518 6519 6520 6521 6522 6523 6524 6525
            goto cleanup;
    }

    ret = 0;

 cleanup:
    virBitmapFree(livevcpus);
    return ret;
}