qemu_hotplug.c 211.9 KB
Newer Older
1
/*
2
 * qemu_hotplug.c: QEMU device hotplug management
3
 *
4
 * Copyright (C) 2006-2016 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25
 */


#include <config.h>

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

#define VIR_FROM_THIS VIR_FROM_QEMU
61 62 63

VIR_LOG_INIT("qemu.qemu_hotplug");

64
#define CHANGE_MEDIA_TIMEOUT 5000
65

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


70 71 72
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm);

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

    qemuDomainObjEnterMonitor(driver, vm);

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

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

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

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

    return rc;
}


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

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

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

    ret = 0;

 cleanup:
    VIR_FREE(devstr_zpci);
    return ret;
}


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

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

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

    ret = 0;

 cleanup:
    VIR_FREE(zpciAlias);
    return ret;
}


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

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

    return 0;
}


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

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

    return 0;
}


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

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

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

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

    return 0;
}


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

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

274
    if (!(driveAlias = qemuAliasDiskDriveFromDisk(disk)))
275
        goto cleanup;
276

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

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

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

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

300
    if (!virStorageSourceIsEmpty(newsrc)) {
301
        if (qemuGetDriveSourceString(newsrc, NULL, &sourcestr) < 0)
302
            goto cleanup;
303

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

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

316
    if (rc < 0)
317
        goto cleanup;
318

319
    ret = 0;
320

321
 cleanup:
322
    VIR_FREE(driveAlias);
323
    VIR_FREE(sourcestr);
324 325 326
    return ret;
}

327

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

352
    if (priv->prDaemonRunning ||
353
        !virStorageSourceChainHasManagedPR(src))
354 355
        return 0;

356
    if (!(props = qemuBuildPRManagedManagerInfoProps(priv)))
357 358
        return -1;

359 360
    if (qemuProcessStartManagedPRDaemon(vm) < 0)
        goto cleanup;
361

362 363 364 365 366 367 368 369 370 371
    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;

372
    ret = 0;
373

374
 cleanup:
375 376
    if (ret < 0 && daemonStarted)
        qemuProcessKillManagedPRDaemon(vm);
377 378
    virJSONValueFree(props);
    return ret;
379 380 381
}


382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
/**
 * 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;
398
    int ret = -1;
399

400
    if (virDomainDefHasManagedPR(vm->def))
401 402
        return 0;

403 404
    virErrorPreserveLast(&orig_err);

405
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
406
        goto cleanup;
407 408
    ignore_value(qemuMonitorDelObject(priv->mon, qemuDomainGetManagedPRAlias()));
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
409
        goto cleanup;
410 411 412

    qemuProcessKillManagedPRDaemon(vm);

413 414 415 416
    ret = 0;
 cleanup:
    virErrorRestore(&orig_err);
    return ret;
417 418 419
}


420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
struct _qemuHotplugDiskSourceData {
    qemuBlockStorageSourceAttachDataPtr *backends;
    size_t nbackends;
};
typedef struct _qemuHotplugDiskSourceData qemuHotplugDiskSourceData;
typedef qemuHotplugDiskSourceData *qemuHotplugDiskSourceDataPtr;


static void
qemuHotplugDiskSourceDataFree(qemuHotplugDiskSourceDataPtr data)
{
    size_t i;

    if (!data)
        return;

    for (i = 0; i < data->nbackends; i++)
        qemuBlockStorageSourceAttachDataFree(data->backends[i]);

439
    VIR_FREE(data->backends);
440 441 442 443
    VIR_FREE(data);
}


444 445
static qemuHotplugDiskSourceDataPtr
qemuHotplugDiskSourceRemovePrepare(virDomainDiskDefPtr disk,
446
                                   virStorageSourcePtr src,
447
                                   virQEMUCapsPtr qemuCaps)
448
{
449
    VIR_AUTOPTR(qemuBlockStorageSourceAttachData) backend = NULL;
450 451 452
    qemuHotplugDiskSourceDataPtr data = NULL;
    qemuHotplugDiskSourceDataPtr ret = NULL;
    char *drivealias = NULL;
453
    virStorageSourcePtr n;
454 455 456 457

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

458
    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) {
459
        for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
460
            if (!(backend = qemuBlockStorageSourceDetachPrepare(n, NULL)))
461
                goto cleanup;
462

463 464 465 466 467 468 469
            if (VIR_APPEND_ELEMENT(data->backends, data->nbackends, backend) < 0)
                goto cleanup;
        }
    } else {
        if (!(drivealias = qemuAliasDiskDriveFromDisk(disk)))
            goto cleanup;

470
        if (!(backend = qemuBlockStorageSourceDetachPrepare(src, drivealias)))
471 472 473 474 475
            goto cleanup;

        if (VIR_APPEND_ELEMENT(data->backends, data->nbackends, backend) < 0)
            goto cleanup;
    }
476 477 478 479 480 481 482 483 484

    VIR_STEAL_PTR(ret, data);

 cleanup:
    qemuHotplugDiskSourceDataFree(data);
    return ret;
}


485 486 487
/**
 * qemuHotplugDiskSourceAttachPrepare:
 * @disk: disk to generate attachment data for
488
 * @src: disk source to prepare attachment
489 490 491 492 493 494 495
 * @qemuCaps: capabilities of the qemu process
 *
 * Prepares and returns qemuHotplugDiskSourceData structure filled with all data
 * which will fully attach the source backend of the disk to a given VM.
 */
static qemuHotplugDiskSourceDataPtr
qemuHotplugDiskSourceAttachPrepare(virDomainDiskDefPtr disk,
496
                                   virStorageSourcePtr src,
497 498
                                   virQEMUCapsPtr qemuCaps)
{
499
    VIR_AUTOPTR(qemuBlockStorageSourceAttachData) backend = NULL;
500 501
    qemuHotplugDiskSourceDataPtr data;
    qemuHotplugDiskSourceDataPtr ret = NULL;
502
    virStorageSourcePtr savesrc = NULL;
503
    virStorageSourcePtr n;
504 505 506 507

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

508
    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) {
509
        for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
510 511
            if (!(backend = qemuBlockStorageSourceAttachPrepareBlockdev(n)))
                goto cleanup;
512

513 514 515 516 517 518 519
            if (qemuBuildStorageSourceAttachPrepareCommon(n, backend, qemuCaps) < 0)
                goto cleanup;

            if (VIR_APPEND_ELEMENT(data->backends, data->nbackends, backend) < 0)
                goto cleanup;
        }
    } else {
520 521 522
        VIR_STEAL_PTR(savesrc, disk->src);
        disk->src = src;

523 524 525
        if (!(backend = qemuBuildStorageSourceAttachPrepareDrive(disk, qemuCaps)))
            goto cleanup;

526 527 528
        VIR_STEAL_PTR(disk->src, savesrc);

        if (qemuBuildStorageSourceAttachPrepareCommon(src, backend, qemuCaps) < 0)
529 530 531 532 533
            goto cleanup;

        if (VIR_APPEND_ELEMENT(data->backends, data->nbackends, backend) < 0)
            goto cleanup;
    }
534 535 536 537

    VIR_STEAL_PTR(ret, data);

 cleanup:
538 539 540
    if (savesrc)
        VIR_STEAL_PTR(disk->src, savesrc);

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
    qemuHotplugDiskSourceDataFree(data);
    return ret;
}


/**
 * qemuHotplugDiskSourceAttach:
 * @mon: monitor object
 * @data: disk backend data object describing what to remove
 *
 * Attach a disk source backend with all relevant pieces. Caller must enter the
 * monitor context for @mon.
 */
static int
qemuHotplugDiskSourceAttach(qemuMonitorPtr mon,
                            qemuHotplugDiskSourceDataPtr data)
{
    size_t i;

    for (i = data->nbackends; i > 0; i--) {
        if (qemuBlockStorageSourceAttachApply(mon, data->backends[i - 1]) < 0)
            return -1;
    }

565

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
    return 0;
}


/**
 * qemuHotplugDiskSourceRemove:
 * @mon: monitor object
 * @data: disk backend data object describing what to remove
 *
 * Remove a disk source backend with all relevant pieces. This function
 * preserves the error which was set prior to calling it. Caller must enter the
 * monitor context for @mon.
 */
static void
qemuHotplugDiskSourceRemove(qemuMonitorPtr mon,
                            qemuHotplugDiskSourceDataPtr data)

{
    size_t i;

    for (i = 0; i < data->nbackends; i++)
        qemuBlockStorageSourceAttachRollback(mon, data->backends[i]);
}


591 592 593 594 595
/**
 * qemuDomainChangeMediaBlockdev:
 * @driver: qemu driver structure
 * @vm: domain definition
 * @disk: disk definition to change the source of
596
 * @oldsrc: old source definition
597 598 599 600 601 602 603 604 605 606 607 608 609 610
 * @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,
611
                              virStorageSourcePtr oldsrc,
612 613 614 615 616 617 618 619 620 621 622
                              virStorageSourcePtr newsrc,
                              bool force)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
    qemuHotplugDiskSourceDataPtr newbackend = NULL;
    qemuHotplugDiskSourceDataPtr oldbackend = NULL;
    char *nodename = NULL;
    int rc;
    int ret = -1;

623 624
    if (!virStorageSourceIsEmpty(oldsrc) &&
        !(oldbackend = qemuHotplugDiskSourceRemovePrepare(disk, oldsrc,
625
                                                          priv->qemuCaps)))
626 627
        goto cleanup;

628 629
    if (!virStorageSourceIsEmpty(newsrc)) {
        if (!(newbackend = qemuHotplugDiskSourceAttachPrepare(disk, newsrc,
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
                                                              priv->qemuCaps)))
            goto cleanup;

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

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

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

    qemuDomainObjEnterMonitor(driver, vm);

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

    if (rc == 0 && oldbackend)
        qemuHotplugDiskSourceRemove(priv->mon, oldbackend);

    if (newbackend && nodename) {
        if (rc == 0)
            rc = qemuHotplugDiskSourceAttach(priv->mon, newbackend);

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

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

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

    ret = 0;

 cleanup:
    qemuHotplugDiskSourceDataFree(newbackend);
    qemuHotplugDiskSourceDataFree(oldbackend);
674
    VIR_FREE(nodename);
675 676 677 678
    return ret;
}


679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
/**
 * 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
 */
694
int
695 696 697 698 699 700
qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainDiskDefPtr disk,
                               virStorageSourcePtr newsrc,
                               bool force)
{
701
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
702
    qemuDomainObjPrivatePtr priv = vm->privateData;
703
    virStorageSourcePtr oldsrc = disk->src;
704
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
705
    bool sharedAdded = false;
706 707 708
    int ret = -1;
    int rc;

709 710 711 712 713 714
    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;
    }

715 716
    disk->src = newsrc;

717 718 719 720 721 722 723 724
    if (virDomainDiskTranslateSourcePool(disk) < 0)
        goto cleanup;

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

    sharedAdded = true;

725
    if (qemuDomainDetermineDiskChain(driver, vm, disk, NULL, true) < 0)
726 727
        goto cleanup;

728 729 730
    if (qemuDomainPrepareDiskSource(disk, priv, cfg) < 0)
        goto cleanup;

731
    if (qemuDomainStorageSourceChainAccessAllow(driver, vm, newsrc) < 0)
732 733
        goto cleanup;

734 735 736
    if (qemuHotplugAttachManagedPR(driver, vm, newsrc, QEMU_ASYNC_JOB_NONE) < 0)
        goto cleanup;

737
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
738
        rc = qemuDomainChangeMediaBlockdev(driver, vm, disk, oldsrc, newsrc, force);
739 740
    else
        rc = qemuDomainChangeMediaLegacy(driver, vm, disk, newsrc, force);
741

742
    virDomainAuditDisk(vm, oldsrc, newsrc, "update", rc >= 0);
743

744
    if (rc < 0)
745 746 747
        goto cleanup;

    /* remove the old source from shared device list */
748
    disk->src = oldsrc;
749
    ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));
750
    ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, oldsrc));
751

752
    /* media was changed, so we can remove the old media definition now */
753
    virObjectUnref(oldsrc);
754 755
    oldsrc = NULL;
    disk->src = newsrc;
756

757 758 759
    ret = 0;

 cleanup:
760 761 762 763 764
    /* undo changes to the new disk */
    if (ret < 0) {
        if (sharedAdded)
            ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));

765
        ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, newsrc));
766 767 768 769 770 771
    }

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

    /* revert old image do the disk definition */
772 773 774
    if (oldsrc)
        disk->src = oldsrc;

775 776 777 778
    return ret;
}


779 780 781 782 783
/**
 * 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. */
784
static int
785
qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
786 787
                            virDomainObjPtr vm,
                            virDomainDiskDefPtr disk)
788
{
789
    int ret = -1;
790
    qemuDomainObjPrivatePtr priv = vm->privateData;
791
    qemuHotplugDiskSourceDataPtr diskdata = NULL;
792
    char *devstr = NULL;
793
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
794 795
    VIR_AUTOPTR(virJSONValue) corProps = NULL;
    VIR_AUTOFREE(char *) corAlias = NULL;
796

797
    if (qemuDomainStorageSourceChainAccessAllow(driver, vm, disk->src) < 0)
798
        goto cleanup;
799

800
    if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
801
        goto error;
802

803 804 805
    if (qemuDomainPrepareDiskSource(disk, priv, cfg) < 0)
        goto error;

806 807 808 809 810 811
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV)) {
        if (disk->copy_on_read == VIR_TRISTATE_SWITCH_ON &&
            !(corProps = qemuBlockStorageGetCopyOnReadProps(disk)))
        goto cleanup;
    }

812 813
    if (!(diskdata = qemuHotplugDiskSourceAttachPrepare(disk, disk->src,
                                                        priv->qemuCaps)))
814 815
        goto error;

816
    if (!(devstr = qemuBuildDiskDeviceStr(vm->def, disk, 0, priv->qemuCaps)))
817
        goto error;
818

819
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks + 1) < 0)
820 821
        goto error;

822 823
    if (qemuHotplugAttachManagedPR(driver, vm, disk->src, QEMU_ASYNC_JOB_NONE) < 0)
        goto error;
824

825
    qemuDomainObjEnterMonitor(driver, vm);
826

827
    if (qemuHotplugDiskSourceAttach(priv->mon, diskdata) < 0)
828
        goto exit_monitor;
829

830 831 832 833
    if (corProps &&
        qemuMonitorAddObject(priv->mon, &corProps, &corAlias) < 0)
        goto exit_monitor;

834 835 836 837 838
    if (qemuDomainAttachExtensionDevice(priv->mon, &disk->info) < 0)
        goto exit_monitor;

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &disk->info));
839
        goto exit_monitor;
840
    }
841

842
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
843
        ret = -2;
844
        goto error;
845
    }
846

847
    virDomainAuditDisk(vm, NULL, disk->src, "attach", true);
848 849

    virDomainDiskInsertPreAlloced(vm->def, disk);
850
    ret = 0;
851

852
 cleanup:
853
    qemuHotplugDiskSourceDataFree(diskdata);
854
    qemuDomainSecretDiskDestroy(disk);
855
    VIR_FREE(devstr);
856
    return ret;
857

858
 exit_monitor:
859 860
    if (corAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, corAlias));
861
    qemuHotplugDiskSourceRemove(priv->mon, diskdata);
862

863
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
864
        ret = -2;
865 866
    if (qemuHotplugRemoveManagedPR(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
        ret = -2;
867 868 869

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

870
 error:
871
    ignore_value(qemuDomainStorageSourceChainAccessRevoke(driver, vm, disk->src));
872
    goto cleanup;
873 874 875
}


876
static int
877
qemuDomainAttachVirtioDiskDevice(virQEMUDriverPtr driver,
878 879 880 881 882 883 884 885 886 887
                                 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;

888
    if ((rv = qemuDomainAttachDiskGeneric(driver, vm, disk)) < 0) {
889
        if (rv == -1 && releaseaddr)
890
            qemuDomainReleaseDeviceAddress(vm, &disk->info);
891 892 893 894 895 896 897 898

        return -1;
    }

    return 0;
}


899 900 901
int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
                                     virDomainObjPtr vm,
                                     virDomainControllerDefPtr controller)
902 903 904 905 906
{
    int ret = -1;
    const char* type = virDomainControllerTypeToString(controller->type);
    char *devstr = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
907 908
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CONTROLLER,
                               { .controller = controller } };
909
    bool releaseaddr = false;
910

911 912 913 914 915 916 917
    if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
                       virDomainControllerTypeToString(controller->type));
        return -1;
    }

918 919 920 921 922 923 924 925
    /* 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);

926
    if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) {
927 928 929 930
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target %s:%d already exists"),
                       type, controller->idx);
        return -1;
931 932
    }

933 934
    if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, "controller") < 0)
        return -1;
935

936 937 938
    if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, controller) < 0)
        goto cleanup;

939
    if (qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, &devstr) < 0)
940 941 942
        goto cleanup;

    if (!devstr)
943
        goto cleanup;
944

945
    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0)
946 947
        goto cleanup;

948
    qemuDomainObjEnterMonitor(driver, vm);
949 950 951 952 953 954 955 956 957 958

    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:
959 960 961 962 963
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseaddr = false;
        ret = -1;
        goto cleanup;
    }
964

965
    if (ret == 0)
966 967
        virDomainControllerInsertPreAlloced(vm->def, controller);

968
 cleanup:
969
    if (ret != 0 && releaseaddr)
970
        qemuDomainReleaseDeviceAddress(vm, &controller->info);
971 972 973 974 975 976

    VIR_FREE(devstr);
    return ret;
}

static virDomainControllerDefPtr
977
qemuDomainFindOrCreateSCSIDiskController(virQEMUDriverPtr driver,
978
                                         virDomainObjPtr vm,
979
                                         int controller)
980
{
981
    size_t i;
982
    virDomainControllerDefPtr cont;
983
    qemuDomainObjPrivatePtr priv = vm->privateData;
984
    int model = -1;
985

986
    for (i = 0; i < vm->def->ncontrollers; i++) {
987 988 989 990 991 992 993
        cont = vm->def->controllers[i];

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

        if (cont->idx == controller)
            return cont;
994 995 996 997 998 999 1000 1001 1002 1003

        /* 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;
1004 1005 1006 1007
    }

    /* No SCSI controller present, for backward compatibility we
     * now hotplug a controller */
1008
    if (VIR_ALLOC(cont) < 0)
1009 1010
        return NULL;
    cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
1011
    cont->idx = controller;
1012
    if (model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT)
1013 1014 1015
        cont->model = qemuDomainGetSCSIControllerModel(vm->def, cont, priv->qemuCaps);
    else
        cont->model = model;
1016

1017
    VIR_INFO("No SCSI controller present, hotplugging one model=%s",
1018
             virDomainControllerModelSCSITypeToString(cont->model));
1019
    if (qemuDomainAttachControllerDevice(driver, vm, cont) < 0) {
1020 1021 1022 1023 1024
        VIR_FREE(cont);
        return NULL;
    }

    if (!virDomainObjIsActive(vm)) {
1025 1026
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
1027 1028 1029 1030 1031 1032 1033 1034 1035
        /* cont doesn't need freeing here, since the reference
         * now held in def->controllers */
        return NULL;
    }

    return cont;
}


1036
static int
1037
qemuDomainAttachSCSIDisk(virQEMUDriverPtr driver,
1038 1039
                         virDomainObjPtr vm,
                         virDomainDiskDefPtr disk)
1040
{
1041
    size_t i;
1042 1043 1044

    /* We should have an address already, so make sure */
    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
1045 1046 1047
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk address type %s"),
                       virDomainDeviceAddressTypeToString(disk->info.type));
1048
        return -1;
1049 1050
    }

1051 1052 1053 1054 1055 1056
    if (virDomainSCSIDriveAddressIsUsed(vm->def, &disk->info.addr.drive)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain already contains a disk with that address"));
        return -1;
    }

1057 1058 1059 1060 1061 1062 1063 1064 1065
    /* 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))
1066
            return -1;
1067
    }
1068

1069
    if (qemuDomainAttachDiskGeneric(driver, vm, disk) < 0)
1070
        return -1;
1071

1072
    return 0;
1073 1074 1075
}


1076
static int
1077
qemuDomainAttachUSBMassStorageDevice(virQEMUDriverPtr driver,
1078 1079
                                     virDomainObjPtr vm,
                                     virDomainDiskDefPtr disk)
1080 1081
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1082

1083 1084
    if (virDomainUSBAddressEnsure(priv->usbaddrs, &disk->info) < 0)
        return -1;
1085

1086
    if (qemuDomainAttachDiskGeneric(driver, vm, disk) < 0) {
1087
        virDomainUSBAddressRelease(priv->usbaddrs, &disk->info);
1088
        return -1;
1089
    }
1090

1091
    return 0;
1092 1093 1094
}


1095 1096 1097 1098
static int
qemuDomainAttachDeviceDiskLiveInternal(virQEMUDriverPtr driver,
                                       virDomainObjPtr vm,
                                       virDomainDeviceDefPtr dev)
1099
{
1100
    size_t i;
1101 1102 1103
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

1104 1105 1106 1107 1108 1109 1110
    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;
    }

1111
    if (virDomainDiskTranslateSourcePool(disk) < 0)
1112
        goto cleanup;
1113 1114

    if (qemuAddSharedDevice(driver, dev, vm->def->name) < 0)
1115
        goto cleanup;
1116 1117

    if (qemuSetUnprivSGIO(dev) < 0)
1118
        goto cleanup;
1119

1120
    if (qemuDomainDetermineDiskChain(driver, vm, disk, NULL, true) < 0)
1121
        goto cleanup;
1122

1123 1124 1125 1126
    for (i = 0; i < vm->def->ndisks; i++) {
        if (virDomainDiskDefCheckDuplicateInfo(vm->def->disks[i], disk) < 0)
            goto cleanup;
    }
1127

1128 1129 1130 1131 1132
    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"));
1133
            break;
1134
        }
1135
        ret = qemuDomainAttachUSBMassStorageDevice(driver, vm, disk);
1136
        break;
1137

1138 1139
    case VIR_DOMAIN_DISK_BUS_VIRTIO:
        ret = qemuDomainAttachVirtioDiskDevice(driver, vm, disk);
1140
        break;
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158

    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));
1159 1160
    }

1161
 cleanup:
1162 1163 1164 1165 1166 1167
    if (ret != 0)
        ignore_value(qemuRemoveSharedDevice(driver, dev, vm->def->name));
    return ret;
}


1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
/**
 * 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)
{
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
    virDomainDiskDefPtr disk = dev->data.disk;
    virDomainDiskDefPtr orig_disk = NULL;

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

        disk->src = NULL;
        return 0;
    }

1199 1200 1201 1202
    return qemuDomainAttachDeviceDiskLiveInternal(driver, vm, dev);
}


1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
static void
qemuDomainNetDeviceVportRemove(virDomainNetDefPtr net)
{
    virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net);
    const char *brname;

    if (!vport)
        return;

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


1221 1222 1223 1224
int
qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainNetDefPtr net)
1225 1226
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1227
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_NET, { .net = net } };
1228
    virErrorPtr originalError = NULL;
1229 1230
    char **tapfdName = NULL;
    int *tapfd = NULL;
1231
    size_t tapfdSize = 0;
1232 1233
    char **vhostfdName = NULL;
    int *vhostfd = NULL;
1234
    size_t vhostfdSize = 0;
1235
    size_t queueSize = 0;
1236 1237 1238
    char *nicstr = NULL;
    char *netstr = NULL;
    int ret = -1;
1239
    bool releaseaddr = false;
1240
    bool iface_connected = false;
1241
    virDomainNetType actualType;
1242
    virNetDevBandwidthPtr actualBandwidth;
1243
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
1244
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
1245
    size_t i;
1246 1247 1248
    char *charDevAlias = NULL;
    bool charDevPlugged = false;
    bool netdevPlugged = false;
1249
    char *netdev_name;
1250
    virConnectPtr conn = NULL;
1251
    virErrorPtr save_err = NULL;
1252

1253
    /* preallocate new slot for device */
1254
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
1255
        goto cleanup;
1256

1257 1258 1259 1260
    /* 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.
     */
1261 1262 1263 1264 1265 1266
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        if (!(conn = virGetConnectNetwork()))
            goto cleanup;
        if (virDomainNetAllocateActualDevice(conn, vm->def, net) < 0)
            goto cleanup;
    }
1267 1268

    actualType = virDomainNetGetActualType(net);
1269

1270
    /* Currently only TAP/macvtap devices supports multiqueue. */
1271 1272
    if (net->driver.virtio.queues > 0 &&
        !(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
1273
          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
1274
          actualType == VIR_DOMAIN_NET_TYPE_DIRECT ||
1275 1276
          actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
          actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER)) {
1277 1278 1279 1280 1281 1282
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Multiqueue network is not supported for: %s"),
                       virDomainNetTypeToString(actualType));
        return -1;
    }

1283 1284 1285
    /* and only TAP devices support nwfilter rules */
    if (net->filter &&
        !(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
1286 1287
          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
          actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
1288 1289 1290 1291 1292 1293 1294
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("filterref is not supported for "
                         "network interfaces of type %s"),
                       virDomainNetTypeToString(actualType));
        return -1;
    }

1295 1296 1297
    if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
        goto cleanup;

1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
    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;

1317 1318
    switch (actualType) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
1319
    case VIR_DOMAIN_NET_TYPE_NETWORK:
1320 1321 1322
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1323
        queueSize = tapfdSize;
1324
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1325
            goto cleanup;
1326 1327 1328 1329
        memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
        if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
            goto cleanup;
        memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
1330
        if (qemuInterfaceBridgeConnect(vm->def, driver, net,
1331
                                       tapfd, &tapfdSize) < 0)
1332 1333
            goto cleanup;
        iface_connected = true;
J
Ján Tomko 已提交
1334
        if (qemuInterfaceOpenVhostNet(vm->def, net, vhostfd, &vhostfdSize) < 0)
1335
            goto cleanup;
1336 1337 1338
        break;

    case VIR_DOMAIN_NET_TYPE_DIRECT:
1339 1340 1341
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1342
        queueSize = tapfdSize;
1343
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1344
            goto cleanup;
1345 1346
        memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
        if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
1347
            goto cleanup;
1348
        memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
1349 1350 1351
        if (qemuInterfaceDirectConnect(vm->def, driver, net,
                                       tapfd, tapfdSize,
                                       VIR_NETDEV_VPORT_PROFILE_OP_CREATE) < 0)
1352 1353
            goto cleanup;
        iface_connected = true;
J
Ján Tomko 已提交
1354
        if (qemuInterfaceOpenVhostNet(vm->def, net, vhostfd, &vhostfdSize) < 0)
1355
            goto cleanup;
1356 1357 1358
        break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
1359 1360 1361
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1362
        queueSize = tapfdSize;
1363
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1364
            goto cleanup;
1365 1366 1367 1368 1369
        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,
1370
                                         tapfd, tapfdSize) < 0)
1371 1372
            goto cleanup;
        iface_connected = true;
J
Ján Tomko 已提交
1373
        if (qemuInterfaceOpenVhostNet(vm->def, net, vhostfd, &vhostfdSize) < 0)
1374
            goto cleanup;
1375 1376 1377
        break;

    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
1378 1379 1380 1381 1382
        /* 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.
         */
1383
        ret = qemuDomainAttachHostDevice(driver, vm,
1384 1385
                                         virDomainNetGetActualHostdev(net));
        goto cleanup;
1386 1387 1388
        break;

    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
1389 1390 1391
        queueSize = net->driver.virtio.queues;
        if (!queueSize)
            queueSize = 1;
1392
        if (!qemuDomainSupportsNicdev(vm->def, net)) {
1393
            virReportError(VIR_ERR_INTERNAL_ERROR,
1394
                           "%s", _("Nicdev support unavailable"));
1395 1396 1397
            goto cleanup;
        }

1398
        if (!(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias)))
1399
            goto cleanup;
1400 1401 1402 1403 1404

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

1405 1406 1407
        break;

    case VIR_DOMAIN_NET_TYPE_USER:
1408 1409 1410
        /* No preparation needed. */
        break;

1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
    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;
1421 1422
    }

1423 1424
    /* Set device online immediately */
    if (qemuInterfaceStartDevice(net) < 0)
1425
        goto cleanup;
1426

1427 1428 1429 1430
    /* Set bandwidth or warn if requested and not supported. */
    actualBandwidth = virDomainNetGetActualBandwidth(net);
    if (actualBandwidth) {
        if (virNetDevSupportBandwidth(actualType)) {
1431 1432
            if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false,
                                      !virDomainNetTypeSharesHostView(net)) < 0)
1433 1434 1435 1436 1437 1438 1439
                goto cleanup;
        } else {
            VIR_WARN("setting bandwidth on interfaces of "
                     "type '%s' is not implemented yet",
                     virDomainNetTypeToString(actualType));
        }
    }
1440

1441 1442 1443 1444
    if (net->mtu &&
        virNetDevSetMTU(net->ifname, net->mtu) < 0)
        goto cleanup;

M
Michal Privoznik 已提交
1445
    for (i = 0; i < tapfdSize; i++) {
1446 1447
        if (qemuSecuritySetTapFDLabel(driver->securityManager,
                                      vm->def, tapfd[i]) < 0)
M
Michal Privoznik 已提交
1448 1449 1450
            goto cleanup;
    }

1451
    if (VIR_ALLOC_N(tapfdName, tapfdSize) < 0 ||
1452
        VIR_ALLOC_N(vhostfdName, vhostfdSize) < 0)
1453 1454 1455
        goto cleanup;

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

1460
    for (i = 0; i < vhostfdSize; i++) {
1461
        if (virAsprintf(&vhostfdName[i], "vhostfd-%s%zu", net->info.alias, i) < 0)
1462
            goto cleanup;
1463 1464
    }

J
Ján Tomko 已提交
1465 1466 1467 1468
    if (!(netstr = qemuBuildHostNetStr(net, driver,
                                       tapfdName, tapfdSize,
                                       vhostfdName, vhostfdSize)))
        goto cleanup;
1469

1470
    qemuDomainObjEnterMonitor(driver, vm);
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480

    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 已提交
1481 1482 1483 1484 1485 1486
    if (qemuMonitorAddNetdev(priv->mon, netstr,
                             tapfd, tapfdName, tapfdSize,
                             vhostfd, vhostfdName, vhostfdSize) < 0) {
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto try_remove;
1487
    }
J
Ján Tomko 已提交
1488
    netdevPlugged = true;
1489

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

1493 1494 1495 1496
    for (i = 0; i < tapfdSize; i++)
        VIR_FORCE_CLOSE(tapfd[i]);
    for (i = 0; i < vhostfdSize; i++)
        VIR_FORCE_CLOSE(vhostfd[i]);
1497

1498
    if (!(nicstr = qemuBuildNicDevStr(vm->def, net, 0,
1499
                                      queueSize, priv->qemuCaps)))
1500
        goto try_remove;
1501

1502
    qemuDomainObjEnterMonitor(driver, vm);
1503 1504 1505 1506 1507 1508 1509

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

1510
    if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
1511
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &net->info));
1512 1513 1514
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto try_remove;
1515
    }
1516 1517
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
1518

1519 1520 1521
    /* set link state */
    if (net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
        if (!net->info.alias) {
1522 1523
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("device alias not found: cannot set link state to down"));
1524
        } else {
1525
            qemuDomainObjEnterMonitor(driver, vm);
1526

J
Ján Tomko 已提交
1527 1528 1529 1530
            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;
1531 1532
            }

1533 1534
            if (qemuDomainObjExitMonitor(driver, vm) < 0)
                goto cleanup;
1535 1536 1537 1538
        }
        /* link set to down */
    }

1539
    virDomainAuditNet(vm, NULL, net, "attach", true);
1540 1541 1542

    ret = 0;

1543
 cleanup:
1544 1545 1546
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else {
1547
        virErrorPreserveLast(&save_err);
1548
        if (releaseaddr)
1549
            qemuDomainReleaseDeviceAddress(vm, &net->info);
1550

1551
        if (iface_connected) {
1552
            virErrorPreserveLast(&originalError);
1553
            virDomainConfNWFilterTeardown(net);
1554
            virErrorRestore(&originalError);
1555

1556 1557 1558 1559 1560 1561 1562 1563 1564
            if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
                ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
                                 net->ifname, &net->mac,
                                 virDomainNetGetActualDirectDev(net),
                                 virDomainNetGetActualDirectMode(net),
                                 virDomainNetGetActualVirtPortProfile(net),
                                 cfg->stateDir));
            }

1565
            qemuDomainNetDeviceVportRemove(net);
1566
        }
A
Ansis Atteka 已提交
1567

1568 1569
        virDomainNetRemoveHostdev(vm->def, net);

1570 1571 1572 1573 1574 1575
        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));
        }
1576
        virErrorRestore(&save_err);
1577
    }
1578 1579 1580

    VIR_FREE(nicstr);
    VIR_FREE(netstr);
1581
    for (i = 0; tapfd && i < tapfdSize; i++) {
1582
        VIR_FORCE_CLOSE(tapfd[i]);
1583 1584
        if (tapfdName)
            VIR_FREE(tapfdName[i]);
1585 1586 1587
    }
    VIR_FREE(tapfd);
    VIR_FREE(tapfdName);
1588
    for (i = 0; vhostfd && i < vhostfdSize; i++) {
1589
        VIR_FORCE_CLOSE(vhostfd[i]);
1590 1591
        if (vhostfdName)
            VIR_FREE(vhostfdName[i]);
1592 1593 1594
    }
    VIR_FREE(vhostfd);
    VIR_FREE(vhostfdName);
1595
    VIR_FREE(charDevAlias);
1596
    virObjectUnref(conn);
1597
    virDomainCCWAddressSetFree(ccwaddrs);
1598 1599 1600

    return ret;

1601
 try_remove:
1602 1603 1604
    if (!virDomainObjIsActive(vm))
        goto cleanup;

1605
    virErrorPreserveLast(&originalError);
1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
    if (virAsprintf(&netdev_name, "host%s", net->info.alias) >= 0) {
        qemuDomainObjEnterMonitor(driver, vm);
        if (charDevPlugged &&
            qemuMonitorDetachCharDev(priv->mon, charDevAlias) < 0)
            VIR_WARN("Failed to remove associated chardev %s", charDevAlias);
        if (netdevPlugged &&
            qemuMonitorRemoveNetdev(priv->mon, netdev_name) < 0)
            VIR_WARN("Failed to remove network backend for netdev %s",
                     netdev_name);
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        VIR_FREE(netdev_name);
1617
    }
1618
    virErrorRestore(&originalError);
1619 1620 1621 1622
    goto cleanup;
}


1623
static int
1624
qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
1625 1626
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
1627 1628
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1629 1630
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                               { .hostdev = hostdev } };
1631
    virDomainDeviceInfoPtr info = hostdev->info;
1632 1633 1634 1635
    int ret;
    char *devstr = NULL;
    int configfd = -1;
    char *configfd_name = NULL;
1636
    bool releaseaddr = false;
1637
    bool teardowncgroup = false;
1638
    bool teardownlabel = false;
1639
    bool teardowndevice = false;
1640
    int backend;
1641
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
1642
    unsigned int flags = 0;
1643

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

1647 1648
    if (!cfg->relaxedACS)
        flags |= VIR_HOSTDEV_STRICT_ACS_CHECK;
1649
    if (qemuHostdevPreparePCIDevices(driver, vm->def->name, vm->def->uuid,
1650 1651
                                     &hostdev, 1, priv->qemuCaps, flags) < 0)
        goto cleanup;
1652

1653
    /* this could have been changed by qemuHostdevPreparePCIDevices */
1654 1655
    backend = hostdev->source.subsys.u.pci.backend;

1656
    switch ((virDomainHostdevSubsysPCIBackendType)backend) {
1657
    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
1658 1659 1660 1661 1662 1663
        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;
        }
1664 1665
        break;

1666 1667 1668 1669 1670 1671 1672 1673 1674 1675
    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;
1676
        break;
1677 1678
    }

1679
    /* Temporarily add the hostdev to the domain definition. This is needed
1680 1681 1682 1683
     * because qemuDomainAdjustMaxMemLock() requires the hostdev to be already
     * part of the domain definition, but other functions like
     * qemuAssignDeviceHostdevAlias() used below expect it *not* to be there.
     * A better way to handle this would be nice */
1684
    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
1685 1686 1687
    if (qemuDomainAdjustMaxMemLock(vm) < 0) {
        vm->def->hostdevs[--(vm->def->nhostdevs)] = NULL;
        goto error;
1688 1689 1690
    }
    vm->def->hostdevs[--(vm->def->nhostdevs)] = NULL;

1691
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
1692 1693 1694
        goto error;
    teardowndevice = true;

1695
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
1696 1697 1698
        goto error;
    teardowncgroup = true;

1699
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
1700
        goto error;
1701 1702
    if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
        teardownlabel = true;
1703

1704
    if (qemuAssignDeviceHostdevAlias(vm->def, &info->alias, -1) < 0)
1705
        goto error;
1706 1707 1708 1709 1710 1711 1712

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

1713
    if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
1714 1715
        goto error;
    releaseaddr = true;
1716
    if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1717 1718
        configfd = qemuOpenPCIConfig(hostdev);
        if (configfd >= 0) {
1719
            if (virAsprintf(&configfd_name, "fd-%s", info->alias) < 0)
1720
                goto error;
1721
        }
1722
    }
1723

1724 1725 1726 1727 1728
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit during hotplug"));
        goto error;
    }
1729

1730 1731 1732
    if (!(devstr = qemuBuildPCIHostdevDevStr(vm->def, hostdev, 0,
                                             configfd_name, priv->qemuCaps)))
        goto error;
1733

1734
    qemuDomainObjEnterMonitor(driver, vm);
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744

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

    if ((ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr,
                                          configfd, configfd_name)) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, hostdev->info));
    }

 exit_monitor:
1745 1746
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto error;
1747

1748
    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759
    if (ret < 0)
        goto error;

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

    VIR_FREE(devstr);
    VIR_FREE(configfd_name);
    VIR_FORCE_CLOSE(configfd);

    return 0;

1760
 error:
1761 1762
    if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
        VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
1763
    if (teardownlabel &&
1764
        qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
1765
        VIR_WARN("Unable to restore host device labelling on hotplug fail");
1766
    if (teardowndevice &&
1767
        qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
1768
        VIR_WARN("Unable to remove host device from /dev");
1769

1770
    if (releaseaddr)
1771
        qemuDomainReleaseDeviceAddress(vm, info);
1772

1773
    qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
1774 1775 1776 1777 1778

    VIR_FREE(devstr);
    VIR_FREE(configfd_name);
    VIR_FORCE_CLOSE(configfd);

1779
 cleanup:
1780 1781 1782 1783
    return -1;
}


1784 1785 1786
void
qemuDomainDelTLSObjects(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
1787
                        qemuDomainAsyncJob asyncJob,
1788 1789 1790 1791 1792 1793 1794 1795 1796
                        const char *secAlias,
                        const char *tlsAlias)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virErrorPtr orig_err;

    if (!tlsAlias && !secAlias)
        return;

1797
    virErrorPreserveLast(&orig_err);
1798

1799 1800
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;
1801 1802 1803 1804 1805 1806 1807 1808 1809

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

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

    ignore_value(qemuDomainObjExitMonitor(driver, vm));

1810
 cleanup:
1811
    virErrorRestore(&orig_err);
1812 1813 1814 1815 1816 1817
}


int
qemuDomainAddTLSObjects(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
1818
                        qemuDomainAsyncJob asyncJob,
1819 1820 1821 1822 1823
                        virJSONValuePtr *secProps,
                        virJSONValuePtr *tlsProps)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virErrorPtr orig_err;
1824
    char *secAlias = NULL;
1825

1826
    if (!tlsProps && !secProps)
1827 1828
        return 0;

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

1832
    if (secProps && *secProps &&
1833 1834
        qemuMonitorAddObject(priv->mon, secProps, &secAlias) < 0)
        goto error;
1835

1836 1837 1838
    if (tlsProps &&
        qemuMonitorAddObject(priv->mon, tlsProps, NULL) < 0)
        goto error;
1839

1840 1841
    VIR_FREE(secAlias);

1842 1843 1844
    return qemuDomainObjExitMonitor(driver, vm);

 error:
1845
    virErrorPreserveLast(&orig_err);
1846
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
1847
    virErrorRestore(&orig_err);
1848
    qemuDomainDelTLSObjects(driver, vm, asyncJob, secAlias, NULL);
1849
    VIR_FREE(secAlias);
1850 1851 1852 1853 1854

    return -1;
}


1855 1856 1857 1858 1859 1860
int
qemuDomainGetTLSObjects(virQEMUCapsPtr qemuCaps,
                        qemuDomainSecretInfoPtr secinfo,
                        const char *tlsCertdir,
                        bool tlsListen,
                        bool tlsVerify,
1861
                        const char *alias,
1862
                        virJSONValuePtr *tlsProps,
1863
                        virJSONValuePtr *secProps)
1864
{
1865 1866
    const char *secAlias = NULL;

1867 1868
    if (secinfo) {
        if (qemuBuildSecretInfoProps(secinfo, secProps) < 0)
1869 1870
            return -1;

1871
        secAlias = secinfo->s.aes.alias;
1872 1873
    }

1874
    if (qemuBuildTLSx509BackendProps(tlsCertdir, tlsListen, tlsVerify,
1875
                                     alias, secAlias, qemuCaps, tlsProps) < 0)
1876 1877 1878 1879 1880 1881
        return -1;

    return 0;
}


1882
static int
1883
qemuDomainAddChardevTLSObjects(virQEMUDriverPtr driver,
1884 1885
                               virDomainObjPtr vm,
                               virDomainChrSourceDefPtr dev,
1886
                               char *devAlias,
1887 1888
                               char *charAlias,
                               char **tlsAlias,
1889
                               const char **secAlias)
1890 1891
{
    int ret = -1;
1892
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
1893
    qemuDomainObjPrivatePtr priv = vm->privateData;
1894 1895
    qemuDomainChrSourcePrivatePtr chrSourcePriv;
    qemuDomainSecretInfoPtr secinfo = NULL;
1896 1897 1898
    virJSONValuePtr tlsProps = NULL;
    virJSONValuePtr secProps = NULL;

1899 1900 1901
    /* NB: This may alter haveTLS based on cfg */
    qemuDomainPrepareChardevSourceTLS(dev, cfg);

1902
    if (dev->type != VIR_DOMAIN_CHR_TYPE_TCP ||
1903 1904 1905 1906
        dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_YES) {
        ret = 0;
        goto cleanup;
    }
1907

1908
    if (qemuDomainSecretChardevPrepare(cfg, priv, devAlias, dev) < 0)
1909 1910
        goto cleanup;

1911 1912 1913
    if ((chrSourcePriv = QEMU_DOMAIN_CHR_SOURCE_PRIVATE(dev)))
        secinfo = chrSourcePriv->secinfo;

1914 1915 1916
    if (secinfo)
        *secAlias = secinfo->s.aes.alias;

1917 1918 1919
    if (!(*tlsAlias = qemuAliasTLSObjFromSrcAlias(charAlias)))
        goto cleanup;

1920 1921 1922 1923
    if (qemuDomainGetTLSObjects(priv->qemuCaps, secinfo,
                                cfg->chardevTLSx509certdir,
                                dev->data.tcp.listen,
                                cfg->chardevTLSx509verify,
1924
                                *tlsAlias, &tlsProps, &secProps) < 0)
1925
        goto cleanup;
1926
    dev->data.tcp.tlscreds = true;
1927

1928
    if (qemuDomainAddTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
1929
                                &secProps, &tlsProps) < 0)
1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941
        goto cleanup;

    ret = 0;

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

    return ret;
}


1942 1943 1944
static int
qemuDomainDelChardevTLSObjects(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
1945
                               virDomainChrSourceDefPtr dev,
1946 1947 1948
                               const char *inAlias)
{
    int ret = -1;
1949
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
1950 1951 1952 1953
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *tlsAlias = NULL;
    char *secAlias = NULL;

1954 1955 1956 1957 1958 1959
    if (dev->type != VIR_DOMAIN_CHR_TYPE_TCP ||
        dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_YES) {
        ret = 0;
        goto cleanup;
    }

1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
    if (!(tlsAlias = qemuAliasTLSObjFromSrcAlias(inAlias)))
        goto cleanup;

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

    qemuDomainObjEnterMonitor(driver, vm);

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

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

    ret = 0;

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


1989
int qemuDomainAttachRedirdevDevice(virQEMUDriverPtr driver,
1990 1991 1992
                                   virDomainObjPtr vm,
                                   virDomainRedirdevDefPtr redirdev)
{
1993
    int ret = -1;
1994
    qemuDomainObjPrivatePtr priv = vm->privateData;
1995
    virDomainDefPtr def = vm->def;
1996
    char *charAlias = NULL;
1997
    char *devstr = NULL;
1998
    bool chardevAdded = false;
1999
    char *tlsAlias = NULL;
2000
    const char *secAlias = NULL;
2001
    bool need_release = false;
2002
    virErrorPtr orig_err;
2003

2004
    if (qemuAssignDeviceRedirdevAlias(def, redirdev, -1) < 0)
2005 2006
        goto cleanup;

2007
    if (!(charAlias = qemuAliasChardevFromDevAlias(redirdev->info.alias)))
2008 2009
        goto cleanup;

2010
    if ((virDomainUSBAddressEnsure(priv->usbaddrs, &redirdev->info)) < 0)
2011
        goto cleanup;
2012
    need_release = true;
2013

2014
    if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, priv->qemuCaps)))
2015
        goto cleanup;
2016

2017
    if (VIR_REALLOC_N(def->redirdevs, def->nredirdevs+1) < 0)
2018
        goto cleanup;
2019

2020
    if (qemuDomainAddChardevTLSObjects(driver, vm, redirdev->source,
2021 2022
                                       redirdev->info.alias, charAlias,
                                       &tlsAlias, &secAlias) < 0)
2023
        goto audit;
2024

2025
    qemuDomainObjEnterMonitor(driver, vm);
2026

2027 2028
    if (qemuMonitorAttachCharDev(priv->mon,
                                 charAlias,
2029
                                 redirdev->source) < 0)
2030 2031
        goto exit_monitor;
    chardevAdded = true;
2032

2033 2034
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
        goto exit_monitor;
2035

2036 2037
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto audit;
2038

2039
    def->redirdevs[def->nredirdevs++] = redirdev;
2040 2041 2042 2043
    ret = 0;
 audit:
    virDomainAuditRedirdev(vm, redirdev, "attach", ret == 0);
 cleanup:
2044
    if (ret < 0 && need_release)
2045
        qemuDomainReleaseDeviceAddress(vm, &redirdev->info);
2046
    VIR_FREE(tlsAlias);
2047
    VIR_FREE(charAlias);
2048
    VIR_FREE(devstr);
2049
    return ret;
2050 2051

 exit_monitor:
2052
    virErrorPreserveLast(&orig_err);
2053 2054 2055
    /* detach associated chardev on error */
    if (chardevAdded)
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
2056
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2057
    virErrorRestore(&orig_err);
2058 2059
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2060
    goto audit;
2061 2062
}

2063 2064 2065
static int
qemuDomainChrPreInsert(virDomainDefPtr vmdef,
                       virDomainChrDefPtr chr)
2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079
{
    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;
    }

2080
    if (virDomainChrPreAlloc(vmdef, chr) < 0)
2081 2082
        return -1;

2083 2084 2085 2086
    /* 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.
     */
2087 2088 2089 2090 2091
    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;

2092 2093
        /* We'll be dealing with serials[0] directly, so NULL is fine here. */
        if (!(vmdef->consoles[0] = virDomainChrDefNew(NULL))) {
2094
            VIR_FREE(vmdef->consoles);
2095 2096
            return -1;
        }
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108
        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) {
2109 2110 2111 2112 2113 2114
        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;
    }
2115 2116 2117 2118 2119 2120 2121 2122 2123
}

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) {
2124
        virDomainChrDefFree(vmdef->consoles[0]);
2125 2126 2127 2128
        VIR_FREE(vmdef->consoles);
        vmdef->nconsoles = 0;
    }
}
2129

2130 2131 2132 2133 2134 2135 2136 2137 2138
int
qemuDomainChrInsert(virDomainDefPtr vmdef,
                    virDomainChrDefPtr chr)
{
    if (qemuDomainChrPreInsert(vmdef, chr) < 0) {
        qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
        return -1;
    }
    qemuDomainChrInsertPreAlloced(vmdef, chr);
2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174
    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;
}
2175

2176 2177 2178 2179
/* Returns  1 if the address will need to be released later,
 *         -1 on error
 *          0 otherwise
 */
2180
static int
2181
qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm,
2182 2183
                                    virDomainChrDefPtr chr,
                                    virQEMUDriverPtr driver)
2184
{
2185 2186
    virDomainDefPtr def = vm->def;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2187
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CHR, { .chr = chr } };
2188

2189 2190
    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
2191
        if (virDomainVirtioSerialAddrAutoAssign(def, &chr->info, true) < 0)
2192
            return -1;
2193
        return 0;
2194 2195 2196

    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
               chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) {
2197
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
2198 2199
            return -1;
        return 1;
2200

2201
    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
2202 2203
               chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB) {
        if (virDomainUSBAddressEnsure(priv->usbaddrs, &chr->info) < 0)
2204 2205
            return -1;
        return 1;
2206

2207 2208
    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
               chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
2209
        if (virDomainVirtioSerialAddrAutoAssign(def, &chr->info, false) < 0)
2210
            return -1;
2211
        return 0;
2212 2213 2214 2215 2216 2217
    }

    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"));
2218
        return -1;
2219 2220
    }

2221
    return 0;
2222 2223
}

2224
int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
2225 2226 2227
                              virDomainObjPtr vm,
                              virDomainChrDefPtr chr)
{
2228
    int ret = -1, rc;
2229
    qemuDomainObjPrivatePtr priv = vm->privateData;
2230
    virErrorPtr orig_err;
2231 2232
    virDomainDefPtr vmdef = vm->def;
    char *devstr = NULL;
2233
    virDomainChrSourceDefPtr dev = chr->source;
2234
    char *charAlias = NULL;
2235
    bool chardevAttached = false;
2236
    bool teardowncgroup = false;
2237
    bool teardowndevice = false;
2238
    bool teardownlabel = false;
2239
    char *tlsAlias = NULL;
2240
    const char *secAlias = NULL;
2241
    bool need_release = false;
2242
    bool guestfwd = false;
2243

2244 2245 2246 2247 2248 2249
    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;
    }
2250

2251
    if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0)
2252
        goto cleanup;
2253

2254
    if ((rc = qemuDomainAttachChrDeviceAssignAddr(vm, chr, driver)) < 0)
2255 2256 2257
        goto cleanup;
    if (rc == 1)
        need_release = true;
2258

2259
    if (qemuDomainNamespaceSetupChardev(vm, chr) < 0)
2260 2261 2262
        goto cleanup;
    teardowndevice = true;

2263 2264 2265 2266
    if (qemuSecuritySetChardevLabel(driver, vm, chr) < 0)
        goto cleanup;
    teardownlabel = true;

2267 2268 2269 2270
    if (qemuSetupChardevCgroup(vm, chr) < 0)
        goto cleanup;
    teardowncgroup = true;

2271
    if (qemuBuildChrDeviceStr(&devstr, vmdef, chr, priv->qemuCaps) < 0)
2272
        goto cleanup;
2273

2274
    if (!(charAlias = qemuAliasChardevFromDevAlias(chr->info.alias)))
2275 2276
        goto cleanup;

2277
    if (qemuDomainChrPreInsert(vmdef, chr) < 0)
2278 2279
        goto cleanup;

2280
    if (qemuDomainAddChardevTLSObjects(driver, vm, dev,
2281
                                       chr->info.alias, charAlias,
2282
                                       &tlsAlias, &secAlias) < 0)
2283
        goto audit;
2284

2285
    qemuDomainObjEnterMonitor(driver, vm);
2286

2287
    if (qemuMonitorAttachCharDev(priv->mon, charAlias, chr->source) < 0)
2288 2289
        goto exit_monitor;
    chardevAttached = true;
2290

2291 2292 2293 2294 2295 2296 2297 2298
    if (guestfwd) {
        if (qemuMonitorAddNetdev(priv->mon, devstr,
                                 NULL, NULL, 0, NULL, NULL, 0) < 0)
            goto exit_monitor;
    } else {
        if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
            goto exit_monitor;
    }
2299

2300 2301
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto audit;
2302

2303
    qemuDomainChrInsertPreAlloced(vmdef, chr);
2304
    ret = 0;
2305 2306
 audit:
    virDomainAuditChardev(vm, NULL, chr, "attach", ret == 0);
2307
 cleanup:
2308 2309 2310 2311
    if (ret < 0) {
        if (virDomainObjIsActive(vm))
            qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
        if (need_release)
2312
            qemuDomainReleaseDeviceAddress(vm, &chr->info);
2313 2314
        if (teardowncgroup && qemuTeardownChardevCgroup(vm, chr) < 0)
            VIR_WARN("Unable to remove chr device cgroup ACL on hotplug fail");
2315 2316
        if (teardownlabel && qemuSecurityRestoreChardevLabel(driver, vm, chr) < 0)
            VIR_WARN("Unable to restore security label on char device");
2317
        if (teardowndevice && qemuDomainNamespaceTeardownChardev(vm, chr) < 0)
2318
            VIR_WARN("Unable to remove chr device from /dev");
2319
    }
2320
    VIR_FREE(tlsAlias);
2321 2322 2323
    VIR_FREE(charAlias);
    VIR_FREE(devstr);
    return ret;
2324

2325
 exit_monitor:
2326
    virErrorPreserveLast(&orig_err);
2327
    /* detach associated chardev on error */
2328 2329
    if (chardevAttached)
        qemuMonitorDetachCharDev(priv->mon, charAlias);
2330
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2331
    virErrorRestore(&orig_err);
2332

2333 2334
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2335
    goto audit;
2336 2337
}

2338 2339

int
2340
qemuDomainAttachRNGDevice(virQEMUDriverPtr driver,
2341 2342 2343 2344
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2345
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_RNG, { .rng = rng } };
2346
    virErrorPtr orig_err;
2347 2348 2349
    char *devstr = NULL;
    char *charAlias = NULL;
    char *objAlias = NULL;
2350
    char *tlsAlias = NULL;
2351
    const char *secAlias = NULL;
2352
    bool releaseaddr = false;
2353
    bool teardowncgroup = false;
2354
    bool teardowndevice = false;
2355
    bool chardevAdded = false;
2356 2357 2358
    virJSONValuePtr props = NULL;
    int ret = -1;

2359
    if (qemuAssignDeviceRNGAlias(vm->def, rng) < 0)
2360
        goto cleanup;
2361 2362 2363

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

2366 2367
    if (qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev, "rng") < 0)
        return -1;
2368

2369
    if (qemuDomainNamespaceSetupRNG(vm, rng) < 0)
2370 2371 2372
        goto cleanup;
    teardowndevice = true;

2373 2374 2375 2376
    if (qemuSetupRNGCgroup(vm, rng) < 0)
        goto cleanup;
    teardowncgroup = true;

2377 2378 2379 2380
    /* build required metadata */
    if (!(devstr = qemuBuildRNGDevStr(vm->def, rng, priv->qemuCaps)))
        goto cleanup;

2381
    if (qemuBuildRNGBackendProps(rng, priv->qemuCaps, &props) < 0)
2382 2383
        goto cleanup;

2384
    if (!(charAlias = qemuAliasChardevFromDevAlias(rng->info.alias)))
2385 2386
        goto cleanup;

2387
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD) {
2388
        if (qemuDomainAddChardevTLSObjects(driver, vm,
2389 2390 2391
                                           rng->source.chardev,
                                           rng->info.alias, charAlias,
                                           &tlsAlias, &secAlias) < 0)
2392
            goto audit;
2393 2394
    }

2395
    qemuDomainObjEnterMonitor(driver, vm);
2396

2397 2398 2399
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
        qemuMonitorAttachCharDev(priv->mon, charAlias,
                                 rng->source.chardev) < 0)
2400 2401
        goto exit_monitor;
    chardevAdded = true;
2402

2403
    if (qemuMonitorAddObject(priv->mon, &props, &objAlias) < 0)
2404
        goto exit_monitor;
2405

2406
    if (qemuDomainAttachExtensionDevice(priv->mon, &rng->info) < 0)
2407
        goto exit_monitor;
2408

2409 2410 2411 2412 2413
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &rng->info));
        goto exit_monitor;
    }

2414
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
2415
        releaseaddr = false;
2416 2417 2418
        goto cleanup;
    }

2419
    VIR_APPEND_ELEMENT_INPLACE(vm->def->rngs, vm->def->nrngs, rng);
2420 2421 2422 2423 2424 2425

    ret = 0;

 audit:
    virDomainAuditRNG(vm, NULL, rng, "attach", ret == 0);
 cleanup:
2426
    virJSONValueFree(props);
2427 2428
    if (ret < 0) {
        if (releaseaddr)
2429
            qemuDomainReleaseDeviceAddress(vm, &rng->info);
2430 2431
        if (teardowncgroup && qemuTeardownRNGCgroup(vm, rng) < 0)
            VIR_WARN("Unable to remove RNG device cgroup ACL on hotplug fail");
2432
        if (teardowndevice && qemuDomainNamespaceTeardownRNG(vm, rng) < 0)
2433
            VIR_WARN("Unable to remove chr device from /dev");
2434 2435
    }

2436
    VIR_FREE(tlsAlias);
2437 2438 2439 2440 2441
    VIR_FREE(charAlias);
    VIR_FREE(objAlias);
    VIR_FREE(devstr);
    return ret;

2442
 exit_monitor:
2443
    virErrorPreserveLast(&orig_err);
2444
    if (objAlias)
2445 2446
        ignore_value(qemuMonitorDelObject(priv->mon, objAlias));
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD && chardevAdded)
2447
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
2448 2449
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        releaseaddr = false;
2450
    virErrorRestore(&orig_err);
2451

2452 2453
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2454 2455 2456 2457
    goto audit;
}


2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473
/**
 * 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;
2474
    virErrorPtr orig_err;
2475
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
2476
    unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
2477
    unsigned long long newmem = oldmem + mem->size;
2478 2479
    char *devstr = NULL;
    char *objalias = NULL;
2480
    bool objAdded = false;
M
Michal Privoznik 已提交
2481
    bool teardownlabel = false;
2482
    bool teardowncgroup = false;
M
Michal Privoznik 已提交
2483
    bool teardowndevice = false;
2484
    virJSONValuePtr props = NULL;
2485
    virObjectEventPtr event;
2486 2487 2488
    int id;
    int ret = -1;

2489 2490 2491
    qemuDomainMemoryDeviceAlignSize(vm->def, mem);

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

2494 2495 2496
    if (qemuDomainAssignMemoryDeviceSlot(vm->def, mem) < 0)
        goto cleanup;

2497 2498 2499
    /* 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)
2500 2501 2502 2503 2504
        goto cleanup;

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

2505
    if (!(devstr = qemuBuildMemoryDeviceStr(mem, priv)))
2506 2507
        goto cleanup;

2508
    if (qemuBuildMemoryBackendProps(&props, objalias, cfg,
2509
                                    priv, vm->def, mem, true) < 0)
2510 2511
        goto cleanup;

2512
    if (qemuProcessBuildDestroyMemoryPaths(driver, vm, mem, true) < 0)
2513 2514
        goto cleanup;

2515
    if (qemuDomainNamespaceSetupMemory(vm, mem) < 0)
M
Michal Privoznik 已提交
2516 2517 2518
        goto cleanup;
    teardowndevice = true;

2519 2520 2521 2522
    if (qemuSetupMemoryDevicesCgroup(vm, mem) < 0)
        goto cleanup;
    teardowncgroup = true;

M
Michal Privoznik 已提交
2523
    if (qemuSecuritySetMemoryLabel(driver, vm, mem) < 0)
2524
        goto cleanup;
M
Michal Privoznik 已提交
2525
    teardownlabel = true;
2526

M
Michal Privoznik 已提交
2527 2528 2529 2530
    if (virDomainMemoryInsert(vm->def, mem) < 0)
        goto cleanup;

    if (qemuDomainAdjustMaxMemLock(vm) < 0)
2531 2532
        goto removedef;

2533
    qemuDomainObjEnterMonitor(driver, vm);
2534
    if (qemuMonitorAddObject(priv->mon, &props, NULL) < 0)
2535
        goto exit_monitor;
2536
    objAdded = true;
2537

2538
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2539
        goto exit_monitor;
2540 2541 2542 2543

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

2547
    event = virDomainEventDeviceAddedNewFromObj(vm, objalias);
2548
    virObjectEventStateQueue(driver->domainEventState, event);
2549

2550 2551
    /* fix the balloon size */
    ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));
2552

2553 2554 2555 2556 2557 2558 2559 2560 2561
    /* 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;

2562 2563
 audit:
    virDomainAuditMemory(vm, oldmem, newmem, "update", ret == 0);
2564
 cleanup:
M
Michal Privoznik 已提交
2565
    if (mem && ret < 0) {
2566 2567
        if (teardowncgroup && qemuTeardownMemoryDevicesCgroup(vm, mem) < 0)
            VIR_WARN("Unable to remove memory device cgroup ACL on hotplug fail");
M
Michal Privoznik 已提交
2568 2569
        if (teardownlabel && qemuSecurityRestoreMemoryLabel(driver, vm, mem) < 0)
            VIR_WARN("Unable to restore security label on memdev");
M
Michal Privoznik 已提交
2570
        if (teardowndevice &&
2571
            qemuDomainNamespaceTeardownMemory(vm, mem) <  0)
M
Michal Privoznik 已提交
2572
            VIR_WARN("Unable to remove memory device from /dev");
M
Michal Privoznik 已提交
2573 2574 2575
    }

    virJSONValueFree(props);
2576 2577 2578 2579 2580
    VIR_FREE(devstr);
    VIR_FREE(objalias);
    virDomainMemoryDefFree(mem);
    return ret;

2581
 exit_monitor:
2582
    virErrorPreserveLast(&orig_err);
2583 2584
    if (objAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, objalias));
2585 2586
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        mem = NULL;
2587 2588 2589 2590

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

2591
    virErrorRestore(&orig_err);
2592
    if (!mem)
2593
        goto audit;
2594

2595
 removedef:
2596 2597 2598 2599 2600
    if ((id = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
        mem = virDomainMemoryRemove(vm->def, id);
    else
        mem = NULL;

2601
    /* reset the mlock limit */
2602
    virErrorPreserveLast(&orig_err);
2603
    ignore_value(qemuDomainAdjustMaxMemLock(vm));
2604
    virErrorRestore(&orig_err);
2605

2606
    goto audit;
2607 2608 2609
}


2610
static int
2611
qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
2612 2613
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
2614 2615 2616
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *devstr = NULL;
2617
    bool added = false;
2618
    bool teardowncgroup = false;
2619
    bool teardownlabel = false;
2620
    bool teardowndevice = false;
2621 2622
    int ret = -1;

2623 2624
    if (virDomainUSBAddressEnsure(priv->usbaddrs, hostdev->info) < 0)
        return -1;
2625

2626
    if (qemuHostdevPrepareUSBDevices(driver, vm->def->name, &hostdev, 1, 0) < 0)
2627 2628 2629
        goto cleanup;

    added = true;
2630

2631
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2632 2633 2634
        goto cleanup;
    teardowndevice = true;

2635
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
2636 2637 2638
        goto cleanup;
    teardowncgroup = true;

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

2643 2644 2645 2646
    if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
        goto cleanup;
    if (!(devstr = qemuBuildUSBHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
        goto cleanup;
2647

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

2651
    qemuDomainObjEnterMonitor(driver, vm);
2652
    ret = qemuMonitorAddDevice(priv->mon, devstr);
2653 2654 2655 2656
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        ret = -1;
        goto cleanup;
    }
2657
    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
2658
    if (ret < 0)
2659
        goto cleanup;
2660 2661 2662

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

2663
    ret = 0;
2664
 cleanup:
2665 2666 2667 2668
    if (ret < 0) {
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
        if (teardownlabel &&
2669
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2670
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2671
        if (teardowndevice &&
2672
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2673
            VIR_WARN("Unable to remove host device from /dev");
2674
        if (added)
2675
            qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
2676
        virDomainUSBAddressRelease(priv->usbaddrs, hostdev->info);
2677
    }
2678
    VIR_FREE(devstr);
2679
    return ret;
2680 2681
}

2682

2683
static int
2684
qemuDomainAttachHostSCSIDevice(virQEMUDriverPtr driver,
2685 2686 2687
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
2688
    size_t i;
2689 2690
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2691
    virErrorPtr orig_err;
2692 2693
    char *devstr = NULL;
    char *drvstr = NULL;
2694
    char *drivealias = NULL;
2695
    char *secobjAlias = NULL;
2696
    bool teardowncgroup = false;
2697
    bool teardownlabel = false;
2698
    bool teardowndevice = false;
2699
    bool driveAdded = false;
2700 2701
    virJSONValuePtr secobjProps = NULL;
    virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
2702
    qemuDomainSecretInfoPtr secinfo = NULL;
2703

2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714
    /* 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;
    }
2715

2716
    if (qemuHostdevPrepareSCSIDevices(driver, vm->def->name, &hostdev, 1) < 0)
2717 2718
        return -1;

2719
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2720 2721 2722
        goto cleanup;
    teardowndevice = true;

2723
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
2724 2725 2726
        goto cleanup;
    teardowncgroup = true;

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

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

2734
    if (qemuDomainSecretHostdevPrepare(priv, hostdev) < 0)
2735 2736
        goto cleanup;

2737 2738 2739
    if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
        qemuDomainStorageSourcePrivatePtr srcPriv =
            QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(scsisrc->u.iscsi.src);
2740 2741
        if (srcPriv)
            secinfo = srcPriv->secinfo;
2742 2743
    }

2744 2745 2746 2747 2748 2749
    if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
        if (qemuBuildSecretInfoProps(secinfo, &secobjProps) < 0)
            goto cleanup;
    }

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

2752 2753 2754
    if (!(drivealias = qemuAliasFromHostdev(hostdev)))
        goto cleanup;

2755
    if (!(devstr = qemuBuildSCSIHostdevDevStr(vm->def, hostdev)))
2756 2757
        goto cleanup;

2758
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
2759 2760 2761 2762
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);

2763 2764 2765
    if (secobjProps &&
        qemuMonitorAddObject(priv->mon, &secobjProps, &secobjAlias) < 0)
        goto exit_monitor;
2766

2767
    if (qemuMonitorAddDrive(priv->mon, drvstr) < 0)
2768 2769
        goto exit_monitor;
    driveAdded = true;
2770 2771

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2772
        goto exit_monitor;
2773 2774

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

    virDomainAuditHostdev(vm, hostdev, "attach", true);
2778 2779 2780 2781

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

    ret = 0;
2782

2783
 cleanup:
2784
    if (ret < 0) {
2785
        qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
2786 2787
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
2788
        if (teardownlabel &&
2789
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2790
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2791
        if (teardowndevice &&
2792
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2793
            VIR_WARN("Unable to remove host device from /dev");
2794
    }
2795 2796
    qemuDomainSecretHostdevDestroy(hostdev);
    virJSONValueFree(secobjProps);
2797
    VIR_FREE(secobjAlias);
2798
    VIR_FREE(drivealias);
2799 2800 2801
    VIR_FREE(drvstr);
    VIR_FREE(devstr);
    return ret;
2802

2803
 exit_monitor:
2804
    virErrorPreserveLast(&orig_err);
2805
    if (driveAdded && qemuMonitorDriveDel(priv->mon, drivealias) < 0) {
2806 2807 2808
        VIR_WARN("Unable to remove drive %s (%s) after failed "
                 "qemuMonitorAddDevice",
                 drvstr, devstr);
2809
    }
2810 2811
    if (secobjAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, secobjAlias));
2812
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2813
    virErrorRestore(&orig_err);
2814 2815 2816 2817

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

    goto cleanup;
2818 2819
}

2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834
static int
qemuDomainAttachSCSIVHostDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainHostdevDefPtr hostdev)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                               { .hostdev = hostdev } };
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
    char *vhostfdName = NULL;
    int vhostfd = -1;
    char *devstr = NULL;
    bool teardowncgroup = false;
    bool teardownlabel = false;
2835
    bool teardowndevice = false;
2836 2837
    bool releaseaddr = false;

2838
    if (qemuHostdevPrepareSCSIVHostDevices(driver, vm->def->name, &hostdev, 1) < 0)
2839 2840
        return -1;

2841
    if (qemuDomainNamespaceSetupHostdev(vm, hostdev) < 0)
2842 2843 2844
        goto cleanup;
    teardowndevice = true;

2845 2846 2847 2848
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
        goto cleanup;
    teardowncgroup = true;

2849
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
2850 2851 2852 2853 2854 2855 2856 2857 2858 2859
        goto cleanup;
    teardownlabel = true;

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

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

    if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
2860
        if (qemuDomainIsS390CCW(vm->def) &&
2861
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CCW))
2862 2863 2864 2865 2866
            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) {
2867
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
2868 2869
            goto cleanup;
    } else if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
2870
        if (!(ccwaddrs = virDomainCCWAddressSetCreateFromDomain(vm->def)))
2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891
            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);

2892 2893 2894 2895 2896 2897 2898 2899
    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;
    }
2900

2901
 exit_monitor:
2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915
    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 &&
2916
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2917
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2918
        if (teardowndevice &&
2919
            qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
2920
            VIR_WARN("Unable to remove host device from /dev");
2921
        if (releaseaddr)
2922
            qemuDomainReleaseDeviceAddress(vm, hostdev->info);
2923 2924 2925 2926 2927 2928 2929 2930 2931 2932
    }

    virDomainCCWAddressSetFree(ccwaddrs);

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

2933

2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948
static int
qemuDomainAttachMediatedDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    int ret = -1;
    char *devstr = NULL;
    bool added = false;
    bool teardowncgroup = false;
    bool teardownlabel = false;
    bool teardowndevice = false;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                                { .hostdev = hostdev } };

2949 2950 2951 2952 2953 2954 2955 2956 2957
    switch (hostdev->source.subsys.u.mdev.model) {
    case VIR_MDEV_MODEL_TYPE_VFIO_PCI:
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
            return -1;
        break;
    case VIR_MDEV_MODEL_TYPE_VFIO_CCW:
    case VIR_MDEV_MODEL_TYPE_LAST:
        break;
    }
2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015

    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;

    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) {
        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);
3016
        qemuDomainReleaseDeviceAddress(vm, hostdev->info);
3017 3018 3019 3020 3021 3022
    }
    VIR_FREE(devstr);
    return ret;
}


3023
int
3024
qemuDomainAttachHostDevice(virQEMUDriverPtr driver,
3025 3026
                           virDomainObjPtr vm,
                           virDomainHostdevDefPtr hostdev)
3027 3028
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
3029
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3030
                       _("hotplug is not supported for hostdev mode '%s'"),
3031
                       virDomainHostdevModeTypeToString(hostdev->mode));
3032 3033 3034 3035 3036
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
3037
        if (qemuDomainAttachHostPCIDevice(driver, vm,
3038
                                          hostdev) < 0)
3039 3040 3041 3042
            goto error;
        break;

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
3043
        if (qemuDomainAttachHostUSBDevice(driver, vm,
3044
                                          hostdev) < 0)
3045 3046 3047
            goto error;
        break;

3048
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
3049
        if (qemuDomainAttachHostSCSIDevice(driver, vm,
3050 3051 3052 3053
                                           hostdev) < 0)
            goto error;
        break;

3054 3055 3056 3057
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
        if (qemuDomainAttachSCSIVHostDevice(driver, vm, hostdev) < 0)
            goto error;
        break;
3058 3059 3060 3061
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
        if (qemuDomainAttachMediatedDevice(driver, vm, hostdev) < 0)
            goto error;
        break;
3062

3063
    default:
3064
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3065
                       _("hotplug is not supported for hostdev subsys type '%s'"),
3066
                       virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
3067 3068 3069 3070 3071
        goto error;
    }

    return 0;

3072
 error:
3073 3074 3075
    return -1;
}

3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090

int
qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainShmemDefPtr shmem)
{
    int ret = -1;
    char *shmstr = NULL;
    char *charAlias = NULL;
    char *memAlias = NULL;
    bool release_backing = false;
    bool release_address = true;
    virErrorPtr orig_err = NULL;
    virJSONValuePtr props = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
3091
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_SHMEM, { .shmem = shmem } };
3092 3093 3094 3095 3096 3097 3098 3099 3100 3101

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

    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live attach of shmem model '%s' is not supported"),
                       virDomainShmemModelTypeToString(shmem->model));
M
Marc Hartmayer 已提交
3102
        ATTRIBUTE_FALLTHROUGH;
3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117
    case VIR_DOMAIN_SHMEM_MODEL_LAST:
        return -1;
    }

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

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

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

    if ((shmem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
         shmem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
3118
        (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0))
3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139
        return -1;

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

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

    }

    qemuDomainObjEnterMonitor(driver, vm);

    if (shmem->server.enabled) {
        if (qemuMonitorAttachCharDev(priv->mon, charAlias,
                                     &shmem->server.chr) < 0)
            goto exit_monitor;
    } else {
3140
        if (qemuMonitorAddObject(priv->mon, &props, &memAlias) < 0)
3141 3142 3143 3144 3145
            goto exit_monitor;
    }

    release_backing = true;

3146 3147 3148 3149 3150
    if (qemuDomainAttachExtensionDevice(priv->mon, &shmem->info) < 0)
        goto exit_monitor;

    if (qemuMonitorAddDevice(priv->mon, shmstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &shmem->info));
3151
        goto exit_monitor;
3152
    }
3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170

    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)
3171
        qemuDomainReleaseDeviceAddress(vm, &shmem->info);
3172 3173 3174 3175 3176 3177 3178 3179 3180

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

    return ret;

 exit_monitor:
3181
    virErrorPreserveLast(&orig_err);
3182 3183 3184 3185 3186 3187 3188
    if (release_backing) {
        if (shmem->server.enabled)
            ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
        else
            ignore_value(qemuMonitorDelObject(priv->mon, memAlias));
    }

3189 3190 3191
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        release_address = false;

3192
    virErrorRestore(&orig_err);
3193 3194 3195 3196 3197

    goto audit;
}


M
Michal Privoznik 已提交
3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231
int
qemuDomainAttachWatchdog(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         virDomainWatchdogDefPtr watchdog)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_WATCHDOG, { .watchdog = watchdog } };
    virDomainWatchdogAction actualAction = watchdog->action;
    const char *actionStr = NULL;
    char *watchdogstr = NULL;
    bool releaseAddress = false;
    int rv;

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

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

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

3232 3233 3234
    if (!(watchdogstr = qemuBuildWatchdogDevStr(vm->def, watchdog, priv->qemuCaps)))
        goto cleanup;

M
Michal Privoznik 已提交
3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
    /* 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)
3264
        qemuDomainReleaseDeviceAddress(vm, &watchdog->info);
M
Michal Privoznik 已提交
3265 3266 3267 3268 3269
    VIR_FREE(watchdogstr);
    return ret;
}


J
Ján Tomko 已提交
3270 3271 3272 3273 3274 3275 3276 3277 3278 3279
int
qemuDomainAttachInputDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainInputDefPtr input)
{
    int ret = -1;
    char *devstr = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_INPUT,
                               { .input = input } };
3280
    virErrorPtr originalError = NULL;
J
Ján Tomko 已提交
3281
    bool releaseaddr = false;
3282 3283 3284
    bool teardowndevice = false;
    bool teardownlabel = false;
    bool teardowncgroup = false;
J
Ján Tomko 已提交
3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297

    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) {
3298 3299 3300
        if (virDomainUSBAddressEnsure(priv->usbaddrs, &input->info) < 0)
            goto cleanup;
        releaseaddr = true;
J
Ján Tomko 已提交
3301 3302 3303 3304 3305 3306 3307 3308
    }

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

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

3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320
    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 已提交
3321 3322 3323 3324
    if (VIR_REALLOC_N(vm->def->inputs, vm->def->ninputs + 1) < 0)
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);
3325 3326

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

3329 3330 3331 3332 3333
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0) {
        ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &input->info));
        goto exit_monitor;
    }

J
Ján Tomko 已提交
3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346
    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:
3347 3348 3349 3350 3351 3352 3353 3354 3355
    if (ret < 0) {
        virErrorPreserveLast(&originalError);
        if (teardownlabel)
            qemuSecurityRestoreInputLabel(vm, input);
        if (teardowncgroup)
            qemuTeardownInputCgroup(vm, input);
        if (teardowndevice)
            qemuDomainNamespaceTeardownInput(vm, input);
        if (releaseaddr)
3356
            qemuDomainReleaseDeviceAddress(vm, &input->info);
3357 3358
        virErrorRestore(&originalError);
    }
J
Ján Tomko 已提交
3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371

    VIR_FREE(devstr);
    return ret;

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


J
Ján Tomko 已提交
3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409
int
qemuDomainAttachVsockDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainVsockDefPtr vsock)
{
    qemuDomainVsockPrivatePtr vsockPriv = (qemuDomainVsockPrivatePtr)vsock->privateData;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_VSOCK,
                               { .vsock = vsock } };
    virErrorPtr originalError = NULL;
    const char *fdprefix = "vsockfd";
    bool releaseaddr = false;
    char *fdname = NULL;
    char *devstr = NULL;
    int ret = -1;

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

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

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

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

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

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

    qemuDomainObjEnterMonitor(driver, vm);
3410 3411 3412 3413 3414 3415

    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 已提交
3416
        goto exit_monitor;
3417
    }
J
Ján Tomko 已提交
3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431

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

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

    ret = 0;

 cleanup:
    if (ret < 0) {
        virErrorPreserveLast(&originalError);
        if (releaseaddr)
3432
            qemuDomainReleaseDeviceAddress(vm, &vsock->info);
J
Ján Tomko 已提交
3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446
        virErrorRestore(&originalError);
    }

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

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


3447 3448 3449 3450 3451 3452
int
qemuDomainAttachLease(virQEMUDriverPtr driver,
                      virDomainObjPtr vm,
                      virDomainLeaseDefPtr lease)
{
    int ret = -1;
3453
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471

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

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

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

 cleanup:
    return ret;
}


3472
static int
3473
qemuDomainChangeNetBridge(virDomainObjPtr vm,
3474 3475
                          virDomainNetDefPtr olddev,
                          virDomainNetDefPtr newdev)
3476 3477
{
    int ret = -1;
3478 3479
    const char *oldbridge = virDomainNetGetActualBridgeName(olddev);
    const char *newbridge = virDomainNetGetActualBridgeName(newdev);
3480

3481 3482
    if (!oldbridge || !newbridge) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
3483
        goto cleanup;
3484
    }
3485 3486 3487 3488 3489

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

    if (virNetDevExists(newbridge) != 1) {
3490 3491
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("bridge %s doesn't exist"), newbridge);
3492
        goto cleanup;
3493 3494
    }

3495 3496 3497 3498 3499 3500 3501 3502 3503
    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);
3504 3505 3506
    }

    ret = virNetDevBridgeAddPort(newbridge, olddev->ifname);
3507
    virDomainAuditNet(vm, NULL, newdev, "attach", ret == 0);
3508 3509 3510 3511
    if (ret < 0) {
        ret = virNetDevBridgeAddPort(oldbridge, olddev->ifname);
        virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
        if (ret < 0) {
3512
            virReportError(VIR_ERR_OPERATION_FAILED,
3513
                           _("unable to recover former state by adding port "
3514
                             "to bridge %s"), oldbridge);
3515
        }
3516
        goto cleanup;
3517
    }
3518 3519
    /* caller will replace entire olddev with newdev in domain nets list */
    ret = 0;
3520
 cleanup:
3521
    return ret;
3522 3523
}

3524
static int
3525
qemuDomainChangeNetFilter(virDomainObjPtr vm,
3526 3527 3528 3529 3530 3531 3532
                          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:
3533
    case VIR_DOMAIN_NET_TYPE_NETWORK:
3534
        break;
3535 3536 3537 3538 3539 3540 3541 3542 3543
    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:
3544 3545 3546 3547
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("filters not supported on interfaces of type %s"),
                       virDomainNetTypeToString(virDomainNetGetActualType(newdev)));
        return -1;
3548 3549 3550 3551 3552
    case VIR_DOMAIN_NET_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainNetType,
                                virDomainNetGetActualType(newdev));
        return -1;
3553 3554 3555 3556
    }

    virDomainConfNWFilterTeardown(olddev);

3557
    if (newdev->filter &&
3558
        virDomainConfNWFilterInstantiate(vm->def->name,
3559
                                         vm->def->uuid, newdev, false) < 0) {
3560 3561 3562 3563 3564 3565
        virErrorPtr errobj;

        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to add new filter rules to '%s' "
                         "- attempting to restore old rules"),
                       olddev->ifname);
3566
        virErrorPreserveLast(&errobj);
3567
        ignore_value(virDomainConfNWFilterInstantiate(vm->def->name,
3568
                                                      vm->def->uuid, olddev, false));
3569
        virErrorRestore(&errobj);
3570 3571 3572 3573 3574
        return -1;
    }
    return 0;
}

3575
int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver,
3576 3577 3578 3579 3580 3581 3582 3583
                                 virDomainObjPtr vm,
                                 virDomainNetDefPtr dev,
                                 int linkstate)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if (!dev->info.alias) {
3584 3585
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("can't change link state: device alias not found"));
3586 3587 3588
        return -1;
    }

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

3591
    qemuDomainObjEnterMonitor(driver, vm);
3592 3593 3594 3595 3596 3597 3598 3599

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

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

3600
 cleanup:
3601 3602
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        return -1;
3603 3604 3605 3606

    return ret;
}

3607
int
3608
qemuDomainChangeNet(virQEMUDriverPtr driver,
3609 3610
                    virDomainObjPtr vm,
                    virDomainDeviceDefPtr dev)
3611
{
3612
    virDomainNetDefPtr newdev = dev->data.net;
3613
    virDomainNetDefPtr *devslot = NULL;
3614
    virDomainNetDefPtr olddev;
3615
    virDomainNetType oldType, newType;
3616 3617
    bool needReconnect = false;
    bool needBridgeChange = false;
3618
    bool needFilterChange = false;
3619 3620
    bool needLinkStateChange = false;
    bool needReplaceDevDef = false;
3621
    bool needBandwidthSet = false;
3622
    bool needCoalesceChange = false;
3623
    bool needVlanUpdate = false;
3624
    int ret = -1;
3625
    int changeidx = -1;
3626
    virConnectPtr conn = NULL;
3627
    virErrorPtr save_err = NULL;
3628 3629 3630 3631

    if ((changeidx = virDomainNetFindIdx(vm->def, newdev)) < 0)
        goto cleanup;
    devslot = &vm->def->nets[changeidx];
3632
    olddev = *devslot;
3633 3634 3635 3636

    oldType = virDomainNetGetActualType(olddev);
    if (oldType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* no changes are possible to a type='hostdev' interface */
3637
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659
                       _("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];

3660
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3661 3662 3663 3664 3665 3666 3667
                       _("cannot change network interface mac address "
                         "from %s to %s"),
                       virMacAddrFormat(&olddev->mac, oldmac),
                       virMacAddrFormat(&newdev->mac, newmac));
        goto cleanup;
    }

3668 3669
    if (STRNEQ_NULLABLE(virDomainNetGetModelString(olddev),
                        virDomainNetGetModelString(newdev))) {
3670
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3671
                       _("cannot modify network device model from %s to %s"),
3672 3673
                       NULLSTR(virDomainNetGetModelString(olddev)),
                       NULLSTR(virDomainNetGetModelString(newdev)));
3674
        goto cleanup;
3675 3676
    }

3677 3678 3679 3680 3681 3682 3683 3684
    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;
    }

3685
    if (virDomainNetIsVirtioModel(olddev) &&
3686 3687 3688
        (olddev->driver.virtio.name != newdev->driver.virtio.name ||
         olddev->driver.virtio.txmode != newdev->driver.virtio.txmode ||
         olddev->driver.virtio.ioeventfd != newdev->driver.virtio.ioeventfd ||
3689
         olddev->driver.virtio.event_idx != newdev->driver.virtio.event_idx ||
3690
         olddev->driver.virtio.queues != newdev->driver.virtio.queues ||
3691 3692
         olddev->driver.virtio.rx_queue_size != newdev->driver.virtio.rx_queue_size ||
         olddev->driver.virtio.tx_queue_size != newdev->driver.virtio.tx_queue_size ||
3693 3694 3695 3696 3697 3698
         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 已提交
3699
         olddev->driver.virtio.host.mrg_rxbuf != newdev->driver.virtio.host.mrg_rxbuf ||
3700 3701 3702 3703 3704
         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)) {
3705
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3706 3707 3708 3709 3710 3711 3712 3713 3714 3715
                       _("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;
3716 3717
    }

3718
    if (STRNEQ_NULLABLE(olddev->script, newdev->script)) {
3719
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3720 3721
                       _("cannot modify network device script attribute"));
        goto cleanup;
3722 3723
    }

3724
    /* ifname: check if it's set in newdev. If not, retain the autogenerated one */
3725
    if (!newdev->ifname && VIR_STRDUP(newdev->ifname, olddev->ifname) < 0)
3726 3727
        goto cleanup;
    if (STRNEQ_NULLABLE(olddev->ifname, newdev->ifname)) {
3728
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3729 3730 3731
                       _("cannot modify network device tap name"));
        goto cleanup;
    }
3732

3733 3734
    /* info: Nothing is allowed to change. First fill the missing newdev->info
     * from olddev and then check for changes.
3735
     */
3736 3737 3738 3739 3740 3741 3742 3743 3744 3745
    /* 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"));
3746
    }
3747
    if (!virPCIDeviceAddressEqual(&olddev->info.addr.pci,
3748
                                  &newdev->info.addr.pci)) {
3749
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3750 3751 3752 3753
                       _("cannot modify network device guest PCI address"));
        goto cleanup;
    }
    /* grab alias from olddev if not set in newdev */
3754 3755
    if (!newdev->info.alias &&
        VIR_STRDUP(newdev->info.alias, olddev->info.alias) < 0)
3756
        goto cleanup;
3757 3758 3759

    /* device alias is checked already in virDomainDefCompatibleDevice */

3760 3761
    if (newdev->info.rombar == VIR_TRISTATE_BOOL_ABSENT)
        newdev->info.rombar = olddev->info.rombar;
3762
    if (olddev->info.rombar != newdev->info.rombar) {
3763
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3764 3765 3766
                       _("cannot modify network device rom bar setting"));
        goto cleanup;
    }
3767 3768 3769 3770

    if (!newdev->info.romfile &&
        VIR_STRDUP(newdev->info.romfile, olddev->info.romfile) < 0)
        goto cleanup;
3771
    if (STRNEQ_NULLABLE(olddev->info.romfile, newdev->info.romfile)) {
3772
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3773 3774 3775
                       _("cannot modify network rom file"));
        goto cleanup;
    }
3776 3777 3778

    if (newdev->info.bootIndex == 0)
        newdev->info.bootIndex = olddev->info.bootIndex;
3779
    if (olddev->info.bootIndex != newdev->info.bootIndex) {
3780
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3781 3782 3783
                       _("cannot modify network device boot index setting"));
        goto cleanup;
    }
3784 3785 3786

    if (newdev->info.romenabled == VIR_TRISTATE_BOOL_ABSENT)
        newdev->info.romenabled = olddev->info.romenabled;
3787 3788 3789 3790 3791
    if (olddev->info.romenabled != newdev->info.romenabled) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot modify network device rom enabled setting"));
        goto cleanup;
    }
3792
    /* (end of device info checks) */
3793

3794 3795 3796 3797
    if (STRNEQ_NULLABLE(olddev->filter, newdev->filter) ||
        !virNWFilterHashTableEqual(olddev->filterparams, newdev->filterparams)) {
        needFilterChange = true;
    }
3798

3799 3800 3801 3802
    /* bandwidth can be modified, and will be checked later */
    /* vlan can be modified, and will be checked later */
    /* linkstate can be modified */

3803 3804 3805 3806 3807 3808
    if (olddev->mtu != newdev->mtu) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot modify MTU"));
        goto cleanup;
    }

3809 3810 3811
    /* allocate new actual device to compare to old - we will need to
     * free it if we fail for any reason
     */
3812 3813 3814 3815 3816
    if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        if (!(conn = virGetConnectNetwork()))
            goto cleanup;
        if (virDomainNetAllocateActualDevice(conn, vm->def, newdev) < 0)
            goto cleanup;
3817 3818 3819 3820 3821 3822
    }

    newType = virDomainNetGetActualType(newdev);

    if (newType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* can't turn it into a type='hostdev' interface */
3823
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3824 3825 3826 3827 3828 3829
                       _("cannot change network interface type to '%s'"),
                       virDomainNetTypeToString(newType));
        goto cleanup;
    }

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

3831 3832 3833 3834 3835 3836
        /* 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:
3837
            break;
3838

3839 3840 3841
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
3842
        case VIR_DOMAIN_NET_TYPE_UDP:
3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874
            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;

3875 3876
        case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
        case VIR_DOMAIN_NET_TYPE_HOSTDEV:
3877
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3878 3879
                           _("unable to change config on '%s' network type"),
                           virDomainNetTypeToString(newdev->type));
3880 3881 3882 3883 3884
            goto cleanup;
        case VIR_DOMAIN_NET_TYPE_LAST:
        default:
            virReportEnumRangeError(virDomainNetType, newdev->type);
            goto cleanup;
3885
        }
3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916
    } 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;
3917 3918

        }
3919
    }
3920

3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931
    /* 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;
    }
3932

3933 3934
    if (STRNEQ_NULLABLE(virDomainNetGetActualDirectDev(olddev),
                        virDomainNetGetActualDirectDev(newdev)) ||
3935
        virDomainNetGetActualDirectMode(olddev) != virDomainNetGetActualDirectMode(newdev) ||
3936
        !virNetDevVPortProfileEqual(virDomainNetGetActualVirtPortProfile(olddev),
3937
                                    virDomainNetGetActualVirtPortProfile(newdev))) {
3938
        needReconnect = true;
3939 3940
    }

3941 3942 3943 3944 3945
    if (!virNetDevVlanEqual(virDomainNetGetActualVlan(olddev),
                             virDomainNetGetActualVlan(newdev))) {
        needVlanUpdate = true;
    }

3946 3947 3948
    if (olddev->linkstate != newdev->linkstate)
        needLinkStateChange = true;

3949 3950 3951 3952
    if (!virNetDevBandwidthEqual(virDomainNetGetActualBandwidth(olddev),
                                 virDomainNetGetActualBandwidth(newdev)))
        needBandwidthSet = true;

3953 3954
    if (!!olddev->coalesce != !!newdev->coalesce ||
        (olddev->coalesce && newdev->coalesce &&
3955 3956
         memcmp(olddev->coalesce, newdev->coalesce,
                sizeof(*olddev->coalesce))))
3957 3958
        needCoalesceChange = true;

3959 3960 3961
    /* FINALLY - actually perform the required actions */

    if (needReconnect) {
3962
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3963 3964 3965
                       _("unable to change config on '%s' network type"),
                       virDomainNetTypeToString(newdev->type));
        goto cleanup;
3966 3967
    }

3968
    if (needBandwidthSet) {
3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981
        virNetDevBandwidthPtr newb = virDomainNetGetActualBandwidth(newdev);

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

3985
    if (needBridgeChange) {
3986
        if (qemuDomainChangeNetBridge(vm, olddev, newdev) < 0)
3987 3988 3989
            goto cleanup;
        /* we successfully switched to the new bridge, and we've
         * determined that the rest of newdev is equivalent to olddev,
3990 3991 3992 3993 3994
         * so move newdev into place */
        needReplaceDevDef = true;
    }

    if (needFilterChange) {
3995
        if (qemuDomainChangeNetFilter(vm, olddev, newdev) < 0)
3996 3997 3998 3999
            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 */
4000
        needReplaceDevDef = true;
4001 4002
    }

4003 4004 4005 4006 4007 4008
    if (needCoalesceChange) {
        if (virNetDevSetCoalesce(newdev->ifname, newdev->coalesce, true) < 0)
            goto cleanup;
        needReplaceDevDef = true;
    }

4009 4010 4011
    if (needLinkStateChange &&
        qemuDomainChangeNetLinkState(driver, vm, olddev, newdev->linkstate) < 0) {
        goto cleanup;
4012 4013
    }

4014 4015 4016 4017 4018 4019
    if (needVlanUpdate) {
        if (virNetDevOpenvswitchUpdateVlan(newdev->ifname, &newdev->vlan) < 0)
            goto cleanup;
        needReplaceDevDef = true;
    }

4020 4021 4022 4023
    if (needReplaceDevDef) {
        /* the changes above warrant replacing olddev with newdev in
         * the domain's nets list.
         */
4024 4025 4026

        /* this function doesn't work with HOSTDEV networks yet, thus
         * no need to change the pointer in the hostdev structure */
4027 4028 4029 4030 4031 4032
        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));
        }
4033 4034 4035 4036 4037 4038 4039 4040
        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;
4041 4042
    }

4043
    ret = 0;
4044
 cleanup:
4045
    virErrorPreserveLast(&save_err);
4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063
    /* 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.
     */
4064 4065 4066
    if (newdev && newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK && conn)
        virDomainNetReleaseActualDevice(conn, vm->def, newdev);
    virObjectUnref(conn);
4067
    virErrorRestore(&save_err);
4068

4069 4070 4071
    return ret;
}

4072 4073 4074
static virDomainGraphicsDefPtr
qemuDomainFindGraphics(virDomainObjPtr vm,
                       virDomainGraphicsDefPtr dev)
4075
{
4076
    size_t i;
4077

4078
    for (i = 0; i < vm->def->ngraphics; i++) {
4079 4080 4081 4082 4083 4084 4085
        if (vm->def->graphics[i]->type == dev->type)
            return vm->def->graphics[i];
    }

    return NULL;
}

4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099
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;
}

4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154

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

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

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

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

    if (ret != 0)
        goto end_job;

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

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

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


4155
int
4156
qemuDomainChangeGraphics(virQEMUDriverPtr driver,
4157 4158 4159 4160
                         virDomainObjPtr vm,
                         virDomainGraphicsDefPtr dev)
{
    virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
4161
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
4162
    const char *type = virDomainGraphicsTypeToString(dev->type);
4163
    size_t i;
4164
    int ret = -1;
4165 4166

    if (!olddev) {
4167
        virReportError(VIR_ERR_DEVICE_MISSING,
4168 4169
                       _("cannot find existing graphics device to modify of "
                         "type '%s'"), type);
4170
        goto cleanup;
4171 4172
    }

4173
    if (dev->nListens != olddev->nListens) {
4174 4175 4176
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("cannot change the number of listen addresses "
                         "on '%s' graphics"), type);
4177 4178 4179 4180
        goto cleanup;
    }

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

J
Jim Fehlig 已提交
4184
        if (newlisten->type != oldlisten->type) {
4185 4186 4187
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                           _("cannot change the type of listen address "
                             "on '%s' graphics"), type);
4188 4189 4190
            goto cleanup;
        }

4191
        switch (newlisten->type) {
4192
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
J
Jim Fehlig 已提交
4193
            if (STRNEQ_NULLABLE(newlisten->address, oldlisten->address)) {
4194 4195 4196
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen address setting "
                                 "on '%s' graphics"), type);
4197 4198
                goto cleanup;
            }
4199

4200 4201 4202
            break;

        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
J
Jim Fehlig 已提交
4203
            if (STRNEQ_NULLABLE(newlisten->network, oldlisten->network)) {
4204 4205 4206
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen address setting "
                                 "on '%s' graphics"), type);
4207 4208
                goto cleanup;
            }
4209

4210 4211
            break;

4212 4213 4214 4215 4216 4217 4218 4219 4220
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_SOCKET:
            if (STRNEQ_NULLABLE(newlisten->socket, oldlisten->socket)) {
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen socket setting "
                                 "on '%s' graphics"), type);
                goto cleanup;
            }
            break;

4221 4222 4223 4224 4225 4226
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE:
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST:
            /* nada */
            break;
        }
    }
4227

4228 4229
    switch (dev->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
4230 4231 4232
        if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
            (!dev->data.vnc.autoport &&
             (olddev->data.vnc.port != dev->data.vnc.port))) {
4233
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4234
                           _("cannot change port settings on vnc graphics"));
4235
            goto cleanup;
4236 4237
        }
        if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
4238
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4239
                           _("cannot change keymap setting on vnc graphics"));
4240
            goto cleanup;
4241 4242
        }

4243 4244 4245
        /* 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 */
4246 4247
        if (olddev->data.vnc.auth.expires ||
            dev->data.vnc.auth.expires ||
4248
            olddev->data.vnc.auth.connected != dev->data.vnc.auth.connected ||
E
Eric Blake 已提交
4249 4250 4251
            STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd,
                            dev->data.vnc.auth.passwd)) {
            VIR_DEBUG("Updating password on VNC server %p %p",
4252
                      dev->data.vnc.auth.passwd, cfg->vncPassword);
E
Eric Blake 已提交
4253 4254 4255
            ret = qemuDomainChangeGraphicsPasswords(driver, vm,
                                                    VIR_DOMAIN_GRAPHICS_TYPE_VNC,
                                                    &dev->data.vnc.auth,
4256 4257
                                                    cfg->vncPassword,
                                                    QEMU_ASYNC_JOB_NONE);
4258
            if (ret < 0)
4259
                goto cleanup;
4260 4261 4262 4263 4264

            /* 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;
4265 4266
            olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo;
            olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires;
4267
            olddev->data.vnc.auth.connected = dev->data.vnc.auth.connected;
4268 4269 4270 4271 4272
        } else {
            ret = 0;
        }
        break;

4273
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
4274 4275 4276 4277 4278
        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))) {
4279
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4280
                           _("cannot change port settings on spice graphics"));
4281
            goto cleanup;
4282
        }
E
Eric Blake 已提交
4283 4284
        if (STRNEQ_NULLABLE(olddev->data.spice.keymap,
                            dev->data.spice.keymap)) {
4285
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4286
                            _("cannot change keymap setting on spice graphics"));
4287
            goto cleanup;
4288 4289
        }

4290 4291 4292 4293 4294
        /* 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"
         */
4295 4296
        if (olddev->data.spice.auth.expires ||
            dev->data.spice.auth.expires ||
4297
            olddev->data.spice.auth.connected != dev->data.spice.auth.connected ||
4298 4299
            dev->data.spice.auth.connected ==
            VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DISCONNECT ||
E
Eric Blake 已提交
4300 4301 4302
            STRNEQ_NULLABLE(olddev->data.spice.auth.passwd,
                            dev->data.spice.auth.passwd)) {
            VIR_DEBUG("Updating password on SPICE server %p %p",
4303
                      dev->data.spice.auth.passwd, cfg->spicePassword);
E
Eric Blake 已提交
4304 4305 4306
            ret = qemuDomainChangeGraphicsPasswords(driver, vm,
                                                    VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
                                                    &dev->data.spice.auth,
4307 4308
                                                    cfg->spicePassword,
                                                    QEMU_ASYNC_JOB_NONE);
E
Eric Blake 已提交
4309

4310
            if (ret < 0)
4311
                goto cleanup;
4312

E
Eric Blake 已提交
4313
            /* Steal the new dev's char * reference */
4314 4315 4316 4317 4318
            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;
4319
            olddev->data.spice.auth.connected = dev->data.spice.auth.connected;
4320
        } else {
4321
            VIR_DEBUG("Not updating since password didn't change");
4322 4323
            ret = 0;
        }
E
Eric Blake 已提交
4324
        break;
4325

4326 4327 4328
    case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
    case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
    case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
4329
    case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
4330
        virReportError(VIR_ERR_INTERNAL_ERROR,
4331
                       _("unable to change config on '%s' graphics type"), type);
4332
        break;
4333 4334 4335 4336
    case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
    default:
        virReportEnumRangeError(virDomainGraphicsType, dev->type);
        break;
4337 4338
    }

4339
 cleanup:
4340 4341 4342 4343
    return ret;
}


4344
static int qemuComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
4345
                                virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
4346
                                virDomainDeviceInfoPtr info1,
4347 4348
                                void *opaque)
{
4349
    virDomainDeviceInfoPtr info2 = opaque;
4350

4351 4352
    if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
        info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
4353 4354
        return 0;

4355 4356 4357
    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 &&
4358
        info1->addr.pci.function != info2->addr.pci.function)
4359 4360 4361 4362 4363
        return -1;
    return 0;
}

static bool qemuIsMultiFunctionDevice(virDomainDefPtr def,
4364
                                      virDomainDeviceInfoPtr info)
4365
{
4366
    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
4367 4368
        return false;

4369
    if (virDomainDeviceInfoIterate(def, qemuComparePCIDevice, info) < 0)
4370 4371 4372 4373
        return true;
    return false;
}

4374

4375
static int
4376 4377 4378 4379
qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainDiskDefPtr disk)
{
4380
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
4381
    qemuHotplugDiskSourceDataPtr diskbackend = NULL;
4382 4383
    virDomainDeviceDef dev;
    size_t i;
4384
    qemuDomainObjPrivatePtr priv = vm->privateData;
4385 4386
    VIR_AUTOFREE(char *) corAlias = NULL;
    bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
4387
    int ret = -1;
4388 4389 4390 4391

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

4392 4393
    if (!(diskbackend = qemuHotplugDiskSourceRemovePrepare(disk, disk->src,
                                                           priv->qemuCaps)))
4394 4395
        return -1;

4396 4397 4398 4399 4400
    if (blockdev) {
        if (VIR_STRDUP(corAlias, diskPriv->nodeCopyOnRead) < 0)
            goto cleanup;
    }

4401 4402 4403 4404 4405 4406 4407
    for (i = 0; i < vm->def->ndisks; i++) {
        if (vm->def->disks[i] == disk) {
            virDomainDiskRemove(vm->def, i);
            break;
        }
    }

4408
    qemuDomainObjEnterMonitor(driver, vm);
4409

4410 4411 4412
    if (corAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, corAlias));

4413
    qemuHotplugDiskSourceRemove(priv->mon, diskbackend);
4414

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

4418
    virDomainAuditDisk(vm, disk->src, NULL, "detach", true);
4419

4420
    qemuDomainReleaseDeviceAddress(vm, &disk->info);
4421

4422
    /* tear down disk security access */
4423
    qemuDomainStorageSourceChainAccessRevoke(driver, vm, disk->src);
4424

4425 4426 4427 4428
    dev.type = VIR_DOMAIN_DEVICE_DISK;
    dev.data.disk = disk;
    ignore_value(qemuRemoveSharedDevice(driver, &dev, vm->def->name));

4429 4430 4431
    if (qemuHotplugRemoveManagedPR(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
        goto cleanup;

4432 4433 4434
    ret = 0;

 cleanup:
4435
    qemuHotplugDiskSourceDataFree(diskbackend);
4436
    virDomainDiskDefFree(disk);
4437
    return ret;
4438 4439 4440
}


4441
static int
4442
qemuDomainRemoveControllerDevice(virDomainObjPtr vm,
4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456
                                 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;
        }
    }

4457
    qemuDomainReleaseDeviceAddress(vm, &controller->info);
4458
    virDomainControllerDefFree(controller);
4459
    return 0;
4460 4461 4462
}


4463 4464 4465 4466 4467 4468
static int
qemuDomainRemoveMemoryDevice(virQEMUDriverPtr driver,
                             virDomainObjPtr vm,
                             virDomainMemoryDefPtr mem)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4469
    unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
4470
    unsigned long long newmem = oldmem - mem->size;
4471 4472 4473 4474 4475 4476 4477 4478
    char *backendAlias = NULL;
    int rc;
    int idx;

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

    if (virAsprintf(&backendAlias, "mem%s", mem->info.alias) < 0)
4479
        return -1;
4480 4481 4482

    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorDelObject(priv->mon, backendAlias);
4483 4484 4485 4486 4487 4488 4489 4490
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        rc = -1;

    VIR_FREE(backendAlias);

    virDomainAuditMemory(vm, oldmem, newmem, "update", rc == 0);
    if (rc < 0)
        return -1;
4491 4492 4493 4494

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

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

4498 4499 4500
    if (qemuTeardownMemoryDevicesCgroup(vm, mem) < 0)
        VIR_WARN("Unable to remove memory device cgroup ACL");

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

4504 4505 4506
    if (qemuProcessDestroyMemoryBackingPath(driver, vm, mem) < 0)
        VIR_WARN("Unable to destroy memory backing path");

4507
    virDomainMemoryDefFree(mem);
4508

4509 4510 4511
    /* fix the balloon size */
    ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));

4512
    /* decrease the mlock limit after memory unplug if necessary */
4513
    ignore_value(qemuDomainAdjustMaxMemLock(vm));
4514

4515
    return 0;
4516 4517 4518
}


4519 4520 4521 4522 4523
static void
qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
{
4524
    qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
4525
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4526 4527 4528 4529
}

static void
qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver,
4530
                              virDomainObjPtr vm,
4531 4532
                              virDomainHostdevDefPtr hostdev)
{
4533
    qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
4534
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4535 4536 4537 4538 4539 4540 4541
}

static void
qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
4542
    qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
4543 4544
}

4545 4546 4547 4548 4549 4550 4551 4552
static void
qemuDomainRemoveSCSIVHostDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainHostdevDefPtr hostdev)
{
    qemuHostdevReAttachSCSIVHostDevices(driver, vm->def->name, &hostdev, 1);
}

4553 4554 4555 4556 4557 4558 4559

static void
qemuDomainRemoveMediatedDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    qemuHostdevReAttachMediatedDevices(driver, vm->def->name, &hostdev, 1);
4560
    qemuDomainReleaseDeviceAddress(vm, hostdev->info);
4561 4562 4563
}


4564
static int
4565 4566 4567 4568 4569 4570
qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainHostdevDefPtr hostdev)
{
    virDomainNetDefPtr net = NULL;
    size_t i;
4571 4572
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
J
John Ferlan 已提交
4573
    char *drivealias = NULL;
4574
    char *objAlias = NULL;
4575
    bool is_vfio = false;
4576 4577 4578 4579

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

4580 4581 4582 4583 4584
    if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
        int backend = hostdev->source.subsys.u.pci.backend;
        is_vfio = backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
    }

4585
    if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
4586 4587 4588
        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
        virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;

J
John Ferlan 已提交
4589
        if (!(drivealias = qemuAliasFromHostdev(hostdev)))
4590 4591
            goto cleanup;

4592 4593 4594 4595 4596
        /* 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) &&
4597
            qemuDomainStorageSourceHasAuth(iscsisrc->src)) {
4598 4599 4600 4601
            if (!(objAlias = qemuDomainGetSecretAESAlias(hostdev->info->alias, false)))
                goto cleanup;
        }

4602
        qemuDomainObjEnterMonitor(driver, vm);
J
John Ferlan 已提交
4603
        qemuMonitorDriveDel(priv->mon, drivealias);
4604 4605 4606 4607 4608

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

4609 4610
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            goto cleanup;
4611 4612
    }

4613
    if (hostdev->parentnet) {
4614
        for (i = 0; i < vm->def->nnets; i++) {
4615
            if (vm->def->nets[i] == hostdev->parentnet) {
4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630
                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);

4631
    if (!is_vfio &&
4632
        qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
4633
        VIR_WARN("Failed to restore host device labelling");
4634

4635 4636 4637
    if (qemuTeardownHostdevCgroup(vm, hostdev) < 0)
        VIR_WARN("Failed to remove host device cgroup ACL");

4638
    if (qemuDomainNamespaceTeardownHostdev(vm, hostdev) < 0)
4639 4640
        VIR_WARN("Unable to remove host device from /dev");

4641
    switch ((virDomainHostdevSubsysType)hostdev->source.subsys.type) {
4642 4643
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
        qemuDomainRemovePCIHostDevice(driver, vm, hostdev);
4644 4645 4646 4647
        /* 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");
4648 4649 4650 4651 4652 4653 4654
        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;
4655
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
4656
        qemuDomainRemoveSCSIVHostDevice(driver, vm, hostdev);
4657
        break;
4658
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
4659
        qemuDomainRemoveMediatedDevice(driver, vm, hostdev);
4660
        break;
4661 4662 4663 4664 4665 4666 4667
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
        break;
    }

    virDomainHostdevDefFree(hostdev);

    if (net) {
4668 4669 4670 4671 4672 4673 4674 4675 4676
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            virConnectPtr conn = virGetConnectNetwork();
            if (conn) {
                virDomainNetReleaseActualDevice(conn, vm->def, net);
                virObjectUnref(conn);
            } else {
                VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
            }
        }
4677 4678
        virDomainNetDefFree(net);
    }
4679

4680 4681 4682
    ret = 0;

 cleanup:
J
John Ferlan 已提交
4683
    VIR_FREE(drivealias);
4684
    VIR_FREE(objAlias);
4685
    return ret;
4686 4687 4688
}


4689
static int
4690 4691 4692 4693
qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainNetDefPtr net)
{
4694
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
4695 4696
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *hostnet_name = NULL;
4697
    char *charDevAlias = NULL;
4698
    size_t i;
4699
    int ret = -1;
4700
    int actualType = virDomainNetGetActualType(net);
4701

4702
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
4703
        /* this function handles all hostdev and netdev cleanup */
4704 4705
        ret = qemuDomainRemoveHostDevice(driver, vm,
                                         virDomainNetGetActualHostdev(net));
4706
        goto cleanup;
4707 4708
    }

4709 4710 4711
    VIR_DEBUG("Removing network interface %s from domain %p %s",
              net->info.alias, vm, vm->def->name);

4712
    if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0 ||
4713
        !(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias)))
4714 4715
        goto cleanup;

4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726
    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));
4727

4728
    qemuDomainObjEnterMonitor(driver, vm);
J
Ján Tomko 已提交
4729 4730
    if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
4731
            goto cleanup;
J
Ján Tomko 已提交
4732 4733
        virDomainAuditNet(vm, net, NULL, "detach", false);
        goto cleanup;
4734
    }
4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745

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

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

4749 4750 4751 4752 4753 4754 4755 4756 4757
    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;
        }
    }

4758
    qemuDomainReleaseDeviceAddress(vm, &net->info);
4759 4760
    virDomainConfNWFilterTeardown(net);

4761 4762 4763 4764 4765 4766
    if (cfg->macFilter && (net->ifname != NULL)) {
        ignore_value(ebtablesRemoveForwardAllowIn(driver->ebtables,
                                                  net->ifname,
                                                  &net->mac));
    }

4767
    if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
4768 4769 4770 4771 4772 4773 4774 4775
        ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
                         net->ifname, &net->mac,
                         virDomainNetGetActualDirectDev(net),
                         virDomainNetGetActualDirectMode(net),
                         virDomainNetGetActualVirtPortProfile(net),
                         cfg->stateDir));
    }

4776
    qemuDomainNetDeviceVportRemove(net);
4777

4778 4779 4780 4781 4782 4783 4784 4785 4786
    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virConnectPtr conn = virGetConnectNetwork();
        if (conn) {
            virDomainNetReleaseActualDevice(conn, vm->def, net);
            virObjectUnref(conn);
        } else {
            VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
        }
    }
4787
    virDomainNetDefFree(net);
4788
    ret = 0;
4789 4790

 cleanup:
4791
    VIR_FREE(charDevAlias);
4792 4793
    VIR_FREE(hostnet_name);
    return ret;
4794 4795 4796
}


4797
static int
4798
qemuDomainRemoveChrDevice(virQEMUDriverPtr driver,
4799
                          virDomainObjPtr vm,
4800 4801
                          virDomainChrDefPtr chr,
                          bool monitor)
4802
{
4803
    virObjectEventPtr event;
4804 4805 4806
    char *charAlias = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
4807
    int rc = 0;
4808

4809 4810 4811
    VIR_DEBUG("Removing character device %s from domain %p %s",
              chr->info.alias, vm, vm->def->name);

4812 4813
    if (!(charAlias = qemuAliasChardevFromDevAlias(chr->info.alias)))
        goto cleanup;
4814

4815
    if (monitor) {
4816 4817 4818 4819 4820
        qemuDomainObjEnterMonitor(driver, vm);
        rc = qemuMonitorDetachCharDev(priv->mon, charAlias);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            goto cleanup;
    }
4821

4822 4823
    if (rc == 0 &&
        qemuDomainDelChardevTLSObjects(driver, vm, chr->source, charAlias) < 0)
4824 4825
        goto cleanup;

4826 4827 4828 4829 4830
    virDomainAuditChardev(vm, chr, NULL, "detach", rc == 0);

    if (rc < 0)
        goto cleanup;

4831 4832 4833
    if (qemuTeardownChardevCgroup(vm, chr) < 0)
        VIR_WARN("Failed to remove chr device cgroup ACL");

4834 4835 4836
    if (qemuSecurityRestoreChardevLabel(driver, vm, chr) < 0)
        VIR_WARN("Unable to restore security label on char device");

4837
    if (qemuDomainNamespaceTeardownChardev(vm, chr) < 0)
4838 4839
        VIR_WARN("Unable to remove chr device from /dev");

4840
    qemuDomainReleaseDeviceAddress(vm, &chr->info);
4841 4842 4843 4844 4845 4846
    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.
     */
4847
    event = virDomainEventDeviceRemovedNewFromObj(vm, chr->info.alias);
4848
    virObjectEventStateQueue(driver->domainEventState, event);
4849

4850
    virDomainChrDefFree(chr);
4851 4852 4853 4854 4855
    ret = 0;

 cleanup:
    VIR_FREE(charAlias);
    return ret;
4856 4857 4858
}


4859 4860 4861 4862 4863 4864 4865 4866 4867 4868
static int
qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
    char *charAlias = NULL;
    char *objAlias = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ssize_t idx;
    int ret = -1;
4869
    int rc = 0;
4870 4871 4872 4873

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

4874

4875 4876 4877
    if (virAsprintf(&objAlias, "obj%s", rng->info.alias) < 0)
        goto cleanup;

4878
    if (!(charAlias = qemuAliasChardevFromDevAlias(rng->info.alias)))
4879 4880 4881
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);
4882

4883 4884 4885 4886 4887 4888 4889 4890
    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;
4891 4892 4893 4894

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

4895 4896
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
        rc == 0 &&
4897 4898
        qemuDomainDelChardevTLSObjects(driver, vm, rng->source.chardev,
                                       charAlias) < 0)
4899
        rc = -1;
4900

4901 4902 4903 4904 4905
    virDomainAuditRNG(vm, rng, NULL, "detach", rc == 0);

    if (rc < 0)
        goto cleanup;

4906 4907 4908
    if (qemuTeardownRNGCgroup(vm, rng) < 0)
        VIR_WARN("Failed to remove RNG device cgroup ACL");

4909
    if (qemuDomainNamespaceTeardownRNG(vm, rng) < 0)
4910 4911
        VIR_WARN("Unable to remove RNG device from /dev");

4912 4913
    if ((idx = virDomainRNGFind(vm->def, rng)) >= 0)
        virDomainRNGRemove(vm->def, idx);
4914
    qemuDomainReleaseDeviceAddress(vm, &rng->info);
4915 4916 4917 4918 4919 4920 4921 4922 4923 4924
    virDomainRNGDefFree(rng);
    ret = 0;

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


4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964
static int
qemuDomainRemoveShmemDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainShmemDefPtr shmem)
{
    int rc;
    int ret = -1;
    ssize_t idx = -1;
    char *charAlias = NULL;
    char *memAlias = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;

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

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

    qemuDomainObjEnterMonitor(driver, vm);

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

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

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

    if (rc < 0)
        goto cleanup;

    if ((idx = virDomainShmemDefFind(vm->def, shmem)) >= 0)
        virDomainShmemDefRemove(vm->def, idx);
4965
    qemuDomainReleaseDeviceAddress(vm, &shmem->info);
4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976
    virDomainShmemDefFree(shmem);

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

    return ret;
}


M
Michal Privoznik 已提交
4977
static int
4978
qemuDomainRemoveWatchdog(virDomainObjPtr vm,
M
Michal Privoznik 已提交
4979 4980 4981 4982 4983
                         virDomainWatchdogDefPtr watchdog)
{
    VIR_DEBUG("Removing watchdog %s from domain %p %s",
              watchdog->info.alias, vm, vm->def->name);

4984
    qemuDomainReleaseDeviceAddress(vm, &watchdog->info);
M
Michal Privoznik 已提交
4985 4986 4987 4988 4989 4990
    virDomainWatchdogDefFree(vm->def->watchdog);
    vm->def->watchdog = NULL;
    return 0;
}


4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003
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;
    }
5004
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
5005 5006 5007 5008 5009 5010 5011 5012 5013
    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");

5014 5015 5016 5017 5018 5019
    virDomainInputDefFree(vm->def->inputs[i]);
    VIR_DELETE_ELEMENT(vm->def->inputs, i, vm->def->ninputs);
    return 0;
}


J
Ján Tomko 已提交
5020 5021 5022 5023 5024 5025 5026
static int
qemuDomainRemoveVsockDevice(virDomainObjPtr vm,
                            virDomainVsockDefPtr dev)
{
    VIR_DEBUG("Removing vsock device %s from domain %p %s",
              dev->info.alias, vm, vm->def->name);

5027
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
J
Ján Tomko 已提交
5028 5029 5030 5031 5032 5033
    virDomainVsockDefFree(vm->def->vsock);
    vm->def->vsock = NULL;
    return 0;
}


5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065
static int
qemuDomainRemoveRedirdevDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainRedirdevDefPtr dev)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *charAlias = NULL;
    ssize_t idx;
    int ret = -1;

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

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

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

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

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

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

    if ((idx = virDomainRedirdevDefFind(vm->def, dev)) >= 0)
        virDomainRedirdevDefRemove(vm->def, idx);
5066
    qemuDomainReleaseDeviceAddress(vm, &dev->info);
5067 5068 5069 5070 5071 5072 5073 5074 5075 5076
    virDomainRedirdevDefFree(dev);

    ret = 0;

 cleanup:
    VIR_FREE(charAlias);
    return ret;
}


5077
static void
5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092
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:
5093 5094
        virDomainAuditInput(vm, detach->data.input, "detach", success);
        break;
5095
    case VIR_DOMAIN_DEVICE_CHR:
5096 5097
        virDomainAuditChardev(vm, detach->data.chr, NULL, "detach", success);
        break;
5098
    case VIR_DOMAIN_DEVICE_RNG:
5099 5100 5101 5102 5103 5104 5105 5106 5107
        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;
    }
5108
    case VIR_DOMAIN_DEVICE_SHMEM:
5109 5110
        virDomainAuditShmem(vm, detach->data.shmem, "detach", success);
        break;
5111
    case VIR_DOMAIN_DEVICE_REDIRDEV:
5112 5113
        virDomainAuditRedirdev(vm, detach->data.redirdev, "detach", success);
        break;
5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140

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


5141
int
5142 5143 5144 5145
qemuDomainRemoveDevice(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       virDomainDeviceDefPtr dev)
{
5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159
    virDomainDeviceInfoPtr info;
    virObjectEventPtr event;
    VIR_AUTOFREE(char *) alias = NULL;

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

5160
    switch ((virDomainDeviceType)dev->type) {
5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175
    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.
         */
5176
    case VIR_DOMAIN_DEVICE_DISK:
5177 5178
        if (qemuDomainRemoveDiskDevice(driver, vm, dev->data.disk) < 0)
            return -1;
5179 5180
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5181 5182
        if (qemuDomainRemoveControllerDevice(vm, dev->data.controller) < 0)
            return -1;
5183 5184
        break;
    case VIR_DOMAIN_DEVICE_NET:
5185 5186
        if (qemuDomainRemoveNetDevice(driver, vm, dev->data.net) < 0)
            return -1;
5187 5188
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
5189 5190
        if (qemuDomainRemoveHostDevice(driver, vm, dev->data.hostdev) < 0)
            return -1;
5191
        break;
5192
    case VIR_DOMAIN_DEVICE_RNG:
5193 5194
        if (qemuDomainRemoveRNGDevice(driver, vm, dev->data.rng) < 0)
            return -1;
5195
        break;
5196
    case VIR_DOMAIN_DEVICE_MEMORY:
5197 5198
        if (qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory) < 0)
            return -1;
5199
        break;
5200
    case VIR_DOMAIN_DEVICE_SHMEM:
5201 5202
        if (qemuDomainRemoveShmemDevice(driver, vm, dev->data.shmem) < 0)
            return -1;
5203
        break;
5204
    case VIR_DOMAIN_DEVICE_INPUT:
5205 5206
        if (qemuDomainRemoveInputDevice(vm, dev->data.input) < 0)
            return -1;
5207
        break;
5208
    case VIR_DOMAIN_DEVICE_REDIRDEV:
5209 5210
        if (qemuDomainRemoveRedirdevDevice(driver, vm, dev->data.redirdev) < 0)
            return -1;
5211
        break;
5212
    case VIR_DOMAIN_DEVICE_WATCHDOG:
5213 5214
        if (qemuDomainRemoveWatchdog(vm, dev->data.watchdog) < 0)
            return -1;
5215
        break;
J
Ján Tomko 已提交
5216
    case VIR_DOMAIN_DEVICE_VSOCK:
5217 5218
        if (qemuDomainRemoveVsockDevice(vm, dev->data.vsock) < 0)
            return -1;
J
Ján Tomko 已提交
5219 5220
        break;

5221 5222 5223 5224 5225 5226 5227 5228 5229 5230
    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:
5231
    case VIR_DOMAIN_DEVICE_TPM:
5232
    case VIR_DOMAIN_DEVICE_PANIC:
J
Ján Tomko 已提交
5233
    case VIR_DOMAIN_DEVICE_IOMMU:
5234 5235 5236 5237 5238 5239
    case VIR_DOMAIN_DEVICE_LAST:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("don't know how to remove a %s device"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }
5240 5241 5242 5243 5244

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

    return 0;
5245 5246 5247 5248
}


static void
5249 5250
qemuDomainMarkDeviceAliasForRemoval(virDomainObjPtr vm,
                                    const char *alias)
5251 5252 5253
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

5254 5255
    memset(&priv->unplug, 0, sizeof(priv->unplug));

5256
    priv->unplug.alias = alias;
5257 5258
}

5259 5260 5261 5262 5263 5264 5265 5266 5267 5268

static void
qemuDomainMarkDeviceForRemoval(virDomainObjPtr vm,
                               virDomainDeviceInfoPtr info)

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


5269 5270 5271 5272
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
5273
    priv->unplug.alias = NULL;
5274
    priv->unplug.eventSeen = false;
5275 5276 5277
}

/* Returns:
5278 5279
 *  -1 Unplug of the device failed
 *
5280
 *   0 removal of the device did not finish in qemuDomainRemoveDeviceWaitTime
5281 5282 5283 5284
 *
 *   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
5285 5286 5287 5288 5289 5290
 */
static int
qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    unsigned long long until;
5291
    int rc;
5292 5293

    if (virTimeMillisNow(&until) < 0)
5294
        return 1;
5295
    until += qemuDomainRemoveDeviceWaitTime;
5296

5297
    while (priv->unplug.alias) {
5298 5299 5300 5301 5302
        if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
            return 0;

        if (rc < 0) {
            VIR_WARN("Failed to wait on unplug condition for domain '%s' "
5303
                     "device '%s'", vm->def->name, priv->unplug.alias);
5304
            return 1;
5305 5306 5307
        }
    }

5308 5309 5310 5311 5312 5313
    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;
    }

5314 5315 5316
    return 1;
}

5317 5318 5319 5320 5321 5322 5323
/* 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
5324
qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
5325 5326
                              const char *devAlias,
                              qemuDomainUnpluggingDeviceStatus status)
5327 5328 5329
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

5330
    if (STREQ_NULLABLE(priv->unplug.alias, devAlias)) {
5331
        VIR_DEBUG("Removal of device '%s' continues in waiting thread", devAlias);
5332
        qemuDomainResetDeviceRemoval(vm);
5333
        priv->unplug.status = status;
5334
        priv->unplug.eventSeen = true;
5335
        virDomainObjBroadcast(vm);
5336
        return true;
5337
    }
5338
    return false;
5339 5340 5341
}


5342 5343 5344 5345 5346 5347
static int
qemuFindDisk(virDomainDefPtr def, const char *dst)
{
    size_t i;

    for (i = 0; i < def->ndisks; i++) {
5348
        if (STREQ(def->disks[i]->dst, dst))
5349 5350 5351 5352 5353 5354
            return i;
    }

    return -1;
}

5355
static int
5356
qemuDomainDetachPrepDisk(virDomainObjPtr vm,
5357
                         virDomainDiskDefPtr match,
5358
                         virDomainDiskDefPtr *detach)
5359 5360 5361 5362
{
    virDomainDiskDefPtr disk;
    int idx;

5363
    if ((idx = qemuFindDisk(vm->def, match->dst)) < 0) {
5364
        virReportError(VIR_ERR_OPERATION_FAILED,
5365
                       _("disk %s not found"), match->dst);
5366 5367
        return -1;
    }
5368
    *detach = disk = vm->def->disks[idx];
5369

5370
    switch ((virDomainDiskDevice) disk->device) {
5371 5372
    case VIR_DOMAIN_DISK_DEVICE_DISK:
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5373 5374 5375 5376 5377

        switch ((virDomainDiskBus) disk->bus) {
        case VIR_DOMAIN_DISK_BUS_VIRTIO:
        case VIR_DOMAIN_DISK_BUS_USB:
        case VIR_DOMAIN_DISK_BUS_SCSI:
5378
            break;
5379 5380 5381 5382 5383 5384 5385

        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:
5386 5387
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("This type of disk cannot be hot unplugged"));
5388
            return -1;
5389 5390 5391 5392

        case VIR_DOMAIN_DISK_BUS_LAST:
        default:
            virReportEnumRangeError(virDomainDiskBus, disk->bus);
5393
            return -1;
5394
        }
5395
        break;
5396 5397 5398

    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5399 5400 5401
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("disk device type '%s' cannot be detached"),
                       virDomainDiskDeviceTypeToString(disk->device));
5402
        return -1;
5403 5404 5405 5406

    case VIR_DOMAIN_DISK_DEVICE_LAST:
    default:
        virReportEnumRangeError(virDomainDiskDevice, disk->device);
5407
        return -1;
5408 5409
    }

5410 5411 5412
    if (qemuDomainDiskBlockJobIsActive(disk))
        return -1;

5413
    return 0;
5414 5415 5416
}


5417 5418 5419
static bool qemuDomainDiskControllerIsBusy(virDomainObjPtr vm,
                                           virDomainControllerDefPtr detach)
{
5420
    size_t i;
5421
    virDomainDiskDefPtr disk;
5422
    virDomainHostdevDefPtr hostdev;
5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444

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

5445 5446 5447 5448 5449 5450 5451 5452 5453
    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;
    }

5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476
    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;
    }
}

5477
static int
5478
qemuDomainDetachPrepController(virDomainObjPtr vm,
5479
                               virDomainControllerDefPtr match,
5480
                               virDomainControllerDefPtr *detach)
5481
{
5482
    int idx;
5483
    virDomainControllerDefPtr controller = NULL;
5484

5485
    if (match->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
5486 5487
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot unplugged."),
5488
                       virDomainControllerTypeToString(match->type));
5489 5490 5491
        return -1;
    }

5492
    if ((idx = virDomainControllerFind(vm->def, match->type, match->idx)) < 0) {
5493
        virReportError(VIR_ERR_DEVICE_MISSING,
5494
                       _("controller %s:%d not found"),
5495 5496
                       virDomainControllerTypeToString(match->type),
                       match->idx);
5497
        return -1;
5498 5499
    }

5500
    *detach = controller = vm->def->controllers[idx];
5501

5502
    if (qemuDomainControllerIsBusy(vm, controller)) {
5503 5504
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("device cannot be detached: device is busy"));
5505
        return -1;
5506
    }
5507

5508
    return 0;
5509 5510 5511
}


5512
/* search for a hostdev matching dev and detach it */
5513
static int
5514
qemuDomainDetachPrepHostdev(virDomainObjPtr vm,
5515
                            virDomainHostdevDefPtr match,
5516
                            virDomainHostdevDefPtr *detach)
5517
{
5518
    virDomainHostdevSubsysPtr subsys = &match->source.subsys;
5519
    virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb;
5520
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
5521
    virDomainHostdevSubsysSCSIPtr scsisrc = &subsys->u.scsi;
5522
    virDomainHostdevSubsysMediatedDevPtr mdevsrc = &subsys->u.mdev;
5523
    virDomainHostdevDefPtr hostdev = NULL;
5524 5525
    int idx;

5526
    if (match->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
5527
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5528
                       _("hot unplug is not supported for hostdev mode '%s'"),
5529
                       virDomainHostdevModeTypeToString(match->mode));
5530 5531 5532
        return -1;
    }

5533 5534
    idx = virDomainHostdevFind(vm->def, match, &hostdev);
    *detach = hostdev;
5535 5536

    if (idx < 0) {
5537
        switch (subsys->type) {
5538
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
5539
            virReportError(VIR_ERR_DEVICE_MISSING,
5540
                           _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
5541 5542
                           pcisrc->addr.domain, pcisrc->addr.bus,
                           pcisrc->addr.slot, pcisrc->addr.function);
5543 5544
            break;
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
5545
            if (usbsrc->bus && usbsrc->device) {
5546
                virReportError(VIR_ERR_DEVICE_MISSING,
5547
                               _("host usb device %03d.%03d not found"),
5548
                               usbsrc->bus, usbsrc->device);
5549
            } else {
5550
                virReportError(VIR_ERR_DEVICE_MISSING,
5551
                               _("host usb device vendor=0x%.4x product=0x%.4x not found"),
5552
                               usbsrc->vendor, usbsrc->product);
5553 5554
            }
            break;
5555
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
5556 5557 5558
            if (scsisrc->protocol ==
                VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
                virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
5559
                virReportError(VIR_ERR_DEVICE_MISSING,
5560
                               _("host scsi iSCSI path %s not found"),
5561
                               iscsisrc->src->path);
5562 5563 5564
            } else {
                 virDomainHostdevSubsysSCSIHostPtr scsihostsrc =
                     &scsisrc->u.host;
5565
                 virReportError(VIR_ERR_DEVICE_MISSING,
5566
                                _("host scsi device %s:%u:%u.%llu not found"),
5567 5568 5569
                                scsihostsrc->adapter, scsihostsrc->bus,
                                scsihostsrc->target, scsihostsrc->unit);
            }
5570
            break;
5571
        }
5572 5573 5574 5575 5576
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
            virReportError(VIR_ERR_DEVICE_MISSING,
                           _("mediated device '%s' not found"),
                           mdevsrc->uuidstr);
            break;
5577 5578
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
            break;
5579
        default:
5580 5581
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"), subsys->type);
5582 5583 5584 5585 5586
            break;
        }
        return -1;
    }

5587
    return 0;
5588 5589
}

5590

5591
static int
5592
qemuDomainDetachPrepShmem(virDomainObjPtr vm,
5593
                          virDomainShmemDefPtr match,
5594
                          virDomainShmemDefPtr *detach)
5595 5596 5597 5598
{
    ssize_t idx = -1;
    virDomainShmemDefPtr shmem = NULL;

5599
    if ((idx = virDomainShmemDefFind(vm->def, match)) < 0) {
5600
        virReportError(VIR_ERR_DEVICE_MISSING,
5601 5602
                       _("model '%s' shmem device not present "
                         "in domain configuration"),
5603
                       virDomainShmemModelTypeToString(match->model));
5604 5605 5606
        return -1;
    }

5607
    *detach = shmem = vm->def->shmems[idx];
5608 5609 5610 5611 5612 5613 5614 5615 5616 5617

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

    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live detach of shmem model '%s' is not supported"),
                       virDomainShmemModelTypeToString(shmem->model));
M
Marc Hartmayer 已提交
5618
        ATTRIBUTE_FALLTHROUGH;
5619 5620 5621 5622
    case VIR_DOMAIN_SHMEM_MODEL_LAST:
        return -1;
    }

5623
    return 0;
5624 5625 5626
}


5627
static int
5628
qemuDomainDetachPrepWatchdog(virDomainObjPtr vm,
5629
                             virDomainWatchdogDefPtr match,
5630
                             virDomainWatchdogDefPtr *detach)
M
Michal Privoznik 已提交
5631
{
5632 5633 5634
    virDomainWatchdogDefPtr watchdog;

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

5636 5637 5638 5639 5640 5641
    if (!watchdog) {
        virReportError(VIR_ERR_DEVICE_MISSING, "%s",
                       _("watchdog device not present in domain configuration"));
        return -1;
    }

M
Michal Privoznik 已提交
5642 5643 5644
    /* 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. */
5645 5646 5647
    if (!(watchdog->model == match->model &&
          watchdog->action == match->action &&
          virDomainDeviceInfoAddressIsEqual(&match->info, &watchdog->info))) {
5648
        virReportError(VIR_ERR_DEVICE_MISSING,
5649 5650 5651
                       _("model '%s' watchdog device not present "
                         "in domain configuration"),
                       virDomainWatchdogModelTypeToString(watchdog->model));
M
Michal Privoznik 已提交
5652 5653 5654 5655 5656 5657 5658 5659 5660 5661
        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;
    }

5662
    return 0;
M
Michal Privoznik 已提交
5663 5664 5665
}


5666
static int
5667
qemuDomainDetachPrepRedirdev(virDomainObjPtr vm,
5668
                             virDomainRedirdevDefPtr match,
5669
                             virDomainRedirdevDefPtr *detach)
5670
{
5671
    virDomainRedirdevDefPtr redirdev;
5672 5673
    ssize_t idx;

5674
    if ((idx = virDomainRedirdevDefFind(vm->def, match)) < 0) {
5675 5676 5677 5678 5679
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("no matching redirdev was not found"));
        return -1;
    }

5680
    *detach = redirdev = vm->def->redirdevs[idx];
5681

5682
    return 0;
5683 5684 5685
}


5686
static int
5687
qemuDomainDetachPrepNet(virDomainObjPtr vm,
5688
                        virDomainNetDefPtr match,
5689
                        virDomainNetDefPtr *detach)
5690
{
5691
    int detachidx;
5692
    virDomainNetDefPtr net = NULL;
5693

5694
    if ((detachidx = virDomainNetFindIdx(vm->def, match)) < 0)
5695
        return -1;
5696

5697
    *detach = net = vm->def->nets[detachidx];
5698

5699 5700
    return 0;
}
5701

5702

5703
static int
5704
qemuDomainDetachDeviceChr(virQEMUDriverPtr driver,
5705 5706 5707
                          virDomainObjPtr vm,
                          virDomainChrDefPtr chr,
                          bool async)
5708 5709 5710 5711 5712
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDefPtr vmdef = vm->def;
    virDomainChrDefPtr tmpChr;
5713
    bool guestfwd = false;
5714 5715

    if (!(tmpChr = virDomainChrFind(vmdef, chr))) {
5716
        virReportError(VIR_ERR_DEVICE_MISSING,
5717 5718 5719
                       _("chr type '%s' device not present "
                         "in domain configuration"),
                       virDomainChrDeviceTypeToString(chr->deviceType));
5720
        goto cleanup;
5721 5722
    }

5723 5724 5725 5726 5727 5728
    /* 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)
5729
        qemuDomainMarkDeviceForRemoval(vm, &tmpChr->info);
5730

5731
    if (guestfwd) {
5732 5733 5734 5735 5736 5737 5738
        int rc;
        qemuDomainObjEnterMonitor(driver, vm);
        rc = qemuMonitorRemoveNetdev(priv->mon, tmpChr->info.alias);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            rc = -1;

        if (rc < 0)
5739 5740
            goto cleanup;
    } else {
5741
        if (qemuDomainDeleteDevice(vm, tmpChr->info.alias) < 0)
5742
            goto cleanup;
5743
    }
5744

5745 5746 5747
    if (guestfwd) {
        ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr, false);
    } else if (async) {
5748 5749 5750
        ret = 0;
    } else {
        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
5751
            ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr, true);
5752
    }
5753

5754
 cleanup:
5755 5756
    if (!async)
        qemuDomainResetDeviceRemoval(vm);
5757 5758
    return ret;
}
5759 5760


5761
static int
5762
qemuDomainDetachPrepRNG(virDomainObjPtr vm,
5763
                        virDomainRNGDefPtr match,
5764
                        virDomainRNGDefPtr *detach)
5765 5766
{
    ssize_t idx;
5767
    virDomainRNGDefPtr rng;
5768

5769
    if ((idx = virDomainRNGFind(vm->def, match)) < 0) {
5770
        virReportError(VIR_ERR_DEVICE_MISSING,
5771 5772
                       _("model '%s' RNG device not present "
                         "in domain configuration"),
5773
                       virDomainRNGBackendTypeToString(match->model));
5774 5775 5776
        return -1;
    }

5777
    *detach = rng = vm->def->rngs[idx];
5778

5779
    return 0;
5780
}
5781 5782


5783
static int
5784
qemuDomainDetachPrepMemory(virDomainObjPtr vm,
5785
                           virDomainMemoryDefPtr match,
5786
                           virDomainMemoryDefPtr *detach)
5787 5788 5789 5790
{
    virDomainMemoryDefPtr mem;
    int idx;

5791
    qemuDomainMemoryDeviceAlignSize(vm->def, match);
5792

5793
    if ((idx = virDomainMemoryFindByDef(vm->def, match)) < 0) {
5794
        virReportError(VIR_ERR_DEVICE_MISSING,
5795 5796
                       _("model '%s' memory device not present "
                         "in the domain configuration"),
5797
                       virDomainMemoryModelTypeToString(match->model));
5798 5799 5800
        return -1;
    }

5801
    *detach = mem = vm->def->mems[idx];
5802

5803
    return 0;
5804
}
5805 5806


5807
static int
5808 5809
qemuDomainDetachPrepInput(virDomainObjPtr vm,
                          virDomainInputDefPtr match,
5810
                          virDomainInputDefPtr *detach)
5811 5812 5813 5814
{
    virDomainInputDefPtr input;
    int idx;

5815
    if ((idx = virDomainInputDefFind(vm->def, match)) < 0) {
5816 5817 5818 5819
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("matching input device not found"));
        return -1;
    }
5820
    *detach = input = vm->def->inputs[idx];
5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836

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

5837
    return 0;
5838 5839 5840
}


5841
static int
5842 5843
qemuDomainDetachPrepVsock(virDomainObjPtr vm,
                          virDomainVsockDefPtr match,
5844
                          virDomainVsockDefPtr *detach)
5845
{
5846
    virDomainVsockDefPtr vsock;
5847

5848
    *detach = vsock = vm->def->vsock;
5849
    if (!vsock ||
5850
        !virDomainVsockDefEquals(match, vsock)) {
5851 5852 5853 5854 5855
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("matching vsock device not found"));
        return -1;
    }

5856
    return 0;
5857 5858 5859
}


5860
static int
5861 5862 5863
qemuDomainDetachDeviceLease(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainLeaseDefPtr lease)
5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883
{
    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;
}


5884 5885
int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
5886
                           virDomainDeviceDefPtr match,
5887 5888 5889
                           virQEMUDriverPtr driver,
                           bool async)
{
5890
    virDomainDeviceDef detach = { .type = match->type };
5891
    virDomainDeviceInfoPtr info = NULL;
5892 5893
    int ret = -1;

5894
    switch ((virDomainDeviceType)match->type) {
5895 5896 5897 5898 5899 5900
        /*
         * 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:
5901
        return qemuDomainDetachDeviceLease(driver, vm, match->data.lease);
5902 5903

    case VIR_DOMAIN_DEVICE_CHR:
5904
        return qemuDomainDetachDeviceChr(driver, vm, match->data.chr, async);
5905 5906 5907 5908 5909 5910 5911 5912

        /*
         * 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.
         */
5913
    case VIR_DOMAIN_DEVICE_DISK:
5914 5915
        if (qemuDomainDetachPrepDisk(vm, match->data.disk,
                                     &detach.data.disk) < 0) {
5916 5917
            return -1;
        }
5918 5919
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5920 5921
        if (qemuDomainDetachPrepController(vm, match->data.controller,
                                           &detach.data.controller) < 0) {
5922 5923
            return -1;
        }
5924 5925
        break;
    case VIR_DOMAIN_DEVICE_NET:
5926 5927
        if (qemuDomainDetachPrepNet(vm, match->data.net,
                                    &detach.data.net) < 0) {
5928 5929
            return -1;
        }
5930 5931
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
5932 5933
        if (qemuDomainDetachPrepHostdev(vm, match->data.hostdev,
                                        &detach.data.hostdev) < 0) {
5934 5935
            return -1;
        }
5936 5937
        break;
    case VIR_DOMAIN_DEVICE_RNG:
5938 5939
        if (qemuDomainDetachPrepRNG(vm, match->data.rng,
                                    &detach.data.rng) < 0) {
5940 5941
            return -1;
        }
5942 5943
        break;
    case VIR_DOMAIN_DEVICE_MEMORY:
5944 5945
        if (qemuDomainDetachPrepMemory(vm, match->data.memory,
                                       &detach.data.memory) < 0) {
5946 5947
            return -1;
        }
5948 5949
        break;
    case VIR_DOMAIN_DEVICE_SHMEM:
5950 5951
        if (qemuDomainDetachPrepShmem(vm, match->data.shmem,
                                      &detach.data.shmem) < 0) {
5952 5953
            return -1;
        }
5954 5955
        break;
    case VIR_DOMAIN_DEVICE_WATCHDOG:
5956 5957
        if (qemuDomainDetachPrepWatchdog(vm, match->data.watchdog,
                                         &detach.data.watchdog) < 0) {
5958 5959
            return -1;
        }
5960 5961
        break;
    case VIR_DOMAIN_DEVICE_INPUT:
5962
        if (qemuDomainDetachPrepInput(vm, match->data.input,
5963
                                      &detach.data.input) < 0) {
5964 5965
            return -1;
        }
5966 5967
        break;
    case VIR_DOMAIN_DEVICE_REDIRDEV:
5968 5969
        if (qemuDomainDetachPrepRedirdev(vm, match->data.redirdev,
                                         &detach.data.redirdev) < 0) {
5970 5971
            return -1;
        }
5972 5973
        break;
    case VIR_DOMAIN_DEVICE_VSOCK:
5974
        if (qemuDomainDetachPrepVsock(vm, match->data.vsock,
5975
                                      &detach.data.vsock) < 0) {
5976 5977
            return -1;
        }
5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994
        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"),
5995
                       virDomainDeviceTypeToString(match->type));
5996
        return -1;
5997 5998
    }

5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056
    /* "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: "
                         "%.4x:%.2x:%.2x.%.1x"),
                       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);
6057

6058 6059 6060 6061
    return ret;
}


6062 6063 6064 6065 6066 6067 6068 6069 6070 6071
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;
6072
    virErrorPtr save_error = NULL;
6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096
    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);

6097 6098 6099 6100 6101 6102
    virErrorPreserveLast(&save_error);

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

    virErrorRestore(&save_error);
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

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


6129
static int
6130
qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
6131
                         virQEMUDriverConfigPtr cfg,
6132 6133 6134 6135 6136 6137 6138 6139
                         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;
6140
    int ret = -1;
6141 6142 6143 6144 6145 6146 6147 6148 6149

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

    qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias);

6150 6151 6152
    if (qemuDomainDeleteDevice(vm, vcpupriv->alias) < 0) {
        if (virDomainObjIsActive(vm))
            virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
6153
        goto cleanup;
6154 6155 6156 6157 6158 6159 6160
    }

    if ((rc = qemuDomainWaitForDeviceRemoval(vm)) <= 0) {
        if (rc == 0)
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("vcpu unplug request timed out"));

6161
        goto cleanup;
6162 6163
    }

6164 6165 6166
    if (qemuDomainRemoveVcpu(driver, vm, vcpu) < 0)
        goto cleanup;

6167 6168 6169 6170 6171
    qemuDomainVcpuPersistOrder(vm->def);

    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
        goto cleanup;

6172 6173 6174 6175 6176
    ret = 0;

 cleanup:
    qemuDomainResetDeviceRemoval(vm);
    return ret;
6177
}
6178 6179 6180 6181


static int
qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
6182
                         virQEMUDriverConfigPtr cfg,
6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242
                         virDomainObjPtr vm,
                         unsigned int vcpu)
{
    virJSONValuePtr vcpuprops = NULL;
    virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu);
    qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);
    unsigned int nvcpus = vcpupriv->vcpus;
    bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm);
    int ret = -1;
    int rc;
    int oldvcpus = virDomainDefGetVcpus(vm->def);
    size_t i;

    if (newhotplug) {
        if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0)
            goto cleanup;

        if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo)))
            goto cleanup;
    }

    qemuDomainObjEnterMonitor(driver, vm);

    if (newhotplug) {
        rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops);
        vcpuprops = NULL;
    } else {
        rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true);
    }

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

    virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0);

    if (rc < 0)
        goto cleanup;

    /* start outputting of the new XML element to allow keeping unpluggability */
    if (newhotplug)
        vm->def->individualvcpus = true;

    if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0)
        goto cleanup;

    /* validation requires us to set the expected state prior to calling it */
    for (i = vcpu; i < vcpu + nvcpus; i++) {
        vcpuinfo = virDomainDefGetVcpu(vm->def, i);
        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo);

        vcpuinfo->online = true;

        if (vcpupriv->tid > 0 &&
            qemuProcessSetupVcpu(vm, i) < 0)
            goto cleanup;
    }

    if (qemuDomainValidateVcpuInfo(vm) < 0)
        goto cleanup;

6243 6244 6245 6246 6247
    qemuDomainVcpuPersistOrder(vm->def);

    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
        goto cleanup;

6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368
    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) {
6369 6370
            if (qemuDomainHotplugAddVcpu(driver, cfg, vm, nextvcpu) < 0)
                goto cleanup;
6371 6372 6373 6374 6375 6376
        }
    } else {
        for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) {
            if (!virBitmapIsBitSet(vcpumap, nextvcpu))
                continue;

6377 6378
            if (qemuDomainHotplugDelVcpu(driver, cfg, vm, nextvcpu) < 0)
                goto cleanup;
6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423
        }
    }

    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) {
6424
                /* non-hotpluggable vcpus need to be clustered at the beginning,
6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469
                 * 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)
{
6470
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512
    virBitmapPtr vcpumap = NULL;
    bool enable;
    int ret = -1;

    if (def && nvcpus > virDomainDefGetVcpusMax(def)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the live domain: %u > %u"),
                       nvcpus, virDomainDefGetVcpusMax(def));
        goto cleanup;
    }

    if (persistentDef && nvcpus > virDomainDefGetVcpusMax(persistentDef)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the persistent domain: %u > %u"),
                       nvcpus, virDomainDefGetVcpusMax(persistentDef));
        goto cleanup;
    }

    if (def) {
        if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus,
                                                            &enable)))
            goto cleanup;

        if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0)
            goto cleanup;
    }

    if (persistentDef) {
        qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable);

        if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;

 cleanup:
    virBitmapFree(vcpumap);
    return ret;
}
6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524


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

    def->individualvcpus = true;

6525 6526 6527
    /* ordering information may become invalid, thus clear it */
    virDomainDefVcpuOrderClear(def);

6528
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559
        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 */
6560
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6561 6562 6563 6564 6565
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        if (vcpu->online == state) {
            virReportError(VIR_ERR_INVALID_ARG,
6566
                           _("vcpu '%zd' is already in requested state"), next);
6567 6568 6569 6570 6571
            goto cleanup;
        }

        if (vcpu->online && !vcpu->hotpluggable) {
            virReportError(VIR_ERR_INVALID_ARG,
6572
                           _("vcpu '%zd' can't be hotunplugged"), next);
6573 6574 6575 6576 6577 6578 6579
            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;
6580
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
6581 6582 6583 6584 6585 6586 6587
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);

        if (vcpupriv->vcpus == 0) {
            virReportError(VIR_ERR_INVALID_ARG,
6588
                           _("vcpu '%zd' belongs to a larger hotpluggable entity, "
6589 6590 6591 6592 6593 6594 6595 6596
                             "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 "
6597
                                 "hotpluggable entity '%zd-%zd' which was "
6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615
                                 "partially selected"),
                               i, next, next + vcpupriv->vcpus - 1);
                goto cleanup;
            }

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

    VIR_STEAL_PTR(ret, map);

 cleanup:
    virBitmapFree(map);
    return ret;
}


6616
static int
6617
qemuDomainVcpuValidateConfig(virDomainDefPtr def,
6618
                             virBitmapPtr map)
6619
{
6620 6621 6622
    virDomainVcpuDefPtr vcpu;
    size_t maxvcpus = virDomainDefGetVcpusMax(def);
    ssize_t next;
6623
    ssize_t firstvcpu = -1;
6624

6625 6626
    /* vcpu 0 can't be modified */
    if (virBitmapIsBitSet(map, 0)) {
6627
        virReportError(VIR_ERR_INVALID_ARG, "%s",
6628
                       _("vCPU '0' can't be modified"));
6629 6630 6631
        return -1;
    }

6632 6633 6634 6635 6636 6637
    /* 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 */
6638 6639 6640 6641
        if (virBitmapIsBitSet(map, next)) {
            if (firstvcpu < 0)
                firstvcpu = next;

6642
            continue;
6643
        }
6644 6645 6646 6647

        if (vcpu->online && vcpu->hotpluggable == VIR_TRISTATE_BOOL_NO) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("vcpu '%zd' can't be modified as it is followed "
6648
                             "by non-hotpluggable online vcpus"), firstvcpu);
6649 6650 6651 6652
            return -1;
        }
    }

6653 6654 6655 6656
    return 0;
}


6657 6658 6659 6660 6661 6662 6663 6664
int
qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainDefPtr def,
                          virDomainDefPtr persistentDef,
                          virBitmapPtr map,
                          bool state)
{
6665
    VIR_AUTOUNREF(virQEMUDriverConfigPtr) cfg = virQEMUDriverGetConfig(driver);
6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690
    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;
        }
    }

6691
    if (persistentDef) {
6692
        if (qemuDomainVcpuValidateConfig(persistentDef, map) < 0)
6693 6694 6695
            goto cleanup;
    }

6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712
    if (livevcpus &&
        qemuDomainSetVcpusLive(driver, cfg, vm, livevcpus, state) < 0)
        goto cleanup;

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

        if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;

 cleanup:
    virBitmapFree(livevcpus);
    return ret;
}