qemu_hotplug.c 197.8 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 26 27
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */


#include <config.h>

#include "qemu_hotplug.h"
28
#include "qemu_hotplugpriv.h"
29
#include "qemu_alias.h"
30 31
#include "qemu_capabilities.h"
#include "qemu_domain.h"
32
#include "qemu_domain_address.h"
33 34
#include "qemu_command.h"
#include "qemu_hostdev.h"
35
#include "qemu_interface.h"
36
#include "qemu_process.h"
37
#include "qemu_security.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
#include "network/bridge_driver.h"
51 52
#include "virnetdev.h"
#include "virnetdevbridge.h"
A
Ansis Atteka 已提交
53
#include "virnetdevtap.h"
54
#include "virnetdevopenvswitch.h"
55
#include "virnetdevmidonet.h"
56
#include "device_conf.h"
57
#include "virstoragefile.h"
58
#include "virstring.h"
59
#include "virtime.h"
60
#include "storage/storage_driver.h"
61 62

#define VIR_FROM_THIS VIR_FROM_QEMU
63 64 65

VIR_LOG_INIT("qemu.qemu_hotplug");

66
#define CHANGE_MEDIA_TIMEOUT 5000
67

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


72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/**
 * qemuDomainPrepareDisk:
 * @driver: qemu driver struct
 * @vm: domain object
 * @disk: disk to prepare
 * @overridesrc: Source different than @disk->src when necessary
 * @teardown: Teardown the disk instead of adding it to a vm
 *
 * Setup the locks, cgroups and security permissions on a disk of a VM.
 * If @overridesrc is specified the source struct is used instead of the
 * one present in @disk. If @teardown is true, then the labels and cgroups
 * are removed instead.
 *
 * Returns 0 on success and -1 on error. Reports libvirt error.
 */
static int
qemuDomainPrepareDisk(virQEMUDriverPtr driver,
                      virDomainObjPtr vm,
                      virDomainDiskDefPtr disk,
                      virStorageSourcePtr overridesrc,
                      bool teardown)
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    int ret = -1;
    virStorageSourcePtr origsrc = NULL;
97
    virErrorPtr orig_err = NULL;
98 99 100 101 102 103 104 105

    if (overridesrc) {
        origsrc = disk->src;
        disk->src = overridesrc;
    }

    /* just tear down the disk access */
    if (teardown) {
106
        virErrorPreserveLast(&orig_err);
107 108 109 110 111 112 113 114
        ret = 0;
        goto rollback_cgroup;
    }

    if (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
                                vm, disk) < 0)
        goto cleanup;

115
    if (qemuDomainNamespaceSetupDisk(driver, vm, disk->src) < 0)
116 117
        goto rollback_lock;

118 119
    if (qemuSecuritySetDiskLabel(driver, vm, disk) < 0)
        goto rollback_namespace;
120

121
    if (qemuSetupDiskCgroup(vm, disk) < 0)
122
        goto rollback_label;
123

124 125 126 127 128 129 130 131
    ret = 0;
    goto cleanup;

 rollback_cgroup:
    if (qemuTeardownDiskCgroup(vm, disk) < 0)
        VIR_WARN("Unable to tear down cgroup access on %s",
                 virDomainDiskGetSource(disk));
 rollback_label:
132
    if (qemuSecurityRestoreDiskLabel(driver, vm, disk) < 0)
133 134 135
        VIR_WARN("Unable to restore security label on %s",
                 virDomainDiskGetSource(disk));

136
 rollback_namespace:
137
    if (qemuDomainNamespaceTeardownDisk(driver, vm, disk->src) < 0)
138 139 140
        VIR_WARN("Unable to remove /dev entry for %s",
                 virDomainDiskGetSource(disk));

141 142 143 144 145 146 147 148 149
 rollback_lock:
    if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
        VIR_WARN("Unable to release lock on %s",
                 virDomainDiskGetSource(disk));

 cleanup:
    if (origsrc)
        disk->src = origsrc;

150 151
    virErrorRestore(&orig_err);

152 153 154 155 156 157
    virObjectUnref(cfg);

    return ret;
}


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
static int
qemuDomainAddDiskSrcTLSObject(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              virStorageSourcePtr src,
                              const char *srcalias)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virJSONValuePtr tlsProps = NULL;

    if (qemuDomainGetTLSObjects(priv->qemuCaps, NULL,
                                src->tlsCertdir,
                                false,
                                src->tlsVerify,
                                srcalias, &tlsProps, &src->tlsAlias,
                                NULL, NULL) < 0)
        goto cleanup;

    if (qemuDomainAddTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                                NULL, NULL, src->tlsAlias, &tlsProps) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    virJSONValueFree(tlsProps);

    return ret;
}


static void
qemuDomainDelDiskSrcTLSObject(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              virStorageSourcePtr src)
{
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE, NULL, src->tlsAlias);
}


198 199 200 201
static int
qemuHotplugWaitForTrayEject(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainDiskDefPtr disk,
202
                            const char *driveAlias)
203 204 205 206 207 208 209 210 211 212 213 214
{
    unsigned long long now;
    int rc;

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

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

        if (rc > 0) {
215 216 217 218 219 220
            /* the caller called qemuMonitorEjectMedia which usually reports an
             * error. Report the failure in an off-chance that it didn't. */
            if (!virGetLastError()) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("timed out waiting for disk tray status update"));
            }
221 222 223 224 225 226
            return -1;
        }
    }

    /* re-issue ejection command to pop out the media */
    qemuDomainObjEnterMonitor(driver, vm);
227
    rc = qemuMonitorEjectMedia(qemuDomainGetMonitor(vm), driveAlias, false);
228 229 230 231 232 233 234
    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
        return -1;

    return 0;
}


235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
/**
 * 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
 */
int
qemuDomainChangeEjectableMedia(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainDiskDefPtr disk,
                               virStorageSourcePtr newsrc,
                               bool force)
256
{
257
    int ret = -1, rc;
258
    char *driveAlias = NULL;
259
    qemuDomainObjPrivatePtr priv = vm->privateData;
260
    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
261
    const char *format = NULL;
262
    char *sourcestr = NULL;
263

264
    if (!disk->info.alias) {
265
        virReportError(VIR_ERR_INTERNAL_ERROR,
266
                       _("missing disk device alias name for %s"), disk->dst);
267
        goto cleanup;
268 269
    }

270 271
    if (disk->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
        disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
272 273
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Removable media not supported for %s device"),
274
                       virDomainDiskDeviceTypeToString(disk->device));
275
        goto cleanup;
276 277
    }

278
    if (qemuDomainPrepareDisk(driver, vm, disk, newsrc, false) < 0)
279
        goto cleanup;
280

281
    if (!(driveAlias = qemuAliasFromDisk(disk)))
282 283
        goto error;

284 285 286 287
    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorEjectMedia(priv->mon, driveAlias, force);
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
288

289
    /* If the tray is present and tray change event is supported wait for it to open. */
290
    if (!force && diskPriv->tray &&
291
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_TRAY_MOVED)) {
292
        rc = qemuHotplugWaitForTrayEject(driver, vm, disk, driveAlias);
293
        if (rc < 0)
294
            goto error;
295 296 297 298 299
    } else  {
        /* otherwise report possible errors from the attempt to eject the media*/
        if (rc < 0)
            goto error;
    }
300

301
    if (!virStorageSourceIsEmpty(newsrc)) {
302
        if (qemuGetDriveSourceString(newsrc, diskPriv->secinfo, &sourcestr) < 0)
303 304
            goto error;

305 306 307
        if (virStorageSourceGetActualType(newsrc) != VIR_STORAGE_TYPE_DIR) {
            if (newsrc->format > 0) {
                format = virStorageFileFormatTypeToString(newsrc->format);
308
            } else {
309 310
                if (disk->src->format > 0)
                    format = virStorageFileFormatTypeToString(disk->src->format);
311
            }
312
        }
313
        qemuDomainObjEnterMonitor(driver, vm);
314 315 316 317 318
        rc = qemuMonitorChangeMedia(priv->mon,
                                    driveAlias,
                                    sourcestr,
                                    format);
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
319
            goto cleanup;
320
    }
321

322
    virDomainAuditDisk(vm, disk->src, newsrc, "update", rc >= 0);
323

324
    if (rc < 0)
325 326
        goto error;

327 328
    /* remove the old source from shared device list */
    ignore_value(qemuRemoveSharedDisk(driver, disk, vm->def->name));
329
    ignore_value(qemuDomainPrepareDisk(driver, vm, disk, NULL, true));
330

331 332 333
    virStorageSourceFree(disk->src);
    disk->src = newsrc;
    newsrc = NULL;
334
    ret = 0;
335

336
 cleanup:
337
    VIR_FREE(driveAlias);
338
    VIR_FREE(sourcestr);
339 340
    return ret;

341
 error:
342 343
    virDomainAuditDisk(vm, disk->src, newsrc, "update", false);
    ignore_value(qemuDomainPrepareDisk(driver, vm, disk, newsrc, true));
344
    goto cleanup;
345 346
}

347

348 349 350 351 352
static int
qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
                                 virQEMUDriverPtr driver,
                                 virDomainObjPtr vm,
                                 virDomainDiskDefPtr disk)
353
{
354
    int ret = -1;
355
    int rv;
356
    qemuDomainObjPrivatePtr priv = vm->privateData;
357
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_DISK, { .disk = disk } };
358
    virErrorPtr orig_err;
359 360
    char *devstr = NULL;
    char *drivestr = NULL;
361
    char *drivealias = NULL;
362
    bool releaseaddr = false;
363
    bool driveAdded = false;
364
    bool secobjAdded = false;
365
    bool encobjAdded = false;
366
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
367
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
368
    const char *src = virDomainDiskGetSource(disk);
369
    virJSONValuePtr secobjProps = NULL;
370
    virJSONValuePtr encobjProps = NULL;
371 372
    qemuDomainDiskPrivatePtr diskPriv;
    qemuDomainSecretInfoPtr secinfo;
373
    qemuDomainSecretInfoPtr encinfo;
374

375
    if (!disk->info.type) {
376
        if (qemuDomainIsS390CCW(vm->def) &&
377 378 379 380
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW))
            disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
        else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390))
            disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390;
381 382 383 384
    } else {
        if (!qemuCheckCCWS390AddressSupport(vm->def, disk->info, priv->qemuCaps,
                                            disk->dst))
            goto cleanup;
385 386
    }

387
    if (qemuDomainPrepareDisk(driver, vm, disk, NULL, false) < 0)
388
        goto cleanup;
389

390
    if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
391 392 393
        if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
            goto error;
        if (virDomainCCWAddressAssign(&disk->info, ccwaddrs,
394
                                      !disk->info.addr.ccw.assigned) < 0)
395
            goto error;
396 397
    } else if (!disk->info.type ||
                disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
398
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
399
            goto error;
400 401 402 403
    }
    releaseaddr = true;
    if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
        goto error;
404

J
John Ferlan 已提交
405
    if (qemuDomainSecretDiskPrepare(conn, priv, disk) < 0)
406 407
        goto error;

408 409 410 411 412 413 414
    diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
    secinfo = diskPriv->secinfo;
    if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
        if (qemuBuildSecretInfoProps(secinfo, &secobjProps) < 0)
            goto error;
    }

415 416 417 418
    encinfo = diskPriv->encinfo;
    if (encinfo && qemuBuildSecretInfoProps(encinfo, &encobjProps) < 0)
        goto error;

419 420 421 422 423 424 425 426
    if (qemuDomainPrepareDiskSourceTLS(disk->src, disk->info.alias, cfg) < 0)
        goto error;

    if (disk->src->haveTLS &&
        qemuDomainAddDiskSrcTLSObject(driver, vm, disk->src,
                                      disk->info.alias) < 0)
        goto error;

427
    if (!(drivestr = qemuBuildDriveStr(disk, cfg, false, priv->qemuCaps)))
428
        goto error;
429

430
    if (!(drivealias = qemuAliasFromDisk(disk)))
431 432 433 434
        goto error;

    if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
        goto error;
435

436
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
437 438
        goto error;

439
    qemuDomainObjEnterMonitor(driver, vm);
440

441 442 443 444 445
    if (secobjProps) {
        rv = qemuMonitorAddObject(priv->mon, "secret", secinfo->s.aes.alias,
                                  secobjProps);
        secobjProps = NULL; /* qemuMonitorAddObject consumes */
        if (rv < 0)
446
            goto exit_monitor;
447
        secobjAdded = true;
448 449
    }

450 451 452 453 454 455
    if (encobjProps) {
        rv = qemuMonitorAddObject(priv->mon, "secret", encinfo->s.aes.alias,
                                  encobjProps);
        encobjProps = NULL; /* qemuMonitorAddObject consumes */
        if (rv < 0)
            goto exit_monitor;
456
        encobjAdded = true;
457 458
    }

459
    if (qemuMonitorAddDrive(priv->mon, drivestr) < 0)
460 461
        goto exit_monitor;
    driveAdded = true;
462 463

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
464
        goto exit_monitor;
465

466 467
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseaddr = false;
468
        goto error;
469
    }
470

471
    virDomainAuditDisk(vm, NULL, disk->src, "attach", true);
472 473

    virDomainDiskInsertPreAlloced(vm->def, disk);
474
    ret = 0;
475

476
 cleanup:
477
    virJSONValueFree(secobjProps);
478
    virJSONValueFree(encobjProps);
479
    qemuDomainSecretDiskDestroy(disk);
480
    virDomainCCWAddressSetFree(ccwaddrs);
481 482
    VIR_FREE(devstr);
    VIR_FREE(drivestr);
483
    VIR_FREE(drivealias);
484 485
    virObjectUnref(cfg);
    return ret;
486

487
 exit_monitor:
488
    virErrorPreserveLast(&orig_err);
489
    if (driveAdded && qemuMonitorDriveDel(priv->mon, drivealias) < 0) {
490 491 492
        VIR_WARN("Unable to remove drive %s (%s) after failed "
                 "qemuMonitorAddDevice", drivealias, drivestr);
    }
493 494
    if (secobjAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, secinfo->s.aes.alias));
495 496
    if (encobjAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias));
497 498
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        releaseaddr = false;
499
    virErrorRestore(&orig_err);
500 501 502

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

503
 error:
504 505
    qemuDomainDelDiskSrcTLSObject(driver, vm, disk->src);

506
    if (releaseaddr)
507
        qemuDomainReleaseDeviceAddress(vm, &disk->info, src);
508

509
    ignore_value(qemuDomainPrepareDisk(driver, vm, disk, NULL, true));
510
    goto cleanup;
511 512 513
}


514 515 516
int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
                                     virDomainObjPtr vm,
                                     virDomainControllerDefPtr controller)
517 518 519 520 521
{
    int ret = -1;
    const char* type = virDomainControllerTypeToString(controller->type);
    char *devstr = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
522 523
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CONTROLLER,
                               { .controller = controller } };
524
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
525
    bool releaseaddr = false;
526

527 528 529 530 531 532 533
    if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
                       virDomainControllerTypeToString(controller->type));
        return -1;
    }

534 535 536 537 538 539 540 541
    /* 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);

542
    if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) {
543 544 545 546
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target %s:%d already exists"),
                       type, controller->idx);
        return -1;
547 548
    }

549
    if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
550
        if (qemuDomainIsS390CCW(vm->def) &&
551 552 553 554 555 556 557
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW))
            controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
        else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390))
            controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390;
    } else {
        if (!qemuCheckCCWS390AddressSupport(vm->def, controller->info,
                                            priv->qemuCaps, "controller"))
558
            goto cleanup;
559
    }
560

561 562
    if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
        controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
563
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
564 565
            goto cleanup;
    } else if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
566 567 568
        if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
            goto cleanup;
        if (virDomainCCWAddressAssign(&controller->info, ccwaddrs,
569
                                      !controller->info.addr.ccw.assigned) < 0)
570 571
            goto cleanup;
    }
572 573 574 575
    releaseaddr = true;
    if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, controller) < 0)
        goto cleanup;

576 577 578 579
    if (qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, &devstr, NULL) < 0)
        goto cleanup;

    if (!devstr)
580
        goto cleanup;
581

582
    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0)
583 584
        goto cleanup;

585
    qemuDomainObjEnterMonitor(driver, vm);
586
    ret = qemuMonitorAddDevice(priv->mon, devstr);
587 588 589 590 591
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        releaseaddr = false;
        ret = -1;
        goto cleanup;
    }
592 593

    if (ret == 0) {
594 595
        if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
            controller->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
596 597 598
        virDomainControllerInsertPreAlloced(vm->def, controller);
    }

599
 cleanup:
600 601
    if (ret != 0 && releaseaddr)
        qemuDomainReleaseDeviceAddress(vm, &controller->info, NULL);
602 603

    VIR_FREE(devstr);
604
    virDomainCCWAddressSetFree(ccwaddrs);
605 606 607 608
    return ret;
}

static virDomainControllerDefPtr
609
qemuDomainFindOrCreateSCSIDiskController(virQEMUDriverPtr driver,
610
                                         virDomainObjPtr vm,
611
                                         int controller)
612
{
613
    size_t i;
614
    virDomainControllerDefPtr cont;
615

616
    for (i = 0; i < vm->def->ncontrollers; i++) {
617 618 619 620 621 622 623 624 625 626 627
        cont = vm->def->controllers[i];

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

        if (cont->idx == controller)
            return cont;
    }

    /* No SCSI controller present, for backward compatibility we
     * now hotplug a controller */
628
    if (VIR_ALLOC(cont) < 0)
629 630
        return NULL;
    cont->type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
631
    cont->idx = controller;
632 633
    cont->model = -1;

634
    VIR_INFO("No SCSI controller present, hotplugging one");
635 636
    if (qemuDomainAttachControllerDevice(driver,
                                         vm, cont) < 0) {
637 638 639 640 641
        VIR_FREE(cont);
        return NULL;
    }

    if (!virDomainObjIsActive(vm)) {
642 643
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit"));
644 645 646 647 648 649 650 651 652
        /* cont doesn't need freeing here, since the reference
         * now held in def->controllers */
        return NULL;
    }

    return cont;
}


653 654 655 656 657
static int
qemuDomainAttachSCSIDisk(virConnectPtr conn,
                         virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         virDomainDiskDefPtr disk)
658
{
659
    size_t i;
660
    qemuDomainObjPrivatePtr priv = vm->privateData;
661
    virErrorPtr orig_err;
662 663
    char *drivestr = NULL;
    char *devstr = NULL;
664
    bool driveAdded = false;
665
    bool encobjAdded = false;
666
    bool secobjAdded = false;
667
    char *drivealias = NULL;
668
    int ret = -1;
669
    int rv;
670
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
671
    virJSONValuePtr encobjProps = NULL;
672
    virJSONValuePtr secobjProps = NULL;
673 674
    qemuDomainDiskPrivatePtr diskPriv;
    qemuDomainSecretInfoPtr encinfo;
675
    qemuDomainSecretInfoPtr secinfo;
676

677
    if (qemuDomainPrepareDisk(driver, vm, disk, NULL, false) < 0)
678
        goto cleanup;
679 680 681

    /* We should have an address already, so make sure */
    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
682 683 684
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected disk address type %s"),
                       virDomainDeviceAddressTypeToString(disk->info.type));
685 686 687
        goto error;
    }

688 689 690 691 692 693 694 695 696 697 698 699
    /* 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))
            goto error;
    }

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

J
John Ferlan 已提交
703
    if (qemuDomainSecretDiskPrepare(conn, priv, disk) < 0)
704 705
        goto error;

706
    diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
707 708 709 710 711 712
    secinfo = diskPriv->secinfo;
    if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
        if (qemuBuildSecretInfoProps(secinfo, &secobjProps) < 0)
            goto error;
    }

713 714 715 716
    encinfo = diskPriv->encinfo;
    if (encinfo && qemuBuildSecretInfoProps(encinfo, &encobjProps) < 0)
        goto error;

717 718
    if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
        goto error;
719

720 721 722 723 724 725 726 727
    if (qemuDomainPrepareDiskSourceTLS(disk->src, disk->info.alias, cfg) < 0)
        goto error;

    if (disk->src->haveTLS &&
        qemuDomainAddDiskSrcTLSObject(driver, vm, disk->src,
                                      disk->info.alias) < 0)
        goto error;

728
    if (!(drivestr = qemuBuildDriveStr(disk, cfg, false, priv->qemuCaps)))
729 730
        goto error;

731 732 733
    if (!(drivealias = qemuAliasFromDisk(disk)))
        goto error;

734
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
735 736
        goto error;

737
    qemuDomainObjEnterMonitor(driver, vm);
738

739 740 741 742 743 744 745 746 747
    if (secobjProps) {
        rv = qemuMonitorAddObject(priv->mon, "secret", secinfo->s.aes.alias,
                                  secobjProps);
        secobjProps = NULL; /* qemuMonitorAddObject consumes */
        if (rv < 0)
            goto exit_monitor;
        secobjAdded = true;
    }

748 749 750 751 752 753
    if (encobjProps) {
        rv = qemuMonitorAddObject(priv->mon, "secret", encinfo->s.aes.alias,
                                  encobjProps);
        encobjProps = NULL; /* qemuMonitorAddObject consumes */
        if (rv < 0)
            goto exit_monitor;
754
        encobjAdded = true;
755 756
    }

757
    if (qemuMonitorAddDrive(priv->mon, drivestr) < 0)
758 759
        goto exit_monitor;
    driveAdded = true;
760

761
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
762
        goto exit_monitor;
763

764
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
765
        goto error;
766

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

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

772
 cleanup:
773
    virJSONValueFree(secobjProps);
774
    virJSONValueFree(encobjProps);
775
    qemuDomainSecretDiskDestroy(disk);
776 777
    VIR_FREE(devstr);
    VIR_FREE(drivestr);
778
    VIR_FREE(drivealias);
779 780
    virObjectUnref(cfg);
    return ret;
781

782
 exit_monitor:
783
    virErrorPreserveLast(&orig_err);
784 785 786 787
    if (driveAdded && qemuMonitorDriveDel(priv->mon, drivealias) < 0) {
        VIR_WARN("Unable to remove drive %s (%s) after failed "
                 "qemuMonitorAddDevice", drivealias, drivestr);
    }
788 789
    if (secobjAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, secinfo->s.aes.alias));
790 791
    if (encobjAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias));
792
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
793
    virErrorRestore(&orig_err);
794

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

797
 error:
798 799
    qemuDomainDelDiskSrcTLSObject(driver, vm, disk->src);

800
    ignore_value(qemuDomainPrepareDisk(driver, vm, disk, NULL, true));
801
    goto cleanup;
802 803 804
}


805
static int
806
qemuDomainAttachUSBMassStorageDevice(virQEMUDriverPtr driver,
807 808
                                     virDomainObjPtr vm,
                                     virDomainDiskDefPtr disk)
809 810
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
811
    virErrorPtr orig_err;
812
    int ret = -1;
813
    char *drivealias = NULL;
814 815
    char *drivestr = NULL;
    char *devstr = NULL;
816
    bool driveAdded = false;
817
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
818
    const char *src = virDomainDiskGetSource(disk);
819 820 821 822 823 824 825
    bool releaseaddr = false;

    if (priv->usbaddrs) {
        if (virDomainUSBAddressEnsure(priv->usbaddrs, &disk->info) < 0)
            goto cleanup;
        releaseaddr = true;
    }
826

827
    if (qemuDomainPrepareDisk(driver, vm, disk, NULL, false) < 0)
828
        goto cleanup;
829

830
    /* XXX not correct once we allow attaching a USB CDROM */
831
    if (!src) {
832 833
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("disk source path is missing"));
834 835 836
        goto error;
    }

837 838
    if (qemuAssignDeviceDiskAlias(vm->def, disk, priv->qemuCaps) < 0)
        goto error;
839

840 841 842 843 844 845 846 847
    if (qemuDomainPrepareDiskSourceTLS(disk->src, disk->info.alias, cfg) < 0)
        goto error;

    if (disk->src->haveTLS &&
        qemuDomainAddDiskSrcTLSObject(driver, vm, disk->src,
                                      disk->info.alias) < 0)
        goto error;

848
    if (!(drivestr = qemuBuildDriveStr(disk, cfg, false, priv->qemuCaps)))
849
        goto error;
850 851 852 853

    if (!(drivealias = qemuAliasFromDisk(disk)))
        goto error;

854 855
    if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
        goto error;
856

857
    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
858 859
        goto error;

860
    qemuDomainObjEnterMonitor(driver, vm);
861

862 863 864 865 866 867
    if (qemuMonitorAddDrive(priv->mon, drivestr) < 0)
        goto exit_monitor;
    driveAdded = true;

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
        goto exit_monitor;
868

869
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
870 871
        goto error;

872 873
    virDomainAuditDisk(vm, NULL, disk->src, "attach", true);

874
    virDomainDiskInsertPreAlloced(vm->def, disk);
875
    ret = 0;
876

877
 cleanup:
878 879
    if (ret < 0 && releaseaddr)
        virDomainUSBAddressRelease(priv->usbaddrs, &disk->info);
880
    VIR_FREE(devstr);
881
    VIR_FREE(drivealias);
882
    VIR_FREE(drivestr);
883 884
    virObjectUnref(cfg);
    return ret;
885

886
 exit_monitor:
887
    virErrorPreserveLast(&orig_err);
888 889 890 891
    if (driveAdded && qemuMonitorDriveDel(priv->mon, drivealias) < 0) {
        VIR_WARN("Unable to remove drive %s (%s) after failed "
                 "qemuMonitorAddDevice", drivealias, drivestr);
    }
892
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
893
    virErrorRestore(&orig_err);
894 895 896

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

897
 error:
898 899
    qemuDomainDelDiskSrcTLSObject(driver, vm, disk->src);

900
    ignore_value(qemuDomainPrepareDisk(driver, vm, disk, NULL, true));
901
    goto cleanup;
902 903 904
}


905 906 907 908 909 910
int
qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
                               virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainDeviceDefPtr dev)
{
911
    size_t i;
912 913 914
    virDomainDiskDefPtr disk = dev->data.disk;
    virDomainDiskDefPtr orig_disk = NULL;
    int ret = -1;
915
    const char *src = virDomainDiskGetSource(disk);
916

917
    if (STRNEQ_NULLABLE(virDomainDiskGetDriver(disk), "qemu")) {
918 919
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unsupported driver name '%s' for disk '%s'"),
920
                       virDomainDiskGetDriver(disk), src);
921
        goto cleanup;
922 923
    }

924
    if (virStorageTranslateDiskSourcePool(conn, disk) < 0)
925
        goto cleanup;
926 927

    if (qemuAddSharedDevice(driver, dev, vm->def->name) < 0)
928
        goto cleanup;
929 930

    if (qemuSetUnprivSGIO(dev) < 0)
931
        goto cleanup;
932

933
    if (qemuDomainDetermineDiskChain(driver, vm, disk, false, true) < 0)
934
        goto cleanup;
935

936
    switch ((virDomainDiskDevice) disk->device)  {
937 938 939 940 941
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
        if (!(orig_disk = virDomainDiskFindByBusAndDst(vm->def,
                                                       disk->bus, disk->dst))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
942 943 944
                           _("No device with bus '%s' and target '%s'. "
                             "cdrom and floppy device hotplug isn't supported "
                             "by libvirt"),
945 946
                           virDomainDiskBusTypeToString(disk->bus),
                           disk->dst);
947
            goto cleanup;
948 949
        }

950
        if (qemuDomainChangeEjectableMedia(driver, vm, orig_disk,
951
                                           disk->src, false) < 0)
952
            goto cleanup;
953

954
        disk->src = NULL;
955
        ret = 0;
956
        break;
957

958 959
    case VIR_DOMAIN_DISK_DEVICE_DISK:
    case VIR_DOMAIN_DISK_DEVICE_LUN:
960
        for (i = 0; i < vm->def->ndisks; i++) {
961 962
            if (virDomainDiskDefCheckDuplicateInfo(vm->def->disks[i], disk) < 0)
                goto cleanup;
963 964
        }

965 966
        switch ((virDomainDiskBus) disk->bus) {
        case VIR_DOMAIN_DISK_BUS_USB:
967 968 969 970 971
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("disk device='lun' is not supported for usb bus"));
                break;
            }
972
            ret = qemuDomainAttachUSBMassStorageDevice(driver, vm, disk);
973 974 975
            break;

        case VIR_DOMAIN_DISK_BUS_VIRTIO:
976
            ret = qemuDomainAttachVirtioDiskDevice(conn, driver, vm, disk);
977 978 979
            break;

        case VIR_DOMAIN_DISK_BUS_SCSI:
980
            ret = qemuDomainAttachSCSIDisk(conn, driver, vm, disk);
981 982 983 984 985 986 987 988 989
            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:
        case VIR_DOMAIN_DISK_BUS_LAST:
990 991 992 993 994
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(disk->bus));
        }
        break;
995 996

    case VIR_DOMAIN_DISK_DEVICE_LAST:
997 998 999
        break;
    }

1000
 cleanup:
1001 1002 1003 1004 1005 1006
    if (ret != 0)
        ignore_value(qemuRemoveSharedDevice(driver, dev, vm->def->name));
    return ret;
}


1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
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));
    }
}


1025 1026 1027 1028
int
qemuDomainAttachNetDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainNetDefPtr net)
1029 1030
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1031
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_NET, { .net = net } };
1032
    virErrorPtr originalError = NULL;
1033 1034
    char **tapfdName = NULL;
    int *tapfd = NULL;
1035
    size_t tapfdSize = 0;
1036 1037
    char **vhostfdName = NULL;
    int *vhostfd = NULL;
1038
    size_t vhostfdSize = 0;
1039
    size_t queueSize = 0;
1040 1041 1042 1043
    char *nicstr = NULL;
    char *netstr = NULL;
    int ret = -1;
    int vlan;
1044
    bool releaseaddr = false;
1045
    bool iface_connected = false;
1046
    virDomainNetType actualType;
1047
    virNetDevBandwidthPtr actualBandwidth;
1048
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
1049
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
1050
    size_t i;
1051 1052 1053 1054
    char *charDevAlias = NULL;
    bool charDevPlugged = false;
    bool netdevPlugged = false;
    bool hostPlugged = false;
1055

1056
    /* preallocate new slot for device */
1057
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
1058
        goto cleanup;
1059

1060 1061 1062 1063
    /* 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.
     */
1064
    if (networkAllocateActualDevice(vm->def, net) < 0)
1065
        goto cleanup;
1066 1067

    actualType = virDomainNetGetActualType(net);
1068

1069
    /* Currently only TAP/macvtap devices supports multiqueue. */
1070 1071
    if (net->driver.virtio.queues > 0 &&
        !(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
1072
          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
1073
          actualType == VIR_DOMAIN_NET_TYPE_DIRECT ||
1074 1075
          actualType == VIR_DOMAIN_NET_TYPE_ETHERNET ||
          actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER)) {
1076 1077 1078 1079 1080 1081
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Multiqueue network is not supported for: %s"),
                       virDomainNetTypeToString(actualType));
        return -1;
    }

1082 1083 1084
    /* and only TAP devices support nwfilter rules */
    if (net->filter &&
        !(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
1085 1086
          actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
          actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
1087 1088 1089 1090 1091 1092 1093
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("filterref is not supported for "
                         "network interfaces of type %s"),
                       virDomainNetTypeToString(actualType));
        return -1;
    }

1094 1095 1096
    if (qemuAssignDeviceNetAlias(vm->def, net, -1) < 0)
        goto cleanup;

1097 1098 1099
    switch (actualType) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
    case VIR_DOMAIN_NET_TYPE_NETWORK:
1100 1101 1102
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1103
        queueSize = tapfdSize;
1104
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1105
            goto cleanup;
1106 1107 1108 1109
        memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
        if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
            goto cleanup;
        memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
1110
        if (qemuInterfaceBridgeConnect(vm->def, driver, net,
1111
                                       tapfd, &tapfdSize) < 0)
1112 1113
            goto cleanup;
        iface_connected = true;
1114 1115
        if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
                                      vhostfd, &vhostfdSize) < 0)
1116
            goto cleanup;
1117 1118 1119
        break;

    case VIR_DOMAIN_NET_TYPE_DIRECT:
1120 1121 1122
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1123
        queueSize = tapfdSize;
1124
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1125
            goto cleanup;
1126 1127
        memset(tapfd, -1, sizeof(*tapfd) * tapfdSize);
        if (VIR_ALLOC_N(vhostfd, vhostfdSize) < 0)
1128
            goto cleanup;
1129
        memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize);
1130 1131 1132
        if (qemuInterfaceDirectConnect(vm->def, driver, net,
                                       tapfd, tapfdSize,
                                       VIR_NETDEV_VPORT_PROFILE_OP_CREATE) < 0)
1133 1134
            goto cleanup;
        iface_connected = true;
1135 1136
        if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
                                      vhostfd, &vhostfdSize) < 0)
1137
            goto cleanup;
1138 1139 1140
        break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
1141 1142 1143
        tapfdSize = vhostfdSize = net->driver.virtio.queues;
        if (!tapfdSize)
            tapfdSize = vhostfdSize = 1;
1144
        queueSize = tapfdSize;
1145
        if (VIR_ALLOC_N(tapfd, tapfdSize) < 0)
1146
            goto cleanup;
1147 1148 1149 1150 1151
        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,
1152
                                         tapfd, tapfdSize) < 0)
1153 1154
            goto cleanup;
        iface_connected = true;
1155 1156
        if (qemuInterfaceOpenVhostNet(vm->def, net, priv->qemuCaps,
                                      vhostfd, &vhostfdSize) < 0)
1157
            goto cleanup;
1158 1159 1160
        break;

    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
        /* 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.
         *
         * qemuDomainAttachHostDevice uses a connection to resolve
         * a SCSI hostdev secret, which is not this case, so pass NULL.
         */
        ret = qemuDomainAttachHostDevice(NULL, driver, vm,
                                         virDomainNetGetActualHostdev(net));
        goto cleanup;
1172 1173 1174
        break;

    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
1175 1176 1177
        queueSize = net->driver.virtio.queues;
        if (!queueSize)
            queueSize = 1;
1178 1179 1180 1181 1182 1183
        if (!qemuDomainSupportsNetdev(vm->def, priv->qemuCaps, net)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Netdev support unavailable"));
            goto cleanup;
        }

1184
        if (!(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias)))
1185 1186 1187 1188
            goto cleanup;
        break;

    case VIR_DOMAIN_NET_TYPE_USER:
1189 1190 1191
        /* No preparation needed. */
        break;

1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
    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;
1202 1203
    }

1204 1205
    /* Set device online immediately */
    if (qemuInterfaceStartDevice(net) < 0)
1206
        goto cleanup;
1207

1208 1209 1210 1211
    /* Set bandwidth or warn if requested and not supported. */
    actualBandwidth = virDomainNetGetActualBandwidth(net);
    if (actualBandwidth) {
        if (virNetDevSupportBandwidth(actualType)) {
1212 1213
            if (virNetDevBandwidthSet(net->ifname, actualBandwidth, false,
                                      !virDomainNetTypeSharesHostView(net)) < 0)
1214 1215 1216 1217 1218 1219 1220
                goto cleanup;
        } else {
            VIR_WARN("setting bandwidth on interfaces of "
                     "type '%s' is not implemented yet",
                     virDomainNetTypeToString(actualType));
        }
    }
1221

1222 1223 1224 1225
    if (net->mtu &&
        virNetDevSetMTU(net->ifname, net->mtu) < 0)
        goto cleanup;

M
Michal Privoznik 已提交
1226
    for (i = 0; i < tapfdSize; i++) {
1227 1228
        if (qemuSecuritySetTapFDLabel(driver->securityManager,
                                      vm->def, tapfd[i]) < 0)
M
Michal Privoznik 已提交
1229 1230 1231
            goto cleanup;
    }

1232
    if (qemuDomainIsS390CCW(vm->def) &&
1233 1234
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
        net->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
1235 1236 1237
        if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
            goto cleanup;
        if (virDomainCCWAddressAssign(&net->info, ccwaddrs,
J
Ján Tomko 已提交
1238
                                      !net->info.addr.ccw.assigned) < 0)
1239
            goto cleanup;
1240
    } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
1241
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1242 1243
                       _("virtio-s390 net device cannot be hotplugged."));
        goto cleanup;
1244
    } else if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0) {
1245 1246
        goto cleanup;
    }
1247

1248 1249
    releaseaddr = true;

1250
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
1251 1252 1253 1254 1255
        vlan = -1;
    } else {
        vlan = qemuDomainNetVLAN(net);

        if (vlan < 0) {
1256 1257
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Unable to attach network devices without vlan"));
1258 1259 1260 1261
            goto cleanup;
        }
    }

1262
    if (VIR_ALLOC_N(tapfdName, tapfdSize) < 0 ||
1263
        VIR_ALLOC_N(vhostfdName, vhostfdSize) < 0)
1264 1265 1266
        goto cleanup;

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

1271
    for (i = 0; i < vhostfdSize; i++) {
1272
        if (virAsprintf(&vhostfdName[i], "vhostfd-%s%zu", net->info.alias, i) < 0)
1273
            goto cleanup;
1274 1275
    }

1276
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
1277
        if (!(netstr = qemuBuildHostNetStr(net, driver,
1278 1279 1280
                                           ',', -1,
                                           tapfdName, tapfdSize,
                                           vhostfdName, vhostfdSize)))
1281
            goto cleanup;
1282
    } else {
1283
        if (!(netstr = qemuBuildHostNetStr(net, driver,
1284 1285 1286
                                           ' ', vlan,
                                           tapfdName, tapfdSize,
                                           vhostfdName, vhostfdSize)))
1287
            goto cleanup;
1288 1289
    }

1290
    qemuDomainObjEnterMonitor(driver, vm);
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300

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

1301
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
1302 1303 1304
        if (qemuMonitorAddNetdev(priv->mon, netstr,
                                 tapfd, tapfdName, tapfdSize,
                                 vhostfd, vhostfdName, vhostfdSize) < 0) {
1305
            ignore_value(qemuDomainObjExitMonitor(driver, vm));
1306
            virDomainAuditNet(vm, NULL, net, "attach", false);
1307
            goto try_remove;
1308
        }
1309
        netdevPlugged = true;
1310
    } else {
1311 1312 1313
        if (qemuMonitorAddHostNetwork(priv->mon, netstr,
                                      tapfd, tapfdName, tapfdSize,
                                      vhostfd, vhostfdName, vhostfdSize) < 0) {
1314
            ignore_value(qemuDomainObjExitMonitor(driver, vm));
1315
            virDomainAuditNet(vm, NULL, net, "attach", false);
1316
            goto try_remove;
1317
        }
1318
        hostPlugged = true;
1319
    }
1320

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

1324 1325 1326 1327
    for (i = 0; i < tapfdSize; i++)
        VIR_FORCE_CLOSE(tapfd[i]);
    for (i = 0; i < vhostfdSize; i++)
        VIR_FORCE_CLOSE(vhostfd[i]);
1328

1329
    if (!(nicstr = qemuBuildNicDevStr(vm->def, net, vlan, 0,
1330
                                      queueSize, priv->qemuCaps)))
1331
        goto try_remove;
1332

1333
    qemuDomainObjEnterMonitor(driver, vm);
1334 1335 1336 1337
    if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) {
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        virDomainAuditNet(vm, NULL, net, "attach", false);
        goto try_remove;
1338
    }
1339 1340
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
1341

1342 1343 1344
    /* set link state */
    if (net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) {
        if (!net->info.alias) {
1345 1346
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("device alias not found: cannot set link state to down"));
1347
        } else {
1348
            qemuDomainObjEnterMonitor(driver, vm);
1349

1350
            if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
1351
                if (qemuMonitorSetLink(priv->mon, net->info.alias, VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) < 0) {
1352
                    ignore_value(qemuDomainObjExitMonitor(driver, vm));
1353 1354 1355 1356
                    virDomainAuditNet(vm, NULL, net, "attach", false);
                    goto try_remove;
                }
            } else {
1357
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1358
                               _("setting of link state not supported: Link is up"));
1359 1360
            }

1361 1362
            if (qemuDomainObjExitMonitor(driver, vm) < 0)
                goto cleanup;
1363 1364 1365 1366
        }
        /* link set to down */
    }

1367
    virDomainAuditNet(vm, NULL, net, "attach", true);
1368 1369 1370

    ret = 0;

1371
 cleanup:
1372 1373 1374
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else {
1375 1376
        if (releaseaddr)
            qemuDomainReleaseDeviceAddress(vm, &net->info, NULL);
1377

1378
        if (iface_connected) {
1379
            virDomainConfNWFilterTeardown(net);
1380

1381 1382 1383 1384 1385 1386 1387 1388 1389
            if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {
                ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
                                 net->ifname, &net->mac,
                                 virDomainNetGetActualDirectDev(net),
                                 virDomainNetGetActualDirectMode(net),
                                 virDomainNetGetActualVirtPortProfile(net),
                                 cfg->stateDir));
            }

1390
            qemuDomainNetDeviceVportRemove(net);
1391
        }
A
Ansis Atteka 已提交
1392

1393 1394
        virDomainNetRemoveHostdev(vm->def, net);

1395
        networkReleaseActualDevice(vm->def, net);
1396
    }
1397 1398 1399

    VIR_FREE(nicstr);
    VIR_FREE(netstr);
1400
    for (i = 0; tapfd && i < tapfdSize; i++) {
1401
        VIR_FORCE_CLOSE(tapfd[i]);
1402 1403
        if (tapfdName)
            VIR_FREE(tapfdName[i]);
1404 1405 1406
    }
    VIR_FREE(tapfd);
    VIR_FREE(tapfdName);
1407
    for (i = 0; vhostfd && i < vhostfdSize; i++) {
1408
        VIR_FORCE_CLOSE(vhostfd[i]);
1409 1410
        if (vhostfdName)
            VIR_FREE(vhostfdName[i]);
1411 1412 1413
    }
    VIR_FREE(vhostfd);
    VIR_FREE(vhostfdName);
1414
    VIR_FREE(charDevAlias);
1415
    virObjectUnref(cfg);
1416
    virDomainCCWAddressSetFree(ccwaddrs);
1417 1418 1419

    return ret;

1420
 try_remove:
1421 1422 1423
    if (!virDomainObjIsActive(vm))
        goto cleanup;

1424
    virErrorPreserveLast(&originalError);
1425
    if (vlan < 0) {
1426
        if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
1427
            char *netdev_name;
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
            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);
            }
1440
        } else {
1441
            VIR_WARN("Unable to remove network backend");
1442 1443 1444
        }
    } else {
        char *hostnet_name;
1445 1446 1447 1448 1449 1450 1451 1452 1453
        if (virAsprintf(&hostnet_name, "host%s", net->info.alias) >= 0) {
            qemuDomainObjEnterMonitor(driver, vm);
            if (hostPlugged &&
                qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0)
                VIR_WARN("Failed to remove network backend for vlan %d, net %s",
                         vlan, hostnet_name);
            ignore_value(qemuDomainObjExitMonitor(driver, vm));
            VIR_FREE(hostnet_name);
        }
1454
    }
1455
    virErrorRestore(&originalError);
1456 1457 1458 1459
    goto cleanup;
}


1460
static int
1461
qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
1462 1463
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
1464 1465
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
1466 1467
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_HOSTDEV,
                               { .hostdev = hostdev } };
1468
    virDomainDeviceInfoPtr info = hostdev->info;
1469 1470 1471 1472
    int ret;
    char *devstr = NULL;
    int configfd = -1;
    char *configfd_name = NULL;
1473
    bool releaseaddr = false;
1474
    bool teardowncgroup = false;
1475
    bool teardownlabel = false;
1476
    bool teardowndevice = false;
1477
    int backend;
1478 1479
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    unsigned int flags = 0;
1480

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

1484 1485
    if (!cfg->relaxedACS)
        flags |= VIR_HOSTDEV_STRICT_ACS_CHECK;
1486
    if (qemuHostdevPreparePCIDevices(driver, vm->def->name, vm->def->uuid,
1487 1488
                                     &hostdev, 1, priv->qemuCaps, flags) < 0)
        goto cleanup;
1489

1490
    /* this could have been changed by qemuHostdevPreparePCIDevices */
1491 1492
    backend = hostdev->source.subsys.u.pci.backend;

1493
    switch ((virDomainHostdevSubsysPCIBackendType) backend) {
1494
    case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
1495 1496 1497 1498 1499 1500
        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;
        }
1501 1502
        break;

1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
    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;
1513
        break;
1514 1515
    }

1516
    /* Temporarily add the hostdev to the domain definition. This is needed
1517 1518 1519 1520
     * 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 */
1521
    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
1522 1523 1524
    if (qemuDomainAdjustMaxMemLock(vm) < 0) {
        vm->def->hostdevs[--(vm->def->nhostdevs)] = NULL;
        goto error;
1525 1526 1527
    }
    vm->def->hostdevs[--(vm->def->nhostdevs)] = NULL;

1528 1529 1530 1531
    if (qemuDomainNamespaceSetupHostdev(driver, vm, hostdev) < 0)
        goto error;
    teardowndevice = true;

1532
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
1533 1534 1535
        goto error;
    teardowncgroup = true;

1536
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
1537
        goto error;
1538 1539
    if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
        teardownlabel = true;
1540

1541
    if (qemuAssignDeviceHostdevAlias(vm->def, &info->alias, -1) < 0)
1542
        goto error;
1543 1544 1545 1546 1547 1548 1549

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

1550
    if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
1551 1552 1553 1554 1555 1556
        goto error;
    releaseaddr = true;
    if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO &&
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_PCI_CONFIGFD)) {
        configfd = qemuOpenPCIConfig(hostdev);
        if (configfd >= 0) {
1557
            if (virAsprintf(&configfd_name, "fd-%s", info->alias) < 0)
1558
                goto error;
1559
        }
1560
    }
1561

1562 1563 1564 1565 1566
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("guest unexpectedly quit during hotplug"));
        goto error;
    }
1567

1568 1569 1570
    if (!(devstr = qemuBuildPCIHostdevDevStr(vm->def, hostdev, 0,
                                             configfd_name, priv->qemuCaps)))
        goto error;
1571

1572 1573 1574 1575 1576
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr,
                                     configfd, configfd_name);
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto error;
1577

1578
    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
1579 1580 1581 1582 1583 1584 1585 1586
    if (ret < 0)
        goto error;

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

    VIR_FREE(devstr);
    VIR_FREE(configfd_name);
    VIR_FORCE_CLOSE(configfd);
1587
    virObjectUnref(cfg);
1588 1589 1590

    return 0;

1591
 error:
1592 1593
    if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
        VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
1594
    if (teardownlabel &&
1595
        qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
1596
        VIR_WARN("Unable to restore host device labelling on hotplug fail");
1597 1598 1599
    if (teardowndevice &&
        qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
        VIR_WARN("Unable to remove host device from /dev");
1600

1601
    if (releaseaddr)
1602
        qemuDomainReleaseDeviceAddress(vm, info, NULL);
1603

1604
    qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
1605 1606 1607 1608 1609

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

1610
 cleanup:
1611
    virObjectUnref(cfg);
1612 1613 1614 1615
    return -1;
}


1616 1617 1618
void
qemuDomainDelTLSObjects(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
1619
                        qemuDomainAsyncJob asyncJob,
1620 1621 1622 1623 1624 1625 1626 1627 1628
                        const char *secAlias,
                        const char *tlsAlias)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virErrorPtr orig_err;

    if (!tlsAlias && !secAlias)
        return;

1629
    virErrorPreserveLast(&orig_err);
1630

1631 1632
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;
1633 1634 1635 1636 1637 1638 1639 1640 1641

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

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

    ignore_value(qemuDomainObjExitMonitor(driver, vm));

1642
 cleanup:
1643
    virErrorRestore(&orig_err);
1644 1645 1646 1647 1648 1649
}


int
qemuDomainAddTLSObjects(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
1650
                        qemuDomainAsyncJob asyncJob,
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
                        const char *secAlias,
                        virJSONValuePtr *secProps,
                        const char *tlsAlias,
                        virJSONValuePtr *tlsProps)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int rc;
    virErrorPtr orig_err;

    if (!tlsAlias && !secAlias)
        return 0;

1663 1664
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        return -1;
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684

    if (secAlias) {
        rc = qemuMonitorAddObject(priv->mon, "secret",
                                  secAlias, *secProps);
        *secProps = NULL; /* qemuMonitorAddObject consumes */
        if (rc < 0)
            goto error;
    }

    if (tlsAlias) {
        rc = qemuMonitorAddObject(priv->mon, "tls-creds-x509",
                                  tlsAlias, *tlsProps);
        *tlsProps = NULL; /* qemuMonitorAddObject consumes */
        if (rc < 0)
            goto error;
    }

    return qemuDomainObjExitMonitor(driver, vm);

 error:
1685
    virErrorPreserveLast(&orig_err);
1686
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
1687
    virErrorRestore(&orig_err);
1688
    qemuDomainDelTLSObjects(driver, vm, asyncJob, secAlias, tlsAlias);
1689 1690 1691 1692 1693

    return -1;
}


1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704
int
qemuDomainGetTLSObjects(virQEMUCapsPtr qemuCaps,
                        qemuDomainSecretInfoPtr secinfo,
                        const char *tlsCertdir,
                        bool tlsListen,
                        bool tlsVerify,
                        const char *srcAlias,
                        virJSONValuePtr *tlsProps,
                        char **tlsAlias,
                        virJSONValuePtr *secProps,
                        char **secAlias)
1705
{
1706 1707
    /* Add a secret object in order to access the TLS environment.
     * The secinfo will only be created for serial TCP device. */
1708 1709
    if (secinfo) {
        if (qemuBuildSecretInfoProps(secinfo, secProps) < 0)
1710 1711
            return -1;

1712 1713
        if (!secAlias ||
            !(*secAlias = qemuDomainGetSecretAESAlias(srcAlias, false)))
1714 1715 1716
            return -1;
    }

1717
    if (qemuBuildTLSx509BackendProps(tlsCertdir, tlsListen, tlsVerify,
1718 1719
                                     secAlias ? *secAlias : NULL, qemuCaps,
                                     tlsProps) < 0)
1720 1721
        return -1;

1722
    if (!(*tlsAlias = qemuAliasTLSObjFromSrcAlias(srcAlias)))
1723 1724 1725 1726 1727 1728
        return -1;

    return 0;
}


1729
static int
1730 1731
qemuDomainAddChardevTLSObjects(virConnectPtr conn,
                               virQEMUDriverPtr driver,
1732 1733
                               virDomainObjPtr vm,
                               virDomainChrSourceDefPtr dev,
1734
                               char *devAlias,
1735 1736 1737 1738 1739
                               char *charAlias,
                               char **tlsAlias,
                               char **secAlias)
{
    int ret = -1;
1740
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
1741
    qemuDomainObjPrivatePtr priv = vm->privateData;
1742 1743
    qemuDomainChrSourcePrivatePtr chrSourcePriv;
    qemuDomainSecretInfoPtr secinfo = NULL;
1744 1745 1746
    virJSONValuePtr tlsProps = NULL;
    virJSONValuePtr secProps = NULL;

1747 1748 1749
    /* NB: This may alter haveTLS based on cfg */
    qemuDomainPrepareChardevSourceTLS(dev, cfg);

1750
    if (dev->type != VIR_DOMAIN_CHR_TYPE_TCP ||
1751 1752 1753 1754
        dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_YES) {
        ret = 0;
        goto cleanup;
    }
1755

1756 1757 1758
    if (qemuDomainSecretChardevPrepare(conn, cfg, priv, devAlias, dev) < 0)
        goto cleanup;

1759 1760 1761 1762 1763 1764 1765 1766 1767
    if ((chrSourcePriv = QEMU_DOMAIN_CHR_SOURCE_PRIVATE(dev)))
        secinfo = chrSourcePriv->secinfo;

    if (qemuDomainGetTLSObjects(priv->qemuCaps, secinfo,
                                cfg->chardevTLSx509certdir,
                                dev->data.tcp.listen,
                                cfg->chardevTLSx509verify,
                                charAlias, &tlsProps, tlsAlias,
                                &secProps, secAlias) < 0)
1768
        goto cleanup;
1769
    dev->data.tcp.tlscreds = true;
1770

1771 1772
    if (qemuDomainAddTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                                *secAlias, &secProps, *tlsAlias, &tlsProps) < 0)
1773 1774 1775 1776 1777 1778 1779
        goto cleanup;

    ret = 0;

 cleanup:
    virJSONValueFree(tlsProps);
    virJSONValueFree(secProps);
1780
    virObjectUnref(cfg);
1781 1782 1783 1784 1785

    return ret;
}


1786 1787
int qemuDomainAttachRedirdevDevice(virConnectPtr conn,
                                   virQEMUDriverPtr driver,
1788 1789 1790
                                   virDomainObjPtr vm,
                                   virDomainRedirdevDefPtr redirdev)
{
1791
    int ret = -1;
1792
    qemuDomainObjPrivatePtr priv = vm->privateData;
1793
    virDomainDefPtr def = vm->def;
1794
    char *charAlias = NULL;
1795
    char *devstr = NULL;
1796
    bool chardevAdded = false;
1797
    char *tlsAlias = NULL;
1798
    char *secAlias = NULL;
1799
    bool need_release = false;
1800
    virErrorPtr orig_err;
1801

1802
    if (qemuAssignDeviceRedirdevAlias(def, redirdev, -1) < 0)
1803 1804
        goto cleanup;

1805
    if (!(charAlias = qemuAliasChardevFromDevAlias(redirdev->info.alias)))
1806 1807
        goto cleanup;

1808
    if ((virDomainUSBAddressEnsure(priv->usbaddrs, &redirdev->info)) < 0)
1809
        goto cleanup;
1810
    need_release = true;
1811

1812
    if (!(devstr = qemuBuildRedirdevDevStr(def, redirdev, priv->qemuCaps)))
1813
        goto cleanup;
1814

1815
    if (VIR_REALLOC_N(def->redirdevs, def->nredirdevs+1) < 0)
1816
        goto cleanup;
1817

1818
    if (qemuDomainAddChardevTLSObjects(conn, driver, vm, redirdev->source,
1819 1820
                                       redirdev->info.alias, charAlias,
                                       &tlsAlias, &secAlias) < 0)
1821
        goto audit;
1822

1823
    qemuDomainObjEnterMonitor(driver, vm);
1824

1825 1826
    if (qemuMonitorAttachCharDev(priv->mon,
                                 charAlias,
1827
                                 redirdev->source) < 0)
1828 1829
        goto exit_monitor;
    chardevAdded = true;
1830

1831 1832
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
        goto exit_monitor;
1833

1834 1835
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto audit;
1836

1837
    def->redirdevs[def->nredirdevs++] = redirdev;
1838 1839 1840 1841
    ret = 0;
 audit:
    virDomainAuditRedirdev(vm, redirdev, "attach", ret == 0);
 cleanup:
1842 1843
    if (ret < 0 && need_release)
        qemuDomainReleaseDeviceAddress(vm, &redirdev->info, NULL);
1844
    VIR_FREE(tlsAlias);
1845
    VIR_FREE(secAlias);
1846
    VIR_FREE(charAlias);
1847
    VIR_FREE(devstr);
1848
    return ret;
1849 1850

 exit_monitor:
1851
    virErrorPreserveLast(&orig_err);
1852 1853 1854
    /* detach associated chardev on error */
    if (chardevAdded)
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
1855
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
1856
    virErrorRestore(&orig_err);
1857 1858
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
1859
    goto audit;
1860 1861
}

1862 1863 1864
static int
qemuDomainChrPreInsert(virDomainDefPtr vmdef,
                       virDomainChrDefPtr chr)
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
{
    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;
    }

1879
    if (virDomainChrPreAlloc(vmdef, chr) < 0)
1880 1881
        return -1;

1882 1883 1884 1885
    /* 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.
     */
1886 1887 1888 1889 1890
    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;

1891 1892
        /* We'll be dealing with serials[0] directly, so NULL is fine here. */
        if (!(vmdef->consoles[0] = virDomainChrDefNew(NULL))) {
1893
            VIR_FREE(vmdef->consoles);
1894 1895
            return -1;
        }
1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
        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) {
1908 1909 1910 1911 1912 1913
        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;
    }
1914 1915 1916 1917 1918 1919 1920 1921 1922
}

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) {
1923
        virDomainChrDefFree(vmdef->consoles[0]);
1924 1925 1926 1927
        VIR_FREE(vmdef->consoles);
        vmdef->nconsoles = 0;
    }
}
1928

1929 1930 1931 1932 1933 1934 1935 1936 1937
int
qemuDomainChrInsert(virDomainDefPtr vmdef,
                    virDomainChrDefPtr chr)
{
    if (qemuDomainChrPreInsert(vmdef, chr) < 0) {
        qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
        return -1;
    }
    qemuDomainChrInsertPreAlloced(vmdef, chr);
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973
    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;
}
1974

1975 1976 1977 1978
/* Returns  1 if the address will need to be released later,
 *         -1 on error
 *          0 otherwise
 */
1979
static int
1980
qemuDomainAttachChrDeviceAssignAddr(virDomainObjPtr vm,
1981 1982
                                    virDomainChrDefPtr chr,
                                    virQEMUDriverPtr driver)
1983
{
1984 1985
    virDomainDefPtr def = vm->def;
    qemuDomainObjPrivatePtr priv = vm->privateData;
1986
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_CHR, { .chr = chr } };
1987

1988 1989
    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO) {
1990
        if (virDomainVirtioSerialAddrAutoAssign(def, &chr->info, true) < 0)
1991
            return -1;
1992
        return 0;
1993 1994 1995

    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
               chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_PCI) {
1996
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
1997 1998
            return -1;
        return 1;
1999

J
Ján Tomko 已提交
2000 2001
    } else if (priv->usbaddrs &&
               chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL &&
2002 2003
               chr->targetType == VIR_DOMAIN_CHR_SERIAL_TARGET_TYPE_USB) {
        if (virDomainUSBAddressEnsure(priv->usbaddrs, &chr->info) < 0)
2004 2005
            return -1;
        return 1;
2006

2007 2008
    } else if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
               chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO) {
2009
        if (virDomainVirtioSerialAddrAutoAssign(def, &chr->info, false) < 0)
2010
            return -1;
2011
        return 0;
2012 2013 2014 2015 2016 2017
    }

    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"));
2018
        return -1;
2019 2020
    }

2021
    return 0;
2022 2023
}

2024 2025
int qemuDomainAttachChrDevice(virConnectPtr conn,
                              virQEMUDriverPtr driver,
2026 2027 2028
                              virDomainObjPtr vm,
                              virDomainChrDefPtr chr)
{
2029
    int ret = -1, rc;
2030
    qemuDomainObjPrivatePtr priv = vm->privateData;
2031
    virErrorPtr orig_err;
2032 2033
    virDomainDefPtr vmdef = vm->def;
    char *devstr = NULL;
2034
    virDomainChrSourceDefPtr dev = chr->source;
2035
    char *charAlias = NULL;
2036
    bool chardevAttached = false;
2037
    bool teardowncgroup = false;
2038
    bool teardowndevice = false;
2039
    char *tlsAlias = NULL;
2040
    char *secAlias = NULL;
2041
    bool need_release = false;
2042

2043 2044 2045 2046
    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
        qemuDomainPrepareChannel(chr, priv->channelTargetDir) < 0)
        goto cleanup;

2047
    if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0)
2048
        goto cleanup;
2049

2050
    if ((rc = qemuDomainAttachChrDeviceAssignAddr(vm, chr, driver)) < 0)
2051 2052 2053
        goto cleanup;
    if (rc == 1)
        need_release = true;
2054

2055 2056 2057 2058
    if (qemuDomainNamespaceSetupChardev(driver, vm, chr) < 0)
        goto cleanup;
    teardowndevice = true;

2059 2060 2061 2062
    if (qemuSetupChardevCgroup(vm, chr) < 0)
        goto cleanup;
    teardowncgroup = true;

2063
    if (qemuBuildChrDeviceStr(&devstr, vmdef, chr, priv->qemuCaps) < 0)
2064
        goto cleanup;
2065

2066
    if (!(charAlias = qemuAliasChardevFromDevAlias(chr->info.alias)))
2067 2068
        goto cleanup;

2069
    if (qemuDomainChrPreInsert(vmdef, chr) < 0)
2070 2071
        goto cleanup;

2072
    if (qemuDomainAddChardevTLSObjects(conn, driver, vm, dev,
2073
                                       chr->info.alias, charAlias,
2074
                                       &tlsAlias, &secAlias) < 0)
2075
        goto audit;
2076

2077
    qemuDomainObjEnterMonitor(driver, vm);
2078

2079
    if (qemuMonitorAttachCharDev(priv->mon, charAlias, chr->source) < 0)
2080 2081
        goto exit_monitor;
    chardevAttached = true;
2082 2083

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2084
        goto exit_monitor;
2085

2086 2087
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto audit;
2088

2089
    qemuDomainChrInsertPreAlloced(vmdef, chr);
2090
    ret = 0;
2091 2092
 audit:
    virDomainAuditChardev(vm, NULL, chr, "attach", ret == 0);
2093
 cleanup:
2094 2095 2096 2097 2098 2099 2100
    if (ret < 0) {
        if (virDomainObjIsActive(vm))
            qemuDomainChrInsertPreAllocCleanup(vmdef, chr);
        if (need_release)
            qemuDomainReleaseDeviceAddress(vm, &chr->info, NULL);
        if (teardowncgroup && qemuTeardownChardevCgroup(vm, chr) < 0)
            VIR_WARN("Unable to remove chr device cgroup ACL on hotplug fail");
2101 2102
        if (teardowndevice && qemuDomainNamespaceTeardownChardev(driver, vm, chr) < 0)
            VIR_WARN("Unable to remove chr device from /dev");
2103
    }
2104
    VIR_FREE(tlsAlias);
2105
    VIR_FREE(secAlias);
2106 2107 2108
    VIR_FREE(charAlias);
    VIR_FREE(devstr);
    return ret;
2109

2110
 exit_monitor:
2111
    virErrorPreserveLast(&orig_err);
2112
    /* detach associated chardev on error */
2113 2114
    if (chardevAttached)
        qemuMonitorDetachCharDev(priv->mon, charAlias);
2115
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2116
    virErrorRestore(&orig_err);
2117

2118 2119
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2120
    goto audit;
2121 2122
}

2123 2124

int
2125 2126
qemuDomainAttachRNGDevice(virConnectPtr conn,
                          virQEMUDriverPtr driver,
2127 2128 2129 2130
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
2131
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_RNG, { .rng = rng } };
2132
    virErrorPtr orig_err;
2133 2134 2135
    char *devstr = NULL;
    char *charAlias = NULL;
    char *objAlias = NULL;
2136
    char *tlsAlias = NULL;
2137
    char *secAlias = NULL;
2138
    bool releaseaddr = false;
2139
    bool teardowncgroup = false;
2140
    bool teardowndevice = false;
2141 2142
    bool chardevAdded = false;
    bool objAdded = false;
2143
    virJSONValuePtr props = NULL;
2144
    virDomainCCWAddressSetPtr ccwaddrs = NULL;
2145 2146
    const char *type;
    int ret = -1;
2147
    int rv;
2148

2149
    if (qemuAssignDeviceRNGAlias(vm->def, rng) < 0)
2150
        goto cleanup;
2151 2152 2153

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

    if (rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
2157
        if (qemuDomainIsS390CCW(vm->def) &&
2158 2159 2160 2161 2162
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
            rng->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW;
        } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_S390)) {
            rng->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390;
        }
2163 2164 2165
    } else {
        if (!qemuCheckCCWS390AddressSupport(vm->def, rng->info, priv->qemuCaps,
                                            rng->source.file))
2166
            goto cleanup;
2167 2168 2169 2170
    }

    if (rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
        rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
2171
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
2172
            goto cleanup;
2173
    } else if (rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
2174 2175 2176
        if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
            goto cleanup;
        if (virDomainCCWAddressAssign(&rng->info, ccwaddrs,
2177
                                      !rng->info.addr.ccw.assigned) < 0)
2178
            goto cleanup;
2179
    }
2180
    releaseaddr = true;
2181

2182 2183 2184 2185
    if (qemuDomainNamespaceSetupRNG(driver, vm, rng) < 0)
        goto cleanup;
    teardowndevice = true;

2186 2187 2188 2189
    if (qemuSetupRNGCgroup(vm, rng) < 0)
        goto cleanup;
    teardowncgroup = true;

2190 2191 2192 2193 2194 2195 2196 2197 2198 2199
    /* build required metadata */
    if (!(devstr = qemuBuildRNGDevStr(vm->def, rng, priv->qemuCaps)))
        goto cleanup;

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

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

2200
    if (!(charAlias = qemuAliasChardevFromDevAlias(rng->info.alias)))
2201 2202
        goto cleanup;

2203
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD) {
2204
        if (qemuDomainAddChardevTLSObjects(conn, driver, vm,
2205 2206 2207
                                           rng->source.chardev,
                                           rng->info.alias, charAlias,
                                           &tlsAlias, &secAlias) < 0)
2208
            goto audit;
2209 2210
    }

2211
    qemuDomainObjEnterMonitor(driver, vm);
2212

2213 2214 2215
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD &&
        qemuMonitorAttachCharDev(priv->mon, charAlias,
                                 rng->source.chardev) < 0)
2216 2217
        goto exit_monitor;
    chardevAdded = true;
2218

2219 2220 2221 2222 2223
    rv = qemuMonitorAddObject(priv->mon, type, objAlias, props);
    props = NULL; /* qemuMonitorAddObject consumes */
    if (rv < 0)
        goto exit_monitor;
    objAdded = true;
2224 2225

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2226
        goto exit_monitor;
2227 2228

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

2233
    VIR_APPEND_ELEMENT_INPLACE(vm->def->rngs, vm->def->nrngs, rng);
2234 2235 2236 2237 2238 2239

    ret = 0;

 audit:
    virDomainAuditRNG(vm, NULL, rng, "attach", ret == 0);
 cleanup:
2240
    virJSONValueFree(props);
2241 2242 2243 2244 2245
    if (ret < 0) {
        if (releaseaddr)
            qemuDomainReleaseDeviceAddress(vm, &rng->info, NULL);
        if (teardowncgroup && qemuTeardownRNGCgroup(vm, rng) < 0)
            VIR_WARN("Unable to remove RNG device cgroup ACL on hotplug fail");
2246 2247
        if (teardowndevice && qemuDomainNamespaceTeardownRNG(driver, vm, rng) < 0)
            VIR_WARN("Unable to remove chr device from /dev");
2248 2249
    }

2250
    VIR_FREE(tlsAlias);
2251
    VIR_FREE(secAlias);
2252 2253 2254
    VIR_FREE(charAlias);
    VIR_FREE(objAlias);
    VIR_FREE(devstr);
2255
    virDomainCCWAddressSetFree(ccwaddrs);
2256 2257
    return ret;

2258
 exit_monitor:
2259
    virErrorPreserveLast(&orig_err);
2260 2261 2262
    if (objAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, objAlias));
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD && chardevAdded)
2263
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
2264 2265
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        releaseaddr = false;
2266
    virErrorRestore(&orig_err);
2267

2268 2269
    qemuDomainDelTLSObjects(driver, vm, QEMU_ASYNC_JOB_NONE,
                            secAlias, tlsAlias);
2270 2271 2272 2273
    goto audit;
}


2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289
/**
 * 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;
2290
    virErrorPtr orig_err;
2291
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
2292
    unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
2293
    unsigned long long newmem = oldmem + mem->size;
2294 2295 2296
    char *devstr = NULL;
    char *objalias = NULL;
    const char *backendType;
2297
    bool objAdded = false;
M
Michal Privoznik 已提交
2298
    bool teardownlabel = false;
2299
    bool teardowncgroup = false;
M
Michal Privoznik 已提交
2300
    bool teardowndevice = false;
2301
    virJSONValuePtr props = NULL;
2302
    virObjectEventPtr event;
2303 2304
    int id;
    int ret = -1;
2305
    int rv;
2306

2307 2308 2309
    qemuDomainMemoryDeviceAlignSize(vm->def, mem);

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

2312 2313 2314
    if (qemuDomainAssignMemoryDeviceSlot(vm->def, mem) < 0)
        goto cleanup;

2315 2316 2317
    /* 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)
2318 2319 2320 2321 2322
        goto cleanup;

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

2323
    if (!(devstr = qemuBuildMemoryDeviceStr(mem)))
2324 2325
        goto cleanup;

2326 2327
    if (qemuBuildMemoryBackendStr(&props, &backendType, cfg,
                                  priv->qemuCaps, vm->def, mem, NULL, true) < 0)
2328 2329
        goto cleanup;

2330 2331 2332
    if (qemuProcessBuildDestroyHugepagesPath(driver, vm, mem, true) < 0)
        goto cleanup;

M
Michal Privoznik 已提交
2333 2334 2335 2336
    if (qemuDomainNamespaceSetupMemory(driver, vm, mem) < 0)
        goto cleanup;
    teardowndevice = true;

2337 2338 2339 2340
    if (qemuSetupMemoryDevicesCgroup(vm, mem) < 0)
        goto cleanup;
    teardowncgroup = true;

M
Michal Privoznik 已提交
2341
    if (qemuSecuritySetMemoryLabel(driver, vm, mem) < 0)
2342
        goto cleanup;
M
Michal Privoznik 已提交
2343
    teardownlabel = true;
2344

M
Michal Privoznik 已提交
2345 2346 2347 2348
    if (virDomainMemoryInsert(vm->def, mem) < 0)
        goto cleanup;

    if (qemuDomainAdjustMaxMemLock(vm) < 0)
2349 2350
        goto removedef;

2351
    qemuDomainObjEnterMonitor(driver, vm);
2352 2353 2354
    rv = qemuMonitorAddObject(priv->mon, backendType, objalias, props);
    props = NULL; /* qemuMonitorAddObject consumes */
    if (rv < 0)
2355
        goto exit_monitor;
2356
    objAdded = true;
2357

2358
    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2359
        goto exit_monitor;
2360 2361 2362 2363

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

2367
    event = virDomainEventDeviceAddedNewFromObj(vm, objalias);
2368
    qemuDomainEventQueue(driver, event);
2369

2370 2371
    /* fix the balloon size */
    ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));
2372

2373 2374 2375 2376 2377 2378 2379 2380 2381
    /* 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;

2382 2383
 audit:
    virDomainAuditMemory(vm, oldmem, newmem, "update", ret == 0);
2384
 cleanup:
M
Michal Privoznik 已提交
2385
    if (mem && ret < 0) {
2386 2387
        if (teardowncgroup && qemuTeardownMemoryDevicesCgroup(vm, mem) < 0)
            VIR_WARN("Unable to remove memory device cgroup ACL on hotplug fail");
M
Michal Privoznik 已提交
2388 2389
        if (teardownlabel && qemuSecurityRestoreMemoryLabel(driver, vm, mem) < 0)
            VIR_WARN("Unable to restore security label on memdev");
M
Michal Privoznik 已提交
2390 2391 2392
        if (teardowndevice &&
            qemuDomainNamespaceTeardownMemory(driver, vm, mem) <  0)
            VIR_WARN("Unable to remove memory device from /dev");
M
Michal Privoznik 已提交
2393 2394 2395
    }

    virJSONValueFree(props);
2396 2397 2398 2399 2400 2401
    virObjectUnref(cfg);
    VIR_FREE(devstr);
    VIR_FREE(objalias);
    virDomainMemoryDefFree(mem);
    return ret;

2402
 exit_monitor:
2403
    virErrorPreserveLast(&orig_err);
2404 2405
    if (objAdded)
        ignore_value(qemuMonitorDelObject(priv->mon, objalias));
2406 2407
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        mem = NULL;
2408
    virErrorRestore(&orig_err);
2409
    if (!mem)
2410
        goto audit;
2411

2412
 removedef:
2413 2414 2415 2416 2417
    if ((id = virDomainMemoryFindByDef(vm->def, mem)) >= 0)
        mem = virDomainMemoryRemove(vm->def, id);
    else
        mem = NULL;

2418
    /* reset the mlock limit */
2419
    virErrorPreserveLast(&orig_err);
2420
    ignore_value(qemuDomainAdjustMaxMemLock(vm));
2421
    virErrorRestore(&orig_err);
2422

2423
    goto audit;
2424 2425 2426
}


2427
static int
2428
qemuDomainAttachHostUSBDevice(virQEMUDriverPtr driver,
2429 2430
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
2431 2432 2433
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *devstr = NULL;
2434
    bool releaseaddr = false;
2435
    bool added = false;
2436
    bool teardowncgroup = false;
2437
    bool teardownlabel = false;
2438
    bool teardowndevice = false;
2439 2440
    int ret = -1;

2441 2442 2443 2444 2445 2446
    if (priv->usbaddrs) {
        if (virDomainUSBAddressEnsure(priv->usbaddrs, hostdev->info) < 0)
            goto cleanup;
        releaseaddr = true;
    }

2447
    if (qemuHostdevPrepareUSBDevices(driver, vm->def->name, &hostdev, 1, 0) < 0)
2448 2449 2450
        goto cleanup;

    added = true;
2451

2452 2453 2454 2455
    if (qemuDomainNamespaceSetupHostdev(driver, vm, hostdev) < 0)
        goto cleanup;
    teardowndevice = true;

2456
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
2457 2458 2459
        goto cleanup;
    teardowncgroup = true;

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

2464 2465 2466 2467
    if (qemuAssignDeviceHostdevAlias(vm->def, &hostdev->info->alias, -1) < 0)
        goto cleanup;
    if (!(devstr = qemuBuildUSBHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
        goto cleanup;
2468

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

2472
    qemuDomainObjEnterMonitor(driver, vm);
2473
    ret = qemuMonitorAddDevice(priv->mon, devstr);
2474 2475 2476 2477
    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
        ret = -1;
        goto cleanup;
    }
2478
    virDomainAuditHostdev(vm, hostdev, "attach", ret == 0);
2479
    if (ret < 0)
2480
        goto cleanup;
2481 2482 2483

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

2484
    ret = 0;
2485
 cleanup:
2486 2487 2488 2489
    if (ret < 0) {
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
        if (teardownlabel &&
2490
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2491
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2492 2493 2494
        if (teardowndevice &&
            qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device from /dev");
2495
        if (added)
2496
            qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
2497 2498
        if (releaseaddr)
            virDomainUSBAddressRelease(priv->usbaddrs, hostdev->info);
2499
    }
2500
    VIR_FREE(devstr);
2501
    return ret;
2502 2503
}

2504

2505
static int
2506 2507
qemuDomainAttachHostSCSIDevice(virConnectPtr conn,
                               virQEMUDriverPtr driver,
2508 2509 2510
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
2511
    size_t i;
2512 2513
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
2514
    virErrorPtr orig_err;
2515 2516
    char *devstr = NULL;
    char *drvstr = NULL;
2517
    char *drivealias = NULL;
2518
    bool teardowncgroup = false;
2519
    bool teardownlabel = false;
2520
    bool teardowndevice = false;
2521
    bool driveAdded = false;
2522

2523
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
2524 2525 2526 2527 2528
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("SCSI passthrough is not supported by this version of qemu"));
        return -1;
    }

2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539
    /* 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;
    }
2540

2541
    if (qemuHostdevPrepareSCSIDevices(driver, vm->def->name, &hostdev, 1) < 0)
2542 2543
        return -1;

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

2548
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
2549 2550 2551
        goto cleanup;
    teardowncgroup = true;

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

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

J
John Ferlan 已提交
2559
    if (qemuDomainSecretHostdevPrepare(conn, priv, hostdev) < 0)
2560 2561
        goto cleanup;

2562
    if (!(drvstr = qemuBuildSCSIHostdevDrvStr(hostdev)))
2563 2564
        goto cleanup;

2565 2566 2567
    if (!(drivealias = qemuAliasFromHostdev(hostdev)))
        goto cleanup;

2568 2569 2570
    if (!(devstr = qemuBuildSCSIHostdevDevStr(vm->def, hostdev, priv->qemuCaps)))
        goto cleanup;

2571
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
2572 2573 2574 2575
        goto cleanup;

    qemuDomainObjEnterMonitor(driver, vm);

2576
    if (qemuMonitorAddDrive(priv->mon, drvstr) < 0)
2577 2578
        goto exit_monitor;
    driveAdded = true;
2579 2580

    if (qemuMonitorAddDevice(priv->mon, devstr) < 0)
2581
        goto exit_monitor;
2582 2583

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

    virDomainAuditHostdev(vm, hostdev, "attach", true);
2587 2588 2589 2590

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

    ret = 0;
2591

2592
 cleanup:
2593
    qemuDomainSecretHostdevDestroy(hostdev);
2594
    if (ret < 0) {
2595
        qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
2596 2597
        if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device cgroup ACL on hotplug fail");
2598
        if (teardownlabel &&
2599
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2600
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2601 2602 2603
        if (teardowndevice &&
            qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device from /dev");
2604
    }
2605
    VIR_FREE(drivealias);
2606 2607 2608
    VIR_FREE(drvstr);
    VIR_FREE(devstr);
    return ret;
2609

2610
 exit_monitor:
2611
    virErrorPreserveLast(&orig_err);
2612
    if (driveAdded && qemuMonitorDriveDel(priv->mon, drivealias) < 0) {
2613 2614 2615
        VIR_WARN("Unable to remove drive %s (%s) after failed "
                 "qemuMonitorAddDevice",
                 drvstr, devstr);
2616
    }
2617
    ignore_value(qemuDomainObjExitMonitor(driver, vm));
2618
    virErrorRestore(&orig_err);
2619 2620 2621 2622

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

    goto cleanup;
2623 2624
}

2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639
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;
2640
    bool teardowndevice = false;
2641 2642 2643 2644 2645 2646 2647 2648
    bool releaseaddr = false;

    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_SCSI_GENERIC)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("SCSI passthrough is not supported by this version of qemu"));
        return -1;
    }

2649
    if (qemuHostdevPrepareSCSIVHostDevices(driver, vm->def->name, &hostdev, 1) < 0)
2650 2651
        return -1;

2652 2653 2654 2655
    if (qemuDomainNamespaceSetupHostdev(driver, vm, hostdev) < 0)
        goto cleanup;
    teardowndevice = true;

2656 2657 2658 2659
    if (qemuSetupHostdevCgroup(vm, hostdev) < 0)
        goto cleanup;
    teardowncgroup = true;

2660
    if (qemuSecuritySetHostdevLabel(driver, vm, hostdev) < 0)
2661 2662 2663 2664 2665 2666 2667 2668 2669 2670
        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) {
2671
        if (qemuDomainIsS390CCW(vm->def) &&
2672 2673 2674 2675 2676 2677
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW))
            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) {
2678
        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718
            goto cleanup;
    } else if (hostdev->info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
        if (!(ccwaddrs = qemuDomainCCWAddrSetCreateFromDomain(vm->def)))
            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);

    ret = qemuMonitorAddDeviceWithFd(priv->mon, devstr, vhostfd, vhostfdName);

    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 &&
2719
            qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
2720
            VIR_WARN("Unable to restore host device labelling on hotplug fail");
2721 2722 2723
        if (teardowndevice &&
            qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
            VIR_WARN("Unable to remove host device from /dev");
2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735
        if (releaseaddr)
            qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
    }

    virDomainCCWAddressSetFree(ccwaddrs);

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

2736 2737 2738 2739 2740 2741

int
qemuDomainAttachHostDevice(virConnectPtr conn,
                           virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainHostdevDefPtr hostdev)
2742 2743
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
2744
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2745
                       _("hotplug is not supported for hostdev mode '%s'"),
2746
                       virDomainHostdevModeTypeToString(hostdev->mode));
2747 2748 2749 2750 2751
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
2752
        if (qemuDomainAttachHostPCIDevice(driver, vm,
2753
                                          hostdev) < 0)
2754 2755 2756 2757
            goto error;
        break;

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
2758
        if (qemuDomainAttachHostUSBDevice(driver, vm,
2759
                                          hostdev) < 0)
2760 2761 2762
            goto error;
        break;

2763
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
2764
        if (qemuDomainAttachHostSCSIDevice(conn, driver, vm,
2765 2766 2767 2768
                                           hostdev) < 0)
            goto error;
        break;

2769 2770 2771 2772 2773
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
        if (qemuDomainAttachSCSIVHostDevice(driver, vm, hostdev) < 0)
            goto error;
        break;

2774
    default:
2775
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2776
                       _("hotplug is not supported for hostdev subsys type '%s'"),
2777
                       virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
2778 2779 2780 2781 2782
        goto error;
    }

    return 0;

2783
 error:
2784 2785 2786
    return -1;
}

2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801

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;
2802
    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_SHMEM, { .shmem = shmem } };
2803 2804 2805 2806 2807 2808 2809 2810 2811 2812

    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 已提交
2813
        ATTRIBUTE_FALLTHROUGH;
2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828
    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) &&
2829
        (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0))
2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892
        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;

        if (virAsprintf(&memAlias, "shmmem-%s", shmem->info.alias) < 0)
            goto cleanup;
    }

    qemuDomainObjEnterMonitor(driver, vm);

    if (shmem->server.enabled) {
        if (qemuMonitorAttachCharDev(priv->mon, charAlias,
                                     &shmem->server.chr) < 0)
            goto exit_monitor;
    } else {
        if (qemuMonitorAddObject(priv->mon, "memory-backend-file",
                                 memAlias, props) < 0) {
            props = NULL;
            goto exit_monitor;
        }
        props = NULL;
    }

    release_backing = true;

    if (qemuMonitorAddDevice(priv->mon, shmstr) < 0)
        goto exit_monitor;

    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)
        qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);

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

    return ret;

 exit_monitor:
2893
    virErrorPreserveLast(&orig_err);
2894 2895 2896 2897 2898 2899 2900
    if (release_backing) {
        if (shmem->server.enabled)
            ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
        else
            ignore_value(qemuMonitorDelObject(priv->mon, memAlias));
    }

2901 2902 2903
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        release_address = false;

2904
    virErrorRestore(&orig_err);
2905 2906 2907 2908 2909

    goto audit;
}


M
Michal Privoznik 已提交
2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981
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 (!(watchdogstr = qemuBuildWatchdogDevStr(vm->def, watchdog, priv->qemuCaps)))
        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;
    }

    /* 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)
        qemuDomainReleaseDeviceAddress(vm, &watchdog->info, NULL);
    VIR_FREE(watchdogstr);
    return ret;
}


2982
static int
2983
qemuDomainChangeNetBridge(virDomainObjPtr vm,
2984 2985
                          virDomainNetDefPtr olddev,
                          virDomainNetDefPtr newdev)
2986 2987
{
    int ret = -1;
2988 2989
    const char *oldbridge = virDomainNetGetActualBridgeName(olddev);
    const char *newbridge = virDomainNetGetActualBridgeName(newdev);
2990

2991 2992
    if (!oldbridge || !newbridge) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
2993
        goto cleanup;
2994
    }
2995 2996 2997 2998 2999

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

    if (virNetDevExists(newbridge) != 1) {
3000 3001
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("bridge %s doesn't exist"), newbridge);
3002
        goto cleanup;
3003 3004 3005 3006 3007
    }

    if (oldbridge) {
        ret = virNetDevBridgeRemovePort(oldbridge, olddev->ifname);
        virDomainAuditNet(vm, olddev, NULL, "detach", ret == 0);
3008 3009 3010 3011 3012 3013 3014 3015
        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);
        }
3016 3017 3018
    }

    ret = virNetDevBridgeAddPort(newbridge, olddev->ifname);
3019
    virDomainAuditNet(vm, NULL, newdev, "attach", ret == 0);
3020 3021 3022 3023
    if (ret < 0) {
        ret = virNetDevBridgeAddPort(oldbridge, olddev->ifname);
        virDomainAuditNet(vm, NULL, olddev, "attach", ret == 0);
        if (ret < 0) {
3024
            virReportError(VIR_ERR_OPERATION_FAILED,
3025
                           _("unable to recover former state by adding port "
3026
                             "to bridge %s"), oldbridge);
3027
        }
3028
        goto cleanup;
3029
    }
3030 3031
    /* caller will replace entire olddev with newdev in domain nets list */
    ret = 0;
3032
 cleanup:
3033
    return ret;
3034 3035
}

3036
static int
3037
qemuDomainChangeNetFilter(virDomainObjPtr vm,
3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055
                          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:
    case VIR_DOMAIN_NET_TYPE_NETWORK:
        break;
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("filters not supported on interfaces of type %s"),
                       virDomainNetTypeToString(virDomainNetGetActualType(newdev)));
        return -1;
    }

    virDomainConfNWFilterTeardown(olddev);

3056
    if (newdev->filter &&
3057
        virDomainConfNWFilterInstantiate(vm->def->uuid, newdev) < 0) {
3058 3059 3060 3061 3062 3063
        virErrorPtr errobj;

        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to add new filter rules to '%s' "
                         "- attempting to restore old rules"),
                       olddev->ifname);
3064
        virErrorPreserveLast(&errobj);
3065
        ignore_value(virDomainConfNWFilterInstantiate(vm->def->uuid, olddev));
3066
        virErrorRestore(&errobj);
3067 3068 3069 3070 3071
        return -1;
    }
    return 0;
}

3072
int qemuDomainChangeNetLinkState(virQEMUDriverPtr driver,
3073 3074 3075 3076 3077 3078 3079 3080
                                 virDomainObjPtr vm,
                                 virDomainNetDefPtr dev,
                                 int linkstate)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if (!dev->info.alias) {
3081 3082
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("can't change link state: device alias not found"));
3083 3084 3085
        return -1;
    }

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

3088
    qemuDomainObjEnterMonitor(driver, vm);
3089 3090 3091 3092 3093 3094 3095 3096

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

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

3097
 cleanup:
3098 3099
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        return -1;
3100 3101 3102 3103

    return ret;
}

3104
int
3105
qemuDomainChangeNet(virQEMUDriverPtr driver,
3106 3107
                    virDomainObjPtr vm,
                    virDomainDeviceDefPtr dev)
3108
{
3109
    virDomainNetDefPtr newdev = dev->data.net;
3110
    virDomainNetDefPtr *devslot = NULL;
3111
    virDomainNetDefPtr olddev;
3112
    virDomainNetType oldType, newType;
3113 3114
    bool needReconnect = false;
    bool needBridgeChange = false;
3115
    bool needFilterChange = false;
3116 3117
    bool needLinkStateChange = false;
    bool needReplaceDevDef = false;
3118
    bool needBandwidthSet = false;
3119
    bool needCoalesceChange = false;
3120
    bool needVlanUpdate = false;
3121
    int ret = -1;
3122 3123 3124 3125 3126
    int changeidx = -1;

    if ((changeidx = virDomainNetFindIdx(vm->def, newdev)) < 0)
        goto cleanup;
    devslot = &vm->def->nets[changeidx];
3127

3128
    if (!(olddev = *devslot)) {
3129
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3130
                       _("cannot find existing network device to modify"));
3131 3132 3133 3134 3135 3136
        goto cleanup;
    }

    oldType = virDomainNetGetActualType(olddev);
    if (oldType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* no changes are possible to a type='hostdev' interface */
3137
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159
                       _("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];

3160
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3161 3162 3163 3164 3165 3166 3167 3168
                       _("cannot change network interface mac address "
                         "from %s to %s"),
                       virMacAddrFormat(&olddev->mac, oldmac),
                       virMacAddrFormat(&newdev->mac, newmac));
        goto cleanup;
    }

    if (STRNEQ_NULLABLE(olddev->model, newdev->model)) {
3169
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3170 3171 3172 3173
                       _("cannot modify network device model from %s to %s"),
                       olddev->model ? olddev->model : "(default)",
                       newdev->model ? newdev->model : "(default)");
        goto cleanup;
3174 3175
    }

3176 3177 3178 3179
    if (olddev->model && STREQ(olddev->model, "virtio") &&
        (olddev->driver.virtio.name != newdev->driver.virtio.name ||
         olddev->driver.virtio.txmode != newdev->driver.virtio.txmode ||
         olddev->driver.virtio.ioeventfd != newdev->driver.virtio.ioeventfd ||
3180
         olddev->driver.virtio.event_idx != newdev->driver.virtio.event_idx ||
3181
         olddev->driver.virtio.queues != newdev->driver.virtio.queues ||
3182 3183
         olddev->driver.virtio.rx_queue_size != newdev->driver.virtio.rx_queue_size ||
         olddev->driver.virtio.tx_queue_size != newdev->driver.virtio.tx_queue_size ||
3184 3185 3186 3187 3188 3189
         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 已提交
3190
         olddev->driver.virtio.host.mrg_rxbuf != newdev->driver.virtio.host.mrg_rxbuf ||
3191 3192 3193 3194 3195
         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)) {
3196
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3197 3198 3199 3200 3201 3202 3203 3204 3205 3206
                       _("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;
3207 3208
    }

3209
    if (STRNEQ_NULLABLE(olddev->script, newdev->script)) {
3210
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3211 3212
                       _("cannot modify network device script attribute"));
        goto cleanup;
3213 3214
    }

3215
    /* ifname: check if it's set in newdev. If not, retain the autogenerated one */
3216
    if (!newdev->ifname && VIR_STRDUP(newdev->ifname, olddev->ifname) < 0)
3217 3218
        goto cleanup;
    if (STRNEQ_NULLABLE(olddev->ifname, newdev->ifname)) {
3219
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3220 3221 3222
                       _("cannot modify network device tap name"));
        goto cleanup;
    }
3223

3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234
    /* info: if newdev->info is empty, fill it in from olddev,
     * otherwise verify that it matches - nothing is allowed to
     * change. (There is no helper function to do this, so
     * individually check the few feidls of virDomainDeviceInfo that
     * are relevant in this case).
     */
    if (!virDomainDeviceAddressIsValid(&newdev->info,
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
        virDomainDeviceInfoCopy(&newdev->info, &olddev->info) < 0) {
        goto cleanup;
    }
3235
    if (!virPCIDeviceAddressEqual(&olddev->info.addr.pci,
3236
                                  &newdev->info.addr.pci)) {
3237
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3238 3239 3240 3241
                       _("cannot modify network device guest PCI address"));
        goto cleanup;
    }
    /* grab alias from olddev if not set in newdev */
3242 3243
    if (!newdev->info.alias &&
        VIR_STRDUP(newdev->info.alias, olddev->info.alias) < 0)
3244 3245
        goto cleanup;
    if (STRNEQ_NULLABLE(olddev->info.alias, newdev->info.alias)) {
3246
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3247 3248 3249 3250
                       _("cannot modify network device alias"));
        goto cleanup;
    }
    if (olddev->info.rombar != newdev->info.rombar) {
3251
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3252 3253 3254 3255
                       _("cannot modify network device rom bar setting"));
        goto cleanup;
    }
    if (STRNEQ_NULLABLE(olddev->info.romfile, newdev->info.romfile)) {
3256
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3257 3258 3259 3260
                       _("cannot modify network rom file"));
        goto cleanup;
    }
    if (olddev->info.bootIndex != newdev->info.bootIndex) {
3261
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3262 3263 3264 3265
                       _("cannot modify network device boot index setting"));
        goto cleanup;
    }
    /* (end of device info checks) */
3266

3267 3268 3269 3270
    if (STRNEQ_NULLABLE(olddev->filter, newdev->filter) ||
        !virNWFilterHashTableEqual(olddev->filterparams, newdev->filterparams)) {
        needFilterChange = true;
    }
3271

3272 3273 3274 3275
    /* bandwidth can be modified, and will be checked later */
    /* vlan can be modified, and will be checked later */
    /* linkstate can be modified */

3276 3277 3278 3279 3280 3281
    if (olddev->mtu != newdev->mtu) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("cannot modify MTU"));
        goto cleanup;
    }

3282 3283 3284 3285
    /* allocate new actual device to compare to old - we will need to
     * free it if we fail for any reason
     */
    if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK &&
3286
        networkAllocateActualDevice(vm->def, newdev) < 0) {
3287 3288 3289 3290 3291 3292 3293
        goto cleanup;
    }

    newType = virDomainNetGetActualType(newdev);

    if (newType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* can't turn it into a type='hostdev' interface */
3294
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3295 3296 3297 3298 3299 3300
                       _("cannot change network interface type to '%s'"),
                       virDomainNetTypeToString(newType));
        goto cleanup;
    }

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

3302 3303 3304 3305 3306 3307
        /* 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:
3308
            break;
3309

3310 3311 3312
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
3313
        case VIR_DOMAIN_NET_TYPE_UDP:
3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346
            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;

        default:
3347
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3348 3349 3350
                           _("unable to change config on '%s' network type"),
                           virDomainNetTypeToString(newdev->type));
            break;
3351

3352
        }
3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383
    } 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;
3384 3385

        }
3386
    }
3387

3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398
    /* 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;
    }
3399

3400 3401
    if (STRNEQ_NULLABLE(virDomainNetGetActualDirectDev(olddev),
                        virDomainNetGetActualDirectDev(newdev)) ||
3402
        virDomainNetGetActualDirectMode(olddev) != virDomainNetGetActualDirectMode(newdev) ||
3403
        !virNetDevVPortProfileEqual(virDomainNetGetActualVirtPortProfile(olddev),
3404
                                    virDomainNetGetActualVirtPortProfile(newdev))) {
3405
        needReconnect = true;
3406 3407
    }

3408 3409 3410 3411 3412
    if (!virNetDevVlanEqual(virDomainNetGetActualVlan(olddev),
                             virDomainNetGetActualVlan(newdev))) {
        needVlanUpdate = true;
    }

3413 3414 3415
    if (olddev->linkstate != newdev->linkstate)
        needLinkStateChange = true;

3416 3417 3418 3419
    if (!virNetDevBandwidthEqual(virDomainNetGetActualBandwidth(olddev),
                                 virDomainNetGetActualBandwidth(newdev)))
        needBandwidthSet = true;

3420 3421
    if (!!olddev->coalesce != !!newdev->coalesce ||
        (olddev->coalesce && newdev->coalesce &&
3422 3423
         memcmp(olddev->coalesce, newdev->coalesce,
                sizeof(*olddev->coalesce))))
3424 3425
        needCoalesceChange = true;

3426 3427 3428
    /* FINALLY - actually perform the required actions */

    if (needReconnect) {
3429
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
3430 3431 3432
                       _("unable to change config on '%s' network type"),
                       virDomainNetTypeToString(newdev->type));
        goto cleanup;
3433 3434
    }

3435 3436 3437
    if (needBandwidthSet) {
        if (virNetDevBandwidthSet(newdev->ifname,
                                  virDomainNetGetActualBandwidth(newdev),
3438 3439
                                  false,
                                  !virDomainNetTypeSharesHostView(newdev)) < 0)
3440 3441 3442 3443
            goto cleanup;
        needReplaceDevDef = true;
    }

3444
    if (needBridgeChange) {
3445
        if (qemuDomainChangeNetBridge(vm, olddev, newdev) < 0)
3446 3447 3448
            goto cleanup;
        /* we successfully switched to the new bridge, and we've
         * determined that the rest of newdev is equivalent to olddev,
3449 3450 3451 3452 3453
         * so move newdev into place */
        needReplaceDevDef = true;
    }

    if (needFilterChange) {
3454
        if (qemuDomainChangeNetFilter(vm, olddev, newdev) < 0)
3455 3456 3457 3458
            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 */
3459
        needReplaceDevDef = true;
3460 3461
    }

3462 3463 3464 3465 3466 3467
    if (needCoalesceChange) {
        if (virNetDevSetCoalesce(newdev->ifname, newdev->coalesce, true) < 0)
            goto cleanup;
        needReplaceDevDef = true;
    }

3468 3469 3470
    if (needLinkStateChange &&
        qemuDomainChangeNetLinkState(driver, vm, olddev, newdev->linkstate) < 0) {
        goto cleanup;
3471 3472
    }

3473 3474 3475 3476 3477 3478
    if (needVlanUpdate) {
        if (virNetDevOpenvswitchUpdateVlan(newdev->ifname, &newdev->vlan) < 0)
            goto cleanup;
        needReplaceDevDef = true;
    }

3479 3480 3481 3482
    if (needReplaceDevDef) {
        /* the changes above warrant replacing olddev with newdev in
         * the domain's nets list.
         */
3483 3484 3485

        /* this function doesn't work with HOSTDEV networks yet, thus
         * no need to change the pointer in the hostdev structure */
3486
        networkReleaseActualDevice(vm->def, olddev);
3487 3488 3489 3490 3491 3492 3493 3494
        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;
3495 3496
    }

3497
    ret = 0;
3498
 cleanup:
3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
    /* 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.
     */
    if (newdev)
3518
        networkReleaseActualDevice(vm->def, newdev);
3519

3520 3521 3522
    return ret;
}

3523 3524 3525
static virDomainGraphicsDefPtr
qemuDomainFindGraphics(virDomainObjPtr vm,
                       virDomainGraphicsDefPtr dev)
3526
{
3527
    size_t i;
3528

3529
    for (i = 0; i < vm->def->ngraphics; i++) {
3530 3531 3532 3533 3534 3535 3536
        if (vm->def->graphics[i]->type == dev->type)
            return vm->def->graphics[i];
    }

    return NULL;
}

3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550
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;
}

3551
int
3552
qemuDomainChangeGraphics(virQEMUDriverPtr driver,
3553 3554 3555 3556
                         virDomainObjPtr vm,
                         virDomainGraphicsDefPtr dev)
{
    virDomainGraphicsDefPtr olddev = qemuDomainFindGraphics(vm, dev);
3557
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3558
    const char *type = virDomainGraphicsTypeToString(dev->type);
3559
    size_t i;
3560
    int ret = -1;
3561 3562

    if (!olddev) {
3563 3564
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot find existing graphics device to modify"));
3565
        goto cleanup;
3566 3567
    }

3568
    if (dev->nListens != olddev->nListens) {
3569 3570 3571
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("cannot change the number of listen addresses "
                         "on '%s' graphics"), type);
3572 3573 3574 3575
        goto cleanup;
    }

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

J
Jim Fehlig 已提交
3579
        if (newlisten->type != oldlisten->type) {
3580 3581 3582
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                           _("cannot change the type of listen address "
                             "on '%s' graphics"), type);
3583 3584 3585
            goto cleanup;
        }

3586
        switch (newlisten->type) {
3587
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_ADDRESS:
J
Jim Fehlig 已提交
3588
            if (STRNEQ_NULLABLE(newlisten->address, oldlisten->address)) {
3589 3590 3591
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen address setting "
                                 "on '%s' graphics"), type);
3592 3593
                goto cleanup;
            }
3594

3595 3596 3597
            break;

        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NETWORK:
J
Jim Fehlig 已提交
3598
            if (STRNEQ_NULLABLE(newlisten->network, oldlisten->network)) {
3599 3600 3601
                virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                               _("cannot change listen address setting "
                                 "on '%s' graphics"), type);
3602 3603
                goto cleanup;
            }
3604

3605 3606
            break;

3607 3608 3609 3610 3611 3612 3613 3614 3615
        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;

3616 3617 3618 3619 3620 3621
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_NONE:
        case VIR_DOMAIN_GRAPHICS_LISTEN_TYPE_LAST:
            /* nada */
            break;
        }
    }
3622

3623 3624
    switch (dev->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
3625 3626 3627
        if ((olddev->data.vnc.autoport != dev->data.vnc.autoport) ||
            (!dev->data.vnc.autoport &&
             (olddev->data.vnc.port != dev->data.vnc.port))) {
3628
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3629
                           _("cannot change port settings on vnc graphics"));
3630
            goto cleanup;
3631 3632
        }
        if (STRNEQ_NULLABLE(olddev->data.vnc.keymap, dev->data.vnc.keymap)) {
3633
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3634
                           _("cannot change keymap setting on vnc graphics"));
3635
            goto cleanup;
3636 3637
        }

3638 3639 3640
        /* 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 */
3641 3642
        if (olddev->data.vnc.auth.expires ||
            dev->data.vnc.auth.expires ||
3643
            olddev->data.vnc.auth.connected != dev->data.vnc.auth.connected ||
E
Eric Blake 已提交
3644 3645 3646
            STRNEQ_NULLABLE(olddev->data.vnc.auth.passwd,
                            dev->data.vnc.auth.passwd)) {
            VIR_DEBUG("Updating password on VNC server %p %p",
3647
                      dev->data.vnc.auth.passwd, cfg->vncPassword);
E
Eric Blake 已提交
3648 3649 3650
            ret = qemuDomainChangeGraphicsPasswords(driver, vm,
                                                    VIR_DOMAIN_GRAPHICS_TYPE_VNC,
                                                    &dev->data.vnc.auth,
3651 3652
                                                    cfg->vncPassword,
                                                    QEMU_ASYNC_JOB_NONE);
3653
            if (ret < 0)
3654
                goto cleanup;
3655 3656 3657 3658 3659

            /* 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;
3660 3661
            olddev->data.vnc.auth.validTo = dev->data.vnc.auth.validTo;
            olddev->data.vnc.auth.expires = dev->data.vnc.auth.expires;
3662
            olddev->data.vnc.auth.connected = dev->data.vnc.auth.connected;
3663 3664 3665 3666 3667
        } else {
            ret = 0;
        }
        break;

3668
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
3669 3670 3671 3672 3673
        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))) {
3674
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3675
                           _("cannot change port settings on spice graphics"));
3676
            goto cleanup;
3677
        }
E
Eric Blake 已提交
3678 3679
        if (STRNEQ_NULLABLE(olddev->data.spice.keymap,
                            dev->data.spice.keymap)) {
3680
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3681
                            _("cannot change keymap setting on spice graphics"));
3682
            goto cleanup;
3683 3684
        }

3685 3686 3687 3688 3689
        /* 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"
         */
3690 3691
        if (olddev->data.spice.auth.expires ||
            dev->data.spice.auth.expires ||
3692
            olddev->data.spice.auth.connected != dev->data.spice.auth.connected ||
3693 3694
            dev->data.spice.auth.connected ==
            VIR_DOMAIN_GRAPHICS_AUTH_CONNECTED_DISCONNECT ||
E
Eric Blake 已提交
3695 3696 3697
            STRNEQ_NULLABLE(olddev->data.spice.auth.passwd,
                            dev->data.spice.auth.passwd)) {
            VIR_DEBUG("Updating password on SPICE server %p %p",
3698
                      dev->data.spice.auth.passwd, cfg->spicePassword);
E
Eric Blake 已提交
3699 3700 3701
            ret = qemuDomainChangeGraphicsPasswords(driver, vm,
                                                    VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
                                                    &dev->data.spice.auth,
3702 3703
                                                    cfg->spicePassword,
                                                    QEMU_ASYNC_JOB_NONE);
E
Eric Blake 已提交
3704

3705
            if (ret < 0)
3706
                goto cleanup;
3707

E
Eric Blake 已提交
3708
            /* Steal the new dev's char * reference */
3709 3710 3711 3712 3713
            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;
3714
            olddev->data.spice.auth.connected = dev->data.spice.auth.connected;
3715
        } else {
3716
            VIR_DEBUG("Not updating since password didn't change");
3717 3718
            ret = 0;
        }
E
Eric Blake 已提交
3719
        break;
3720

3721
    default:
3722
        virReportError(VIR_ERR_INTERNAL_ERROR,
3723
                       _("unable to change config on '%s' graphics type"), type);
3724 3725 3726
        break;
    }

3727
 cleanup:
3728
    virObjectUnref(cfg);
3729 3730 3731 3732
    return ret;
}


3733
static int qemuComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
3734
                                virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
3735
                                virDomainDeviceInfoPtr info1,
3736 3737
                                void *opaque)
{
3738
    virDomainDeviceInfoPtr info2 = opaque;
3739

3740 3741
    if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
        info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
3742 3743
        return 0;

3744 3745 3746
    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 &&
3747
        info1->addr.pci.function != info2->addr.pci.function)
3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759
        return -1;
    return 0;
}

static bool qemuIsMultiFunctionDevice(virDomainDefPtr def,
                                      virDomainDeviceInfoPtr dev)
{
    if (virDomainDeviceInfoIterate(def, qemuComparePCIDevice, dev) < 0)
        return true;
    return false;
}

3760

3761
static int
3762 3763 3764 3765 3766
qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainDiskDefPtr disk)
{
    virDomainDeviceDef dev;
3767
    virObjectEventPtr event;
3768
    size_t i;
3769
    const char *src = virDomainDiskGetSource(disk);
3770 3771
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *drivestr;
3772
    char *objAlias = NULL;
3773
    char *encAlias = NULL;
3774 3775 3776 3777

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

3778 3779
    /* build the actual drive id string as the disk->info.alias doesn't
     * contain the QEMU_DRIVE_HOST_PREFIX that is passed to qemu */
3780
    if (!(drivestr = qemuAliasFromDisk(disk)))
3781 3782
        return -1;

3783 3784 3785 3786 3787 3788 3789 3790
    /* Let's look for some markers for a secret object and create an alias
     * object to be used to attempt to delete the object that was created.
     * We cannot just use the disk private secret info since it would have
     * been removed during cleanup of qemuProcessLaunch. Likewise, libvirtd
     * restart wouldn't have them, so no assumption can be made. */
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_SECRET) &&
        qemuDomainSecretDiskCapable(disk->src)) {

3791 3792
        if (!(objAlias =
              qemuDomainGetSecretAESAlias(disk->info.alias, false))) {
3793 3794 3795 3796 3797
            VIR_FREE(drivestr);
            return -1;
        }
    }

3798 3799 3800
    /* Similarly, if this is possible a device using LUKS encryption, we
     * can remove the luks object password too
     */
3801
    if (qemuDomainDiskHasEncryptionSecret(disk->src)) {
3802 3803 3804 3805 3806 3807 3808 3809 3810

        if (!(encAlias =
              qemuDomainGetSecretAESAlias(disk->info.alias, true))) {
            VIR_FREE(objAlias);
            VIR_FREE(drivestr);
            return -1;
        }
    }

3811
    qemuDomainObjEnterMonitor(driver, vm);
3812

3813 3814 3815
    qemuMonitorDriveDel(priv->mon, drivestr);
    VIR_FREE(drivestr);

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

3821 3822 3823 3824 3825
    /* If it fails, then so be it - it was a best shot */
    if (encAlias)
        ignore_value(qemuMonitorDelObject(priv->mon, encAlias));
    VIR_FREE(encAlias);

3826 3827 3828
    if (disk->src->haveTLS)
        ignore_value(qemuMonitorDelObject(priv->mon, disk->src->tlsAlias));

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

3832
    virDomainAuditDisk(vm, disk->src, NULL, "detach", true);
3833

3834
    event = virDomainEventDeviceRemovedNewFromObj(vm, disk->info.alias);
3835
    qemuDomainEventQueue(driver, event);
3836

3837 3838 3839 3840 3841 3842 3843
    for (i = 0; i < vm->def->ndisks; i++) {
        if (vm->def->disks[i] == disk) {
            virDomainDiskRemove(vm->def, i);
            break;
        }
    }

3844
    qemuDomainReleaseDeviceAddress(vm, &disk->info, src);
3845

3846
    if (qemuSecurityRestoreDiskLabel(driver, vm, disk) < 0)
3847
        VIR_WARN("Unable to restore security label on %s", src);
3848 3849

    if (qemuTeardownDiskCgroup(vm, disk) < 0)
3850
        VIR_WARN("Failed to tear down cgroup for disk path %s", src);
3851 3852

    if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
3853
        VIR_WARN("Unable to release lock on %s", src);
3854

3855
    if (qemuDomainNamespaceTeardownDisk(driver, vm, disk->src) < 0)
3856 3857
        VIR_WARN("Unable to remove /dev entry for %s", src);

3858 3859 3860
    dev.type = VIR_DOMAIN_DEVICE_DISK;
    dev.data.disk = disk;
    ignore_value(qemuRemoveSharedDevice(driver, &dev, vm->def->name));
3861 3862
    if (priv->usbaddrs)
        virDomainUSBAddressRelease(priv->usbaddrs, &disk->info);
3863 3864

    virDomainDiskDefFree(disk);
3865
    return 0;
3866 3867 3868
}


3869
static int
3870
qemuDomainRemoveControllerDevice(virQEMUDriverPtr driver,
3871 3872 3873
                                 virDomainObjPtr vm,
                                 virDomainControllerDefPtr controller)
{
3874
    virObjectEventPtr event;
3875 3876 3877 3878 3879
    size_t i;

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

3880
    event = virDomainEventDeviceRemovedNewFromObj(vm, controller->info.alias);
3881
    qemuDomainEventQueue(driver, event);
3882

3883 3884 3885 3886 3887 3888 3889 3890 3891
    for (i = 0; i < vm->def->ncontrollers; i++) {
        if (vm->def->controllers[i] == controller) {
            virDomainControllerRemove(vm->def, i);
            break;
        }
    }

    qemuDomainReleaseDeviceAddress(vm, &controller->info, NULL);
    virDomainControllerDefFree(controller);
3892
    return 0;
3893 3894 3895
}


3896 3897 3898 3899 3900 3901
static int
qemuDomainRemoveMemoryDevice(virQEMUDriverPtr driver,
                             virDomainObjPtr vm,
                             virDomainMemoryDefPtr mem)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3902
    unsigned long long oldmem = virDomainDefGetMemoryTotal(vm->def);
3903
    unsigned long long newmem = oldmem - mem->size;
3904 3905 3906 3907 3908 3909 3910 3911 3912
    virObjectEventPtr event;
    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)
3913
        return -1;
3914 3915 3916

    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorDelObject(priv->mon, backendAlias);
3917 3918 3919 3920 3921 3922 3923 3924
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        rc = -1;

    VIR_FREE(backendAlias);

    virDomainAuditMemory(vm, oldmem, newmem, "update", rc == 0);
    if (rc < 0)
        return -1;
3925

3926 3927 3928
    event = virDomainEventDeviceRemovedNewFromObj(vm, mem->info.alias);
    qemuDomainEventQueue(driver, event);

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

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

3935 3936 3937
    if (qemuTeardownMemoryDevicesCgroup(vm, mem) < 0)
        VIR_WARN("Unable to remove memory device cgroup ACL");

M
Michal Privoznik 已提交
3938 3939 3940
    if (qemuDomainNamespaceTeardownMemory(driver, vm, mem) <  0)
        VIR_WARN("Unable to remove memory device from /dev");

3941
    virDomainMemoryDefFree(mem);
3942

3943 3944 3945
    /* fix the balloon size */
    ignore_value(qemuProcessRefreshBalloonState(driver, vm, QEMU_ASYNC_JOB_NONE));

3946
    /* decrease the mlock limit after memory unplug if necessary */
3947
    ignore_value(qemuDomainAdjustMaxMemLock(vm));
3948

3949
    return 0;
3950 3951 3952
}


3953 3954 3955 3956 3957
static void
qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainHostdevDefPtr hostdev)
{
3958
    qemuHostdevReAttachPCIDevices(driver, vm->def->name, &hostdev, 1);
3959 3960 3961 3962 3963
    qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
}

static void
qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver,
3964
                              virDomainObjPtr vm,
3965 3966
                              virDomainHostdevDefPtr hostdev)
{
3967
    qemuHostdevReAttachUSBDevices(driver, vm->def->name, &hostdev, 1);
3968
    qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
3969 3970 3971 3972 3973 3974 3975
}

static void
qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
3976
    qemuHostdevReAttachSCSIDevices(driver, vm->def->name, &hostdev, 1);
3977 3978
}

3979 3980 3981 3982 3983 3984 3985 3986
static void
qemuDomainRemoveSCSIVHostDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainHostdevDefPtr hostdev)
{
    qemuHostdevReAttachSCSIVHostDevices(driver, vm->def->name, &hostdev, 1);
}

3987
static int
3988 3989 3990 3991
qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainHostdevDefPtr hostdev)
{
3992
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3993
    virDomainNetDefPtr net = NULL;
3994
    virObjectEventPtr event;
3995
    size_t i;
3996 3997
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
J
John Ferlan 已提交
3998
    char *drivealias = NULL;
3999
    bool is_vfio = false;
4000 4001 4002 4003

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

4004 4005 4006 4007 4008
    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;
    }

4009
    if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) {
J
John Ferlan 已提交
4010
        if (!(drivealias = qemuAliasFromHostdev(hostdev)))
4011 4012 4013
            goto cleanup;

        qemuDomainObjEnterMonitor(driver, vm);
J
John Ferlan 已提交
4014
        qemuMonitorDriveDel(priv->mon, drivealias);
4015 4016
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            goto cleanup;
4017 4018
    }

4019
    event = virDomainEventDeviceRemovedNewFromObj(vm, hostdev->info->alias);
4020
    qemuDomainEventQueue(driver, event);
4021

4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041
    if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET) {
        net = hostdev->parent.data.net;

        for (i = 0; i < vm->def->nnets; i++) {
            if (vm->def->nets[i] == net) {
                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);

4042
    if (!is_vfio &&
4043
        qemuSecurityRestoreHostdevLabel(driver, vm, hostdev) < 0)
4044
        VIR_WARN("Failed to restore host device labelling");
4045

4046 4047 4048
    if (qemuTeardownHostdevCgroup(vm, hostdev) < 0)
        VIR_WARN("Failed to remove host device cgroup ACL");

4049 4050 4051
    if (qemuDomainNamespaceTeardownHostdev(driver, vm, hostdev) < 0)
        VIR_WARN("Unable to remove host device from /dev");

4052
    switch ((virDomainHostdevSubsysType) hostdev->source.subsys.type) {
4053 4054
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
        qemuDomainRemovePCIHostDevice(driver, vm, hostdev);
4055 4056 4057 4058
        /* 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");
4059 4060 4061 4062 4063 4064 4065
        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;
4066
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
4067
        qemuDomainRemoveSCSIVHostDevice(driver, vm, hostdev);
4068
        break;
4069 4070
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
        break;
4071 4072 4073 4074 4075 4076 4077
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
        break;
    }

    virDomainHostdevDefFree(hostdev);

    if (net) {
4078
        networkReleaseActualDevice(vm->def, net);
4079 4080
        virDomainNetDefFree(net);
    }
4081

4082 4083 4084
    ret = 0;

 cleanup:
J
John Ferlan 已提交
4085
    VIR_FREE(drivealias);
4086
    virObjectUnref(cfg);
4087
    return ret;
4088 4089 4090
}


4091
static int
4092 4093 4094 4095 4096
qemuDomainRemoveNetDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainNetDefPtr net)
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4097
    qemuDomainObjPrivatePtr priv = vm->privateData;
4098
    virObjectEventPtr event;
4099
    char *hostnet_name = NULL;
4100
    char *charDevAlias = NULL;
4101
    size_t i;
4102
    int ret = -1;
4103
    int actualType = virDomainNetGetActualType(net);
4104

4105
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
4106
        /* this function handles all hostdev and netdev cleanup */
4107 4108
        ret = qemuDomainRemoveHostDevice(driver, vm,
                                         virDomainNetGetActualHostdev(net));
4109
        goto cleanup;
4110 4111
    }

4112 4113 4114
    VIR_DEBUG("Removing network interface %s from domain %p %s",
              net->info.alias, vm, vm->def->name);

4115
    if (virAsprintf(&hostnet_name, "host%s", net->info.alias) < 0 ||
4116
        !(charDevAlias = qemuAliasChardevFromDevAlias(net->info.alias)))
4117 4118
        goto cleanup;

4119

4120
    qemuDomainObjEnterMonitor(driver, vm);
4121
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NETDEV)) {
4122
        if (qemuMonitorRemoveNetdev(priv->mon, hostnet_name) < 0) {
4123 4124
            if (qemuDomainObjExitMonitor(driver, vm) < 0)
                goto cleanup;
4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135
            virDomainAuditNet(vm, net, NULL, "detach", false);
            goto cleanup;
        }
    } else {
        int vlan;
        if ((vlan = qemuDomainNetVLAN(net)) < 0 ||
            qemuMonitorRemoveHostNetwork(priv->mon, vlan, hostnet_name) < 0) {
            if (vlan < 0) {
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("unable to determine original VLAN"));
            }
4136 4137
            if (qemuDomainObjExitMonitor(driver, vm) < 0)
                goto cleanup;
4138 4139 4140 4141
            virDomainAuditNet(vm, net, NULL, "detach", false);
            goto cleanup;
        }
    }
4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152

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

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

4156 4157 4158
    virDomainAuditNet(vm, net, NULL, "detach", true);

    event = virDomainEventDeviceRemovedNewFromObj(vm, net->info.alias);
4159
    qemuDomainEventQueue(driver, event);
4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170

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

    qemuDomainReleaseDeviceAddress(vm, &net->info, NULL);
    virDomainConfNWFilterTeardown(net);

4171 4172 4173 4174 4175 4176
    if (cfg->macFilter && (net->ifname != NULL)) {
        ignore_value(ebtablesRemoveForwardAllowIn(driver->ebtables,
                                                  net->ifname,
                                                  &net->mac));
    }

4177
    if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
4178 4179 4180 4181 4182 4183 4184 4185
        ignore_value(virNetDevMacVLanDeleteWithVPortProfile(
                         net->ifname, &net->mac,
                         virDomainNetGetActualDirectDev(net),
                         virDomainNetGetActualDirectMode(net),
                         virDomainNetGetActualVirtPortProfile(net),
                         cfg->stateDir));
    }

4186
    qemuDomainNetDeviceVportRemove(net);
4187

4188
    networkReleaseActualDevice(vm->def, net);
4189
    virDomainNetDefFree(net);
4190
    ret = 0;
4191 4192

 cleanup:
4193
    virObjectUnref(cfg);
4194
    VIR_FREE(charDevAlias);
4195 4196
    VIR_FREE(hostnet_name);
    return ret;
4197 4198 4199
}


4200
static int
4201
qemuDomainRemoveChrDevice(virQEMUDriverPtr driver,
4202 4203 4204
                          virDomainObjPtr vm,
                          virDomainChrDefPtr chr)
{
4205
    virObjectEventPtr event;
4206
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4207
    char *charAlias = NULL;
4208
    char *tlsAlias = NULL;
4209
    char *secAlias = NULL;
4210 4211
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;
4212
    int rc;
4213

4214 4215 4216
    VIR_DEBUG("Removing character device %s from domain %p %s",
              chr->info.alias, vm, vm->def->name);

4217
    if (!(charAlias = qemuAliasChardevFromDevAlias(chr->info.alias)))
4218 4219
        goto cleanup;

4220
    if (chr->source->type == VIR_DOMAIN_CHR_TYPE_TCP &&
4221 4222
        chr->source->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) {

4223
        if (!(tlsAlias = qemuAliasTLSObjFromSrcAlias(charAlias)))
4224 4225 4226 4227 4228 4229 4230 4231 4232 4233
            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(charAlias, false)))
            goto cleanup;
    }
4234

4235
    qemuDomainObjEnterMonitor(driver, vm);
4236
    rc = qemuMonitorDetachCharDev(priv->mon, charAlias);
4237

4238 4239 4240 4241 4242 4243
    if (rc == 0) {
        if (tlsAlias)
            ignore_value(qemuMonitorDelObject(priv->mon, tlsAlias));
        if (secAlias)
            ignore_value(qemuMonitorDelObject(priv->mon, secAlias));
    }
4244

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

4248 4249 4250 4251 4252
    virDomainAuditChardev(vm, chr, NULL, "detach", rc == 0);

    if (rc < 0)
        goto cleanup;

4253 4254 4255
    if (qemuTeardownChardevCgroup(vm, chr) < 0)
        VIR_WARN("Failed to remove chr device cgroup ACL");

4256 4257 4258
    if (qemuDomainNamespaceTeardownChardev(driver, vm, chr) < 0)
        VIR_WARN("Unable to remove chr device from /dev");

4259
    event = virDomainEventDeviceRemovedNewFromObj(vm, chr->info.alias);
4260
    qemuDomainEventQueue(driver, event);
4261

4262 4263
    qemuDomainChrRemove(vm->def, chr);
    virDomainChrDefFree(chr);
4264 4265 4266 4267
    ret = 0;

 cleanup:
    VIR_FREE(charAlias);
4268
    VIR_FREE(tlsAlias);
4269
    VIR_FREE(secAlias);
4270
    virObjectUnref(cfg);
4271
    return ret;
4272 4273 4274
}


4275 4276 4277 4278 4279 4280
static int
qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
    virObjectEventPtr event;
4281
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
4282 4283
    char *charAlias = NULL;
    char *objAlias = NULL;
4284
    char *tlsAlias = NULL;
4285
    char *secAlias = NULL;
4286 4287 4288 4289 4290 4291 4292 4293
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ssize_t idx;
    int ret = -1;
    int rc;

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

4294

4295 4296 4297
    if (virAsprintf(&objAlias, "obj%s", rng->info.alias) < 0)
        goto cleanup;

4298
    if (!(charAlias = qemuAliasChardevFromDevAlias(rng->info.alias)))
4299 4300
        goto cleanup;

4301
    if (rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD) {
4302
        if (!(tlsAlias = qemuAliasTLSObjFromSrcAlias(charAlias)))
4303 4304 4305 4306 4307 4308 4309 4310 4311 4312
            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(charAlias, false)))
            goto cleanup;
    }
4313

4314
    qemuDomainObjEnterMonitor(driver, vm);
4315

4316 4317
    rc = qemuMonitorDelObject(priv->mon, objAlias);

4318
    if (rc == 0 && rng->backend == VIR_DOMAIN_RNG_BACKEND_EGD) {
4319
        ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
4320 4321
        if (tlsAlias)
            ignore_value(qemuMonitorDelObject(priv->mon, tlsAlias));
4322 4323
        if (secAlias)
            ignore_value(qemuMonitorDelObject(priv->mon, secAlias));
4324
    }
4325 4326 4327 4328 4329 4330 4331 4332 4333

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

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

    if (rc < 0)
        goto cleanup;

4334 4335 4336
    if (qemuTeardownRNGCgroup(vm, rng) < 0)
        VIR_WARN("Failed to remove RNG device cgroup ACL");

4337 4338 4339
    if (qemuDomainNamespaceTeardownRNG(driver, vm, rng) < 0)
        VIR_WARN("Unable to remove RNG device from /dev");

4340 4341
    event = virDomainEventDeviceRemovedNewFromObj(vm, rng->info.alias);
    qemuDomainEventQueue(driver, event);
4342 4343 4344 4345 4346 4347 4348 4349 4350 4351

    if ((idx = virDomainRNGFind(vm->def, rng)) >= 0)
        virDomainRNGRemove(vm->def, idx);
    qemuDomainReleaseDeviceAddress(vm, &rng->info, NULL);
    virDomainRNGDefFree(rng);
    ret = 0;

 cleanup:
    VIR_FREE(charAlias);
    VIR_FREE(objAlias);
4352
    VIR_FREE(tlsAlias);
4353 4354
    VIR_FREE(secAlias);
    virObjectUnref(cfg);
4355 4356 4357 4358
    return ret;
}


4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414
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;
    virObjectEventPtr event = NULL;

    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;

    event = virDomainEventDeviceRemovedNewFromObj(vm, shmem->info.alias);
    qemuDomainEventQueue(driver, event);

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

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

    return ret;
}


4415
int
4416 4417 4418 4419
qemuDomainRemoveDevice(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       virDomainDeviceDefPtr dev)
{
4420
    int ret = -1;
4421 4422
    switch ((virDomainDeviceType) dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
4423
        ret = qemuDomainRemoveDiskDevice(driver, vm, dev->data.disk);
4424 4425
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
4426
        ret = qemuDomainRemoveControllerDevice(driver, vm, dev->data.controller);
4427 4428
        break;
    case VIR_DOMAIN_DEVICE_NET:
4429
        ret = qemuDomainRemoveNetDevice(driver, vm, dev->data.net);
4430 4431
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
4432
        ret = qemuDomainRemoveHostDevice(driver, vm, dev->data.hostdev);
4433 4434 4435
        break;

    case VIR_DOMAIN_DEVICE_CHR:
4436
        ret = qemuDomainRemoveChrDevice(driver, vm, dev->data.chr);
4437
        break;
4438
    case VIR_DOMAIN_DEVICE_RNG:
4439
        ret = qemuDomainRemoveRNGDevice(driver, vm, dev->data.rng);
4440
        break;
4441

4442
    case VIR_DOMAIN_DEVICE_MEMORY:
4443 4444
        ret = qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory);
        break;
4445

4446 4447 4448 4449
    case VIR_DOMAIN_DEVICE_SHMEM:
        ret = qemuDomainRemoveShmemDevice(driver, vm, dev->data.shmem);
        break;

4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462
    case VIR_DOMAIN_DEVICE_NONE:
    case VIR_DOMAIN_DEVICE_LEASE:
    case VIR_DOMAIN_DEVICE_FS:
    case VIR_DOMAIN_DEVICE_INPUT:
    case VIR_DOMAIN_DEVICE_SOUND:
    case VIR_DOMAIN_DEVICE_VIDEO:
    case VIR_DOMAIN_DEVICE_WATCHDOG:
    case VIR_DOMAIN_DEVICE_GRAPHICS:
    case VIR_DOMAIN_DEVICE_HUB:
    case VIR_DOMAIN_DEVICE_REDIRDEV:
    case VIR_DOMAIN_DEVICE_SMARTCARD:
    case VIR_DOMAIN_DEVICE_MEMBALLOON:
    case VIR_DOMAIN_DEVICE_NVRAM:
4463
    case VIR_DOMAIN_DEVICE_TPM:
4464
    case VIR_DOMAIN_DEVICE_PANIC:
J
Ján Tomko 已提交
4465
    case VIR_DOMAIN_DEVICE_IOMMU:
4466 4467 4468 4469 4470 4471
    case VIR_DOMAIN_DEVICE_LAST:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("don't know how to remove a %s device"),
                       virDomainDeviceTypeToString(dev->type));
        break;
    }
4472
    return ret;
4473 4474 4475 4476
}


static void
4477 4478
qemuDomainMarkDeviceAliasForRemoval(virDomainObjPtr vm,
                                    const char *alias)
4479 4480 4481
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

4482 4483 4484 4485 4486
    memset(&priv->unplug, 0, sizeof(priv->unplug));

    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
        return;

4487
    priv->unplug.alias = alias;
4488 4489
}

4490 4491 4492 4493 4494 4495 4496 4497 4498 4499

static void
qemuDomainMarkDeviceForRemoval(virDomainObjPtr vm,
                               virDomainDeviceInfoPtr info)

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


4500 4501 4502 4503
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4504
    priv->unplug.alias = NULL;
4505 4506 4507
}

/* Returns:
4508 4509
 *  -1 Unplug of the device failed
 *
4510 4511 4512 4513 4514 4515 4516
 *   0 DEVICE_DELETED event is supported and removal of the device did not
 *     finish in qemuDomainRemoveDeviceWaitTime
 *
 *   1 when the caller is responsible for finishing the device removal:
 *      - DEVICE_DELETED event is unsupported
 *      - DEVICE_DELETED event arrived before the timeout time
 *      - we failed to reliably wait for the event and thus use fallback behavior
4517 4518 4519 4520 4521 4522
 */
static int
qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    unsigned long long until;
4523
    int rc;
4524 4525

    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
4526
        return 1;
4527 4528

    if (virTimeMillisNow(&until) < 0)
4529
        return 1;
4530
    until += qemuDomainRemoveDeviceWaitTime;
4531

4532
    while (priv->unplug.alias) {
4533 4534 4535 4536 4537
        if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
            return 0;

        if (rc < 0) {
            VIR_WARN("Failed to wait on unplug condition for domain '%s' "
4538
                     "device '%s'", vm->def->name, priv->unplug.alias);
4539
            return 1;
4540 4541 4542
        }
    }

4543 4544 4545 4546 4547 4548
    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;
    }

4549 4550 4551
    return 1;
}

4552 4553 4554 4555 4556 4557 4558
/* 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
4559
qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
4560 4561
                              const char *devAlias,
                              qemuDomainUnpluggingDeviceStatus status)
4562 4563 4564
{
    qemuDomainObjPrivatePtr priv = vm->privateData;

4565
    if (STREQ_NULLABLE(priv->unplug.alias, devAlias)) {
4566
        VIR_DEBUG("Removal of device '%s' continues in waiting thread", devAlias);
4567
        qemuDomainResetDeviceRemoval(vm);
4568
        priv->unplug.status = status;
4569
        virDomainObjBroadcast(vm);
4570
        return true;
4571
    }
4572
    return false;
4573 4574 4575
}


4576 4577 4578 4579
static int
qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver,
                                 virDomainObjPtr vm,
                                 virDomainDiskDefPtr detach)
4580
{
4581
    int ret = -1;
4582 4583
    qemuDomainObjPrivatePtr priv = vm->privateData;

4584
    if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
4585 4586
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("cannot hot unplug multifunction PCI device: %s"),
4587
                       detach->dst);
4588 4589 4590
        goto cleanup;
    }

4591
    if (qemuDomainIsS390CCW(vm->def) &&
4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
        if (!virDomainDeviceAddressIsValid(&detach->info,
                                           VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("device cannot be detached without a valid CCW address"));
            goto cleanup;
        }
    } else {
        if (!virDomainDeviceAddressIsValid(&detach->info,
                                           VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("device cannot be detached without a valid PCI address"));
            goto cleanup;
        }
4606 4607
    }

4608
    if (!detach->info.alias) {
4609 4610 4611 4612
        if (qemuAssignDeviceDiskAlias(vm->def, detach, priv->qemuCaps) < 0)
            goto cleanup;
    }

4613 4614
    qemuDomainMarkDeviceForRemoval(vm, &detach->info);

4615
    qemuDomainObjEnterMonitor(driver, vm);
4616 4617
    if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
4618
            goto cleanup;
4619 4620
        virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
        goto cleanup;
4621
    }
4622 4623
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
4624

4625
    if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
4626
        ret = qemuDomainRemoveDiskDevice(driver, vm, detach);
4627

4628
 cleanup:
4629
    qemuDomainResetDeviceRemoval(vm);
4630 4631 4632
    return ret;
}

4633 4634 4635 4636
static int
qemuDomainDetachDiskDevice(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainDiskDefPtr detach)
4637
{
4638
    int ret = -1;
4639 4640
    qemuDomainObjPrivatePtr priv = vm->privateData;

4641
    if (qemuDomainDiskBlockJobIsActive(detach))
E
Eric Blake 已提交
4642 4643
        goto cleanup;

4644 4645
    qemuDomainMarkDeviceForRemoval(vm, &detach->info);

4646
    qemuDomainObjEnterMonitor(driver, vm);
4647
    if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
4648 4649
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
            goto cleanup;
4650
        virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
4651 4652
        goto cleanup;
    }
4653 4654
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
4655

4656
    if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
4657
        ret = qemuDomainRemoveDiskDevice(driver, vm, detach);
4658

4659
 cleanup:
4660
    qemuDomainResetDeviceRemoval(vm);
4661 4662 4663
    return ret;
}

4664 4665 4666 4667 4668 4669
static int
qemuFindDisk(virDomainDefPtr def, const char *dst)
{
    size_t i;

    for (i = 0; i < def->ndisks; i++) {
4670
        if (STREQ(def->disks[i]->dst, dst))
4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715
            return i;
    }

    return -1;
}

int
qemuDomainDetachDeviceDiskLive(virQEMUDriverPtr driver,
                               virDomainObjPtr vm,
                               virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr disk;
    int ret = -1;
    int idx;

    if ((idx = qemuFindDisk(vm->def, dev->data.disk->dst)) < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("disk %s not found"), dev->data.disk->dst);
        return -1;
    }
    disk = vm->def->disks[idx];

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_DISK:
    case VIR_DOMAIN_DISK_DEVICE_LUN:
        if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
            ret = qemuDomainDetachVirtioDiskDevice(driver, vm, disk);
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                 disk->bus == VIR_DOMAIN_DISK_BUS_USB)
            ret = qemuDomainDetachDiskDevice(driver, vm, disk);
        else
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("This type of disk cannot be hot unplugged"));
        break;
    default:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("disk device type '%s' cannot be detached"),
                       virDomainDiskDeviceTypeToString(disk->device));
        break;
    }

    return ret;
}


4716 4717 4718
static bool qemuDomainDiskControllerIsBusy(virDomainObjPtr vm,
                                           virDomainControllerDefPtr detach)
{
4719
    size_t i;
4720
    virDomainDiskDefPtr disk;
4721
    virDomainHostdevDefPtr hostdev;
4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743

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

4744 4745 4746 4747 4748 4749 4750 4751 4752
    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;
    }

4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775
    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;
    }
}

4776 4777 4778
int qemuDomainDetachControllerDevice(virQEMUDriverPtr driver,
                                     virDomainObjPtr vm,
                                     virDomainDeviceDefPtr dev)
4779
{
4780
    int idx, ret = -1;
4781 4782 4783
    virDomainControllerDefPtr detach = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;

4784 4785 4786
    if ((idx = virDomainControllerFind(vm->def,
                                       dev->data.controller->type,
                                       dev->data.controller->idx)) < 0) {
4787
        virReportError(VIR_ERR_OPERATION_FAILED,
4788
                       _("controller %s:%d not found"),
4789 4790
                       virDomainControllerTypeToString(dev->data.controller->type),
                       dev->data.controller->idx);
4791 4792 4793
        goto cleanup;
    }

4794 4795
    detach = vm->def->controllers[idx];

4796 4797 4798 4799 4800 4801
    if (detach->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
        detach->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW &&
        detach->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("device with '%s' address cannot be detached"),
                       virDomainDeviceAddressTypeToString(detach->info.type));
4802 4803 4804
        goto cleanup;
    }

4805 4806 4807 4808 4809 4810 4811 4812 4813
    if (!virDomainDeviceAddressIsValid(&detach->info, detach->info.type)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("device with invalid '%s' address cannot be detached"),
                       virDomainDeviceAddressTypeToString(detach->info.type));
        goto cleanup;
    }

    if (detach->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
        qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
4814 4815 4816
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("cannot hot unplug multifunction PCI device: %s"),
                       dev->data.disk->dst);
4817 4818 4819
        goto cleanup;
    }

4820
    if (qemuDomainControllerIsBusy(vm, detach)) {
4821 4822
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("device cannot be detached: device is busy"));
4823 4824 4825
        goto cleanup;
    }

4826
    if (!detach->info.alias) {
4827
        if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, detach) < 0)
4828 4829 4830
            goto cleanup;
    }

4831 4832
    qemuDomainMarkDeviceForRemoval(vm, &detach->info);

4833
    qemuDomainObjEnterMonitor(driver, vm);
4834 4835 4836
    if (qemuMonitorDelDevice(priv->mon, detach->info.alias)) {
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        goto cleanup;
4837
    }
4838 4839
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
4840

4841
    if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
4842
        ret = qemuDomainRemoveControllerDevice(driver, vm, detach);
4843

4844
 cleanup:
4845
    qemuDomainResetDeviceRemoval(vm);
4846 4847 4848
    return ret;
}

4849
static int
4850
qemuDomainDetachHostPCIDevice(virQEMUDriverPtr driver,
4851
                              virDomainObjPtr vm,
4852
                              virDomainHostdevDefPtr detach)
4853 4854
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4855
    virDomainHostdevSubsysPCIPtr pcisrc = &detach->source.subsys.u.pci;
4856
    int ret;
4857

4858
    if (qemuIsMultiFunctionDevice(vm->def, detach->info)) {
4859 4860
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"),
4861 4862
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
4863
        return -1;
4864 4865
    }

4866
    if (!virDomainDeviceAddressIsValid(detach->info,
4867
                                       VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
4868 4869
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("device cannot be detached without a PCI address"));
4870
        return -1;
4871 4872
    }

4873 4874
    qemuDomainMarkDeviceForRemoval(vm, detach->info);

4875
    qemuDomainObjEnterMonitor(driver, vm);
4876
    ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);
4877 4878
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;
4879 4880 4881 4882

    return ret;
}

4883
static int
4884
qemuDomainDetachHostUSBDevice(virQEMUDriverPtr driver,
4885
                              virDomainObjPtr vm,
4886
                              virDomainHostdevDefPtr detach)
4887 4888
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
4889
    int ret;
4890

4891
    if (!detach->info->alias) {
4892 4893
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("device cannot be detached without a device alias"));
4894 4895 4896
        return -1;
    }

4897 4898
    qemuDomainMarkDeviceForRemoval(vm, detach->info);

4899
    qemuDomainObjEnterMonitor(driver, vm);
4900
    ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);
4901 4902
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;
4903 4904 4905 4906

    return ret;
}

4907
static int
4908
qemuDomainDetachHostSCSIDevice(virQEMUDriverPtr driver,
4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr detach)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

    if (!detach->info->alias) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("device cannot be detached without a device alias"));
        return -1;
    }

4921 4922
    qemuDomainMarkDeviceForRemoval(vm, detach->info);

4923
    qemuDomainObjEnterMonitor(driver, vm);
4924 4925 4926 4927
    ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);

    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        return -1;
4928 4929 4930 4931

    return ret;
}

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
static int
qemuDomainDetachSCSIVHostDevice(virQEMUDriverPtr driver,
                                virDomainObjPtr vm,
                                virDomainHostdevDefPtr detach)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

    if (!detach->info->alias) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("device cannot be detached without a device alias"));
        return -1;
    }

    qemuDomainMarkDeviceForRemoval(vm, detach->info);

    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorDelDevice(priv->mon, detach->info->alias);

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

    return ret;
}

4957
static int
4958
qemuDomainDetachThisHostDevice(virQEMUDriverPtr driver,
4959
                               virDomainObjPtr vm,
4960
                               virDomainHostdevDefPtr detach)
4961
{
4962
    int ret = -1;
4963

4964
    if (!detach->info->alias) {
4965
        if (qemuAssignDeviceHostdevAlias(vm->def, &detach->info->alias, -1) < 0)
4966 4967 4968
            return -1;
    }

4969
    switch (detach->source.subsys.type) {
4970
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
4971
        ret = qemuDomainDetachHostPCIDevice(driver, vm, detach);
4972
        break;
4973
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
4974
        ret = qemuDomainDetachHostUSBDevice(driver, vm, detach);
4975
        break;
4976
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
4977
        ret = qemuDomainDetachHostSCSIDevice(driver, vm, detach);
4978
        break;
4979 4980 4981
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
        ret = qemuDomainDetachSCSIVHostDevice(driver, vm, detach);
        break;
4982
    default:
4983
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4984
                       _("hot unplug is not supported for hostdev subsys type '%s'"),
4985
                       virDomainHostdevSubsysTypeToString(detach->source.subsys.type));
4986 4987 4988
        return -1;
    }

4989
    if (ret < 0) {
4990 4991
        if (virDomainObjIsActive(vm))
            virDomainAuditHostdev(vm, detach, "detach", false);
4992 4993
    } else if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1) {
        ret = qemuDomainRemoveHostDevice(driver, vm, detach);
4994
    }
4995

4996 4997
    qemuDomainResetDeviceRemoval(vm);

4998 4999
    return ret;
}
5000

5001
/* search for a hostdev matching dev and detach it */
5002
int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,
5003 5004 5005 5006 5007
                               virDomainObjPtr vm,
                               virDomainDeviceDefPtr dev)
{
    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
5008
    virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb;
5009
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
5010
    virDomainHostdevSubsysSCSIPtr scsisrc = &subsys->u.scsi;
5011 5012 5013 5014
    virDomainHostdevDefPtr detach = NULL;
    int idx;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
5015
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
5016
                       _("hot unplug is not supported for hostdev mode '%s'"),
5017
                       virDomainHostdevModeTypeToString(hostdev->mode));
5018 5019 5020 5021 5022 5023
        return -1;
    }

    idx = virDomainHostdevFind(vm->def, hostdev, &detach);

    if (idx < 0) {
5024
        switch (subsys->type) {
5025
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
5026 5027
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
5028 5029
                           pcisrc->addr.domain, pcisrc->addr.bus,
                           pcisrc->addr.slot, pcisrc->addr.function);
5030 5031
            break;
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
5032
            if (usbsrc->bus && usbsrc->device) {
5033 5034
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("host usb device %03d.%03d not found"),
5035
                               usbsrc->bus, usbsrc->device);
5036
            } else {
5037 5038
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("host usb device vendor=0x%.4x product=0x%.4x not found"),
5039
                               usbsrc->vendor, usbsrc->product);
5040 5041
            }
            break;
5042
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
5043 5044 5045 5046 5047 5048 5049 5050 5051 5052
            if (scsisrc->protocol ==
                VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
                virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("host scsi iSCSI path %s not found"),
                               iscsisrc->path);
            } else {
                 virDomainHostdevSubsysSCSIHostPtr scsihostsrc =
                     &scsisrc->u.host;
                 virReportError(VIR_ERR_OPERATION_FAILED,
5053
                                _("host scsi device %s:%u:%u.%llu not found"),
5054 5055 5056
                                scsihostsrc->adapter, scsihostsrc->bus,
                                scsihostsrc->target, scsihostsrc->unit);
            }
5057
            break;
5058
        }
5059 5060
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST:
            break;
5061
        default:
5062 5063
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"), subsys->type);
5064 5065 5066 5067 5068
            break;
        }
        return -1;
    }

5069 5070 5071 5072
    /* If this is a network hostdev, we need to use the higher-level detach
     * function so that mac address / virtualport are reset
     */
    if (detach->parent.type == VIR_DOMAIN_DEVICE_NET)
5073
        return qemuDomainDetachNetDevice(driver, vm, &detach->parent);
5074
    else
5075
        return qemuDomainDetachThisHostDevice(driver, vm, detach);
5076 5077
}

5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105

int
qemuDomainDetachShmemDevice(virQEMUDriverPtr driver,
                            virDomainObjPtr vm,
                            virDomainShmemDefPtr dev)
{
    int ret = -1;
    ssize_t idx = -1;
    virDomainShmemDefPtr shmem = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;

    if ((idx = virDomainShmemDefFind(vm->def, dev)) < 0) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("device not present in domain configuration"));
        return -1;
    }

    shmem = vm->def->shmems[idx];

    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 已提交
5106
        ATTRIBUTE_FALLTHROUGH;
5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130
    case VIR_DOMAIN_SHMEM_MODEL_LAST:
        return -1;
    }

    qemuDomainMarkDeviceForRemoval(vm, &shmem->info);
    qemuDomainObjEnterMonitor(driver, vm);

    ret = qemuMonitorDelDevice(priv->mon, shmem->info.alias);

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

    if (ret == 0) {
        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1) {
            qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);
            ret = qemuDomainRemoveShmemDevice(driver, vm, shmem);
        }
    }
    qemuDomainResetDeviceRemoval(vm);

    return ret;
}


5131
int
5132
qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
5133 5134 5135
                          virDomainObjPtr vm,
                          virDomainDeviceDefPtr dev)
{
5136
    int detachidx, ret = -1;
5137 5138 5139
    virDomainNetDefPtr detach = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;

5140
    if ((detachidx = virDomainNetFindIdx(vm->def, dev->data.net)) < 0)
5141
        goto cleanup;
5142

5143
    detach = vm->def->nets[detachidx];
5144

5145
    if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
5146
        ret = qemuDomainDetachThisHostDevice(driver, vm,
5147
                                             virDomainNetGetActualHostdev(detach));
5148 5149
        goto cleanup;
    }
5150
    if (qemuDomainIsS390CCW(vm->def) &&
5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164
        virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VIRTIO_CCW)) {
        if (!virDomainDeviceAddressIsValid(&detach->info,
                                           VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW)) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("device cannot be detached without a CCW address"));
            goto cleanup;
        }
    } else {
        if (!virDomainDeviceAddressIsValid(&detach->info,
                                           VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                            "%s", _("device cannot be detached without a PCI address"));
            goto cleanup;
        }
5165

5166 5167 5168 5169 5170 5171
        if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                            _("cannot hot unplug multifunction PCI device :%s"),
                            dev->data.disk->dst);
            goto cleanup;
        }
5172 5173
    }

5174
    if (!detach->info.alias) {
5175 5176 5177 5178
        if (qemuAssignDeviceNetAlias(vm->def, detach, -1) < 0)
            goto cleanup;
    }

5179 5180
    if (virDomainNetGetActualBandwidth(detach) &&
        virNetDevSupportBandwidth(virDomainNetGetActualType(detach)) &&
5181 5182 5183 5184
        virNetDevBandwidthClear(detach->ifname) < 0)
        VIR_WARN("cannot clear bandwidth setting for device : %s",
                 detach->ifname);

5185 5186 5187
    /* 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)
5188 5189 5190
     */
    ignore_value(qemuInterfaceStopDevice(detach));

5191 5192
    qemuDomainMarkDeviceForRemoval(vm, &detach->info);

5193
    qemuDomainObjEnterMonitor(driver, vm);
5194 5195
    if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
        if (qemuDomainObjExitMonitor(driver, vm) < 0)
5196
            goto cleanup;
5197 5198
        virDomainAuditNet(vm, detach, NULL, "detach", false);
        goto cleanup;
5199
    }
5200 5201
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
5202

5203
    if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
5204
        ret = qemuDomainRemoveNetDevice(driver, vm, detach);
5205

5206
 cleanup:
5207
    qemuDomainResetDeviceRemoval(vm);
5208 5209 5210
    return ret;
}

5211
int
5212
qemuDomainChangeGraphicsPasswords(virQEMUDriverPtr driver,
5213 5214 5215
                                  virDomainObjPtr vm,
                                  int type,
                                  virDomainGraphicsAuthDefPtr auth,
5216 5217
                                  const char *defaultPasswd,
                                  int asyncJob)
5218 5219 5220
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    time_t now = time(NULL);
5221 5222
    const char *expire;
    char *validTo = NULL;
5223
    const char *connected = NULL;
5224
    const char *password;
5225 5226
    int ret = -1;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
5227

5228
    if (!auth->passwd && !defaultPasswd) {
5229 5230 5231
        ret = 0;
        goto cleanup;
    }
5232
    password = auth->passwd ? auth->passwd : defaultPasswd;
5233

5234 5235 5236
    if (auth->connected)
        connected = virDomainGraphicsAuthConnectedTypeToString(auth->connected);

5237 5238
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;
5239
    ret = qemuMonitorSetPassword(priv->mon, type, password, connected);
5240 5241 5242

    if (ret == -2) {
        if (type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
5243 5244
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Graphics password only supported for VNC"));
5245 5246
            ret = -1;
        } else {
5247
            ret = qemuMonitorSetVNCPassword(priv->mon, password);
5248 5249
        }
    }
5250
    if (ret != 0)
5251
        goto end_job;
5252

5253 5254 5255
    if (password[0] == '\0' ||
        (auth->expires && auth->validTo <= now)) {
        expire = "now";
5256
    } else if (auth->expires) {
5257 5258 5259
        if (virAsprintf(&validTo, "%lu", (unsigned long) auth->validTo) < 0)
            goto end_job;
        expire = validTo;
5260
    } else {
5261
        expire = "never";
5262 5263
    }

5264
    ret = qemuMonitorExpirePassword(priv->mon, type, expire);
5265 5266 5267 5268

    if (ret == -2) {
        /* XXX we could fake this with a timer */
        if (auth->expires) {
5269 5270
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Expiry of passwords is not supported"));
5271
            ret = -1;
5272 5273
        } else {
            ret = 0;
5274 5275 5276
        }
    }

5277
 end_job:
5278 5279
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        ret = -1;
5280
 cleanup:
5281
    VIR_FREE(validTo);
5282
    virObjectUnref(cfg);
5283 5284
    return ret;
}
5285

5286
int qemuDomainAttachLease(virQEMUDriverPtr driver,
5287 5288 5289
                          virDomainObjPtr vm,
                          virDomainLeaseDefPtr lease)
{
5290 5291 5292
    int ret = -1;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);

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

5296
    if (virDomainLockLeaseAttach(driver->lockManager, cfg->uri,
5297
                                 vm, lease) < 0) {
5298
        virDomainLeaseInsertPreAlloced(vm->def, NULL);
5299
        goto cleanup;
5300 5301 5302
    }

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

5305
 cleanup:
5306 5307
    virObjectUnref(cfg);
    return ret;
5308 5309
}

5310
int qemuDomainDetachLease(virQEMUDriverPtr driver,
5311 5312 5313
                          virDomainObjPtr vm,
                          virDomainLeaseDefPtr lease)
{
5314
    virDomainLeaseDefPtr det_lease;
5315
    int idx;
5316

5317
    if ((idx = virDomainLeaseIndex(vm->def, lease)) < 0) {
5318 5319 5320
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Lease %s in lockspace %s does not exist"),
                       lease->key, NULLSTR(lease->lockspace));
5321 5322 5323 5324 5325 5326
        return -1;
    }

    if (virDomainLockLeaseDetach(driver->lockManager, vm, lease) < 0)
        return -1;

5327
    det_lease = virDomainLeaseRemoveAt(vm->def, idx);
5328
    virDomainLeaseDefFree(det_lease);
5329 5330
    return 0;
}
5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344

int qemuDomainDetachChrDevice(virQEMUDriverPtr driver,
                              virDomainObjPtr vm,
                              virDomainChrDefPtr chr)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainDefPtr vmdef = vm->def;
    virDomainChrDefPtr tmpChr;
    char *devstr = NULL;

    if (!(tmpChr = virDomainChrFind(vmdef, chr))) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("device not present in domain configuration"));
5345
        goto cleanup;
5346 5347
    }

P
Pavel Hrdina 已提交
5348
    if (!tmpChr->info.alias && qemuAssignDeviceChrAlias(vmdef, tmpChr, -1) < 0)
5349
        goto cleanup;
P
Pavel Hrdina 已提交
5350 5351 5352

    sa_assert(tmpChr->info.alias);

5353
    if (qemuBuildChrDeviceStr(&devstr, vmdef, chr, priv->qemuCaps) < 0)
5354
        goto cleanup;
5355

5356 5357
    qemuDomainMarkDeviceForRemoval(vm, &tmpChr->info);

5358
    qemuDomainObjEnterMonitor(driver, vm);
5359 5360 5361 5362
    if (devstr && qemuMonitorDelDevice(priv->mon, tmpChr->info.alias) < 0) {
        ignore_value(qemuDomainObjExitMonitor(driver, vm));
        goto cleanup;
    }
5363 5364
    if (qemuDomainObjExitMonitor(driver, vm) < 0)
        goto cleanup;
5365

5366
    if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1) {
5367
        qemuDomainReleaseDeviceAddress(vm, &tmpChr->info, NULL);
5368
        ret = qemuDomainRemoveChrDevice(driver, vm, tmpChr);
5369 5370
    }

5371
 cleanup:
5372
    qemuDomainResetDeviceRemoval(vm);
5373 5374 5375
    VIR_FREE(devstr);
    return ret;
}
5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388


int
qemuDomainDetachRNGDevice(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainRNGDefPtr rng)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    ssize_t idx;
    virDomainRNGDefPtr tmpRNG;
    int rc;
    int ret = -1;

5389
    if ((idx = virDomainRNGFind(vm->def, rng)) < 0) {
5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("device not present in domain configuration"));
        return -1;
    }

    tmpRNG = vm->def->rngs[idx];

    if (!tmpRNG->info.alias) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("alias not set for RNG device"));
        return -1;
    }

    qemuDomainMarkDeviceForRemoval(vm, &tmpRNG->info);

    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorDelDevice(priv->mon, tmpRNG->info.alias);
    if (qemuDomainObjExitMonitor(driver, vm) || rc < 0)
        goto cleanup;

5410
    if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
5411 5412 5413 5414 5415 5416
        ret = qemuDomainRemoveRNGDevice(driver, vm, tmpRNG);

 cleanup:
    qemuDomainResetDeviceRemoval(vm);
    return ret;
}
5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429


int
qemuDomainDetachMemoryDevice(virQEMUDriverPtr driver,
                             virDomainObjPtr vm,
                             virDomainMemoryDefPtr memdef)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainMemoryDefPtr mem;
    int idx;
    int rc;
    int ret = -1;

5430
    qemuDomainMemoryDeviceAlignSize(vm->def, memdef);
5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452

    if ((idx = virDomainMemoryFindByDef(vm->def, memdef)) < 0) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("device not present in domain configuration"));
        return -1;
    }

    mem = vm->def->mems[idx];

    if (!mem->info.alias) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("alias for the memory device was not found"));
        return -1;
    }

    qemuDomainMarkDeviceForRemoval(vm, &mem->info);

    qemuDomainObjEnterMonitor(driver, vm);
    rc = qemuMonitorDelDevice(priv->mon, mem->info.alias);
    if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
        goto cleanup;

5453
    if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1)
5454 5455 5456 5457 5458 5459
        ret = qemuDomainRemoveMemoryDevice(driver, vm, mem);

 cleanup:
    qemuDomainResetDeviceRemoval(vm);
    return ret;
}
5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471


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;
5472
    virErrorPtr save_error = NULL;
5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496
    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);

5497 5498 5499 5500 5501 5502
    virErrorPreserveLast(&save_error);

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

    virErrorRestore(&save_error);
5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528

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


5529
static int
5530
qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver,
5531
                         virQEMUDriverConfigPtr cfg,
5532 5533 5534 5535 5536 5537 5538 5539
                         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;
5540
    int ret = -1;
5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554

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

    qemuDomainMarkDeviceAliasForRemoval(vm, vcpupriv->alias);

    qemuDomainObjEnterMonitor(driver, vm);

    rc = qemuMonitorDelDevice(qemuDomainGetMonitor(vm), vcpupriv->alias);

    if (qemuDomainObjExitMonitor(driver, vm) < 0)
5555
        goto cleanup;
5556 5557 5558

    if (rc < 0) {
        virDomainAuditVcpu(vm, oldvcpus, oldvcpus - nvcpus, "update", false);
5559
        goto cleanup;
5560 5561 5562 5563 5564 5565 5566
    }

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

5567
        goto cleanup;
5568 5569
    }

5570 5571 5572
    if (qemuDomainRemoveVcpu(driver, vm, vcpu) < 0)
        goto cleanup;

5573 5574 5575 5576 5577
    qemuDomainVcpuPersistOrder(vm->def);

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

5578 5579 5580 5581 5582
    ret = 0;

 cleanup:
    qemuDomainResetDeviceRemoval(vm);
    return ret;
5583
}
5584 5585 5586 5587


static int
qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver,
5588
                         virQEMUDriverConfigPtr cfg,
5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648
                         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;

5649 5650 5651 5652 5653
    qemuDomainVcpuPersistOrder(vm->def);

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

5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774
    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) {
5775 5776
            if (qemuDomainHotplugAddVcpu(driver, cfg, vm, nextvcpu) < 0)
                goto cleanup;
5777 5778 5779 5780 5781 5782
        }
    } else {
        for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) {
            if (!virBitmapIsBitSet(vcpumap, nextvcpu))
                continue;

5783 5784
            if (qemuDomainHotplugDelVcpu(driver, cfg, vm, nextvcpu) < 0)
                goto cleanup;
5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919
        }
    }

    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) {
                /* non-hotpluggable vcpus need to be clustered at the beggining,
                 * 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)
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    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);
    virObjectUnref(cfg);
    return ret;
}
5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931


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

    def->individualvcpus = true;

5932 5933 5934
    /* ordering information may become invalid, thus clear it */
    virDomainDefVcpuOrderClear(def);

5935
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966
        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 */
5967
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
5968 5969 5970 5971 5972
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        if (vcpu->online == state) {
            virReportError(VIR_ERR_INVALID_ARG,
5973
                           _("vcpu '%zd' is already in requested state"), next);
5974 5975 5976 5977 5978
            goto cleanup;
        }

        if (vcpu->online && !vcpu->hotpluggable) {
            virReportError(VIR_ERR_INVALID_ARG,
5979
                           _("vcpu '%zd' can't be hotunplugged"), next);
5980 5981 5982 5983 5984 5985 5986
            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;
5987
    while ((next = virBitmapNextSetBit(map, next)) >= 0) {
5988 5989 5990 5991 5992 5993 5994
        if (!(vcpu = virDomainDefGetVcpu(def, next)))
            continue;

        vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu);

        if (vcpupriv->vcpus == 0) {
            virReportError(VIR_ERR_INVALID_ARG,
5995
                           _("vcpu '%zd' belongs to a larger hotpluggable entity, "
5996 5997 5998 5999 6000 6001 6002 6003
                             "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 "
6004
                                 "hotpluggable entity '%zd-%zd' which was "
6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022
                                 "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;
}


6023
static int
6024
qemuDomainVcpuValidateConfig(virDomainDefPtr def,
6025
                             virBitmapPtr map)
6026
{
6027 6028 6029
    virDomainVcpuDefPtr vcpu;
    size_t maxvcpus = virDomainDefGetVcpusMax(def);
    ssize_t next;
6030
    ssize_t firstvcpu = -1;
6031

6032 6033
    /* vcpu 0 can't be modified */
    if (virBitmapIsBitSet(map, 0)) {
6034
        virReportError(VIR_ERR_INVALID_ARG, "%s",
6035
                       _("vCPU '0' can't be modified"));
6036 6037 6038
        return -1;
    }

6039 6040 6041 6042 6043 6044
    /* 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 */
6045 6046 6047 6048
        if (virBitmapIsBitSet(map, next)) {
            if (firstvcpu < 0)
                firstvcpu = next;

6049
            continue;
6050
        }
6051 6052 6053 6054

        if (vcpu->online && vcpu->hotpluggable == VIR_TRISTATE_BOOL_NO) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("vcpu '%zd' can't be modified as it is followed "
6055
                             "by non-hotpluggable online vcpus"), firstvcpu);
6056 6057 6058 6059
            return -1;
        }
    }

6060 6061 6062 6063
    return 0;
}


6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097
int
qemuDomainSetVcpuInternal(virQEMUDriverPtr driver,
                          virDomainObjPtr vm,
                          virDomainDefPtr def,
                          virDomainDefPtr persistentDef,
                          virBitmapPtr map,
                          bool state)
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    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;
        }
    }

6098
    if (persistentDef) {
6099
        if (qemuDomainVcpuValidateConfig(persistentDef, map) < 0)
6100 6101 6102
            goto cleanup;
    }

6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120
    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);
    virObjectUnref(cfg);
    return ret;
}