qemu_hostdev.c 42.2 KB
Newer Older
1 2 3
/*
 * qemu_hostdev.c: QEMU hostdev management
 *
4
 * Copyright (C) 2006-2007, 2009-2013 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
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include "qemu_hostdev.h"
27
#include "virlog.h"
28
#include "virerror.h"
29
#include "viralloc.h"
30
#include "virpci.h"
31
#include "virusb.h"
32
#include "virscsi.h"
33
#include "virnetdev.h"
34

35 36
#define VIR_FROM_THIS VIR_FROM_QEMU

37
static virPCIDeviceListPtr
38 39
qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
{
40
    virPCIDeviceListPtr list;
41 42
    int i;

43
    if (!(list = virPCIDeviceListNew()))
44 45
        return NULL;

46
    for (i = 0; i < nhostdevs; i++) {
47
        virDomainHostdevDefPtr hostdev = hostdevs[i];
48
        virPCIDevicePtr dev;
49 50 51 52 53 54

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

55 56 57 58
        dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
                              hostdev->source.subsys.u.pci.addr.bus,
                              hostdev->source.subsys.u.pci.addr.slot,
                              hostdev->source.subsys.u.pci.addr.function);
59
        if (!dev) {
60
            virObjectUnref(list);
61 62 63
            return NULL;
        }

64 65
        if (virPCIDeviceListAdd(list, dev) < 0) {
            virPCIDeviceFree(dev);
66
            virObjectUnref(list);
67 68 69
            return NULL;
        }

70
        virPCIDeviceSetManaged(dev, hostdev->managed);
71
        if (hostdev->source.subsys.u.pci.backend
72
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
73 74 75 76
            virPCIDeviceSetStubDriver(dev, "vfio-pci");
        } else {
            virPCIDeviceSetStubDriver(dev, "pci-stub");
        }
77 78 79 80 81
    }

    return list;
}

82 83 84
/*
 * Pre-condition: driver->activePciHostdevs is locked
 */
85
static virPCIDeviceListPtr
86
qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver,
87 88 89
                               virDomainHostdevDefPtr *hostdevs,
                               int nhostdevs)
{
90
    virPCIDeviceListPtr list;
91 92
    int i;

93
    if (!(list = virPCIDeviceListNew()))
94 95
        return NULL;

96
    for (i = 0; i < nhostdevs; i++) {
97
        virDomainHostdevDefPtr hostdev = hostdevs[i];
98 99
        virPCIDevicePtr dev;
        virPCIDevicePtr activeDev;
100 101 102 103 104 105

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

106 107 108 109
        dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
                              hostdev->source.subsys.u.pci.addr.bus,
                              hostdev->source.subsys.u.pci.addr.slot,
                              hostdev->source.subsys.u.pci.addr.function);
110
        if (!dev) {
111
            virObjectUnref(list);
112 113 114
            return NULL;
        }

115 116 117
        if ((activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev))) {
            if (virPCIDeviceListAdd(list, activeDev) < 0) {
                virPCIDeviceFree(dev);
118
                virObjectUnref(list);
119 120 121 122
                return NULL;
            }
        }

123
        virPCIDeviceFree(dev);
124 125 126 127
    }

    return list;
}
128

129
int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
130 131
                                virDomainDefPtr def)
{
132 133
    virDomainHostdevDefPtr hostdev = NULL;
    int i;
134
    int ret = -1;
135 136 137 138

    if (!def->nhostdevs)
        return 0;

139 140 141
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

142
    for (i = 0; i < def->nhostdevs; i++) {
143
        virPCIDevicePtr dev = NULL;
144 145 146 147 148 149 150
        hostdev = def->hostdevs[i];

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

151 152 153 154
        dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
                              hostdev->source.subsys.u.pci.addr.bus,
                              hostdev->source.subsys.u.pci.addr.slot,
                              hostdev->source.subsys.u.pci.addr.function);
155 156

        if (!dev)
157
            goto cleanup;
158

159
        virPCIDeviceSetManaged(dev, hostdev->managed);
160
        if (hostdev->source.subsys.u.pci.backend
161
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
162 163 164 165
            virPCIDeviceSetStubDriver(dev, "vfio-pci");
        } else {
            virPCIDeviceSetStubDriver(dev, "pci-stub");
        }
166
        virPCIDeviceSetUsedBy(dev, def->name);
167 168

        /* Setup the original states for the PCI device */
169 170 171
        virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub);
        virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot);
        virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe);
172

173 174
        if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            virPCIDeviceFree(dev);
175
            goto cleanup;
176 177 178
        }
    }

179
    ret = 0;
180 181 182 183
cleanup:
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
    return ret;
184 185 186
}

int
187
qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
188 189 190 191
                            virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
    int i;
192
    int ret = -1;
193 194 195 196

    if (!def->nhostdevs)
        return 0;

197
    virObjectLock(driver->activeUsbHostdevs);
198
    for (i = 0; i < def->nhostdevs; i++) {
199
        virUSBDevicePtr usb = NULL;
200 201 202 203 204 205 206
        hostdev = def->hostdevs[i];

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

207 208 209
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
210 211 212 213 214 215 216 217
        if (!usb) {
            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
                     hostdev->source.subsys.u.usb.bus,
                     hostdev->source.subsys.u.usb.device,
                     def->name);
            continue;
        }

218
        virUSBDeviceSetUsedBy(usb, def->name);
219

220 221
        if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
            virUSBDeviceFree(usb);
222
            goto cleanup;
223 224
        }
    }
225 226 227 228
    ret = 0;
cleanup:
    virObjectUnlock(driver->activeUsbHostdevs);
    return ret;
229 230
}

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
int
qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
                             virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
    int i;
    int ret = -1;

    if (!def->nhostdevs)
        return 0;

    virObjectLock(driver->activeScsiHostdevs);
    for (i = 0; i < def->nhostdevs; i++) {
        virSCSIDevicePtr scsi = NULL;
        hostdev = def->hostdevs[i];

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

        if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
                                      hostdev->readonly)))
            goto cleanup;

        virSCSIDeviceSetUsedBy(scsi, def->name);

        if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) {
            virSCSIDeviceFree(scsi);
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    virObjectUnlock(driver->activeScsiHostdevs);
    return ret;
}

272 273 274
static int
qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, char **sysfs_path)
{
275
    virPCIDeviceAddress config_address;
276

277 278 279 280
    config_address.domain = hostdev->source.subsys.u.pci.addr.domain;
    config_address.bus = hostdev->source.subsys.u.pci.addr.bus;
    config_address.slot = hostdev->source.subsys.u.pci.addr.slot;
    config_address.function = hostdev->source.subsys.u.pci.addr.function;
281

282
    return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
283 284 285 286 287 288 289 290 291 292 293
}

int
qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
{
    char *sysfs_path = NULL;
    int ret = -1;

    if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
        return ret;

294
    ret = virPCIIsVirtualFunction(sysfs_path);
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310

    VIR_FREE(sysfs_path);

    return ret;
}

static int
qemuDomainHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
                           int *vf)
{
    int ret = -1;
    char *sysfs_path = NULL;

    if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
        return ret;

311 312 313
    if (virPCIIsVirtualFunction(sysfs_path) == 1) {
        if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev,
                                         vf) < 0)
314 315
            goto cleanup;
    } else {
316
        if (virPCIGetNetName(sysfs_path, linkdev) < 0)
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
            goto cleanup;
        *vf = -1;
    }

    ret = 0;

cleanup:
    VIR_FREE(sysfs_path);

    return ret;
}

static int
qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
                                          virNetDevVPortProfilePtr virtPort,
332
                                          const virMacAddrPtr macaddr,
333 334 335 336 337 338 339 340
                                          const unsigned char *uuid,
                                          int associate)
{
    int ret = -1;

    if (!virtPort)
        return ret;

341
    switch (virtPort->virtPortType) {
342 343 344 345
    case VIR_NETDEV_VPORT_PROFILE_NONE:
    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
    case VIR_NETDEV_VPORT_PROFILE_8021QBG:
    case VIR_NETDEV_VPORT_PROFILE_LAST:
346 347 348 349 350
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("virtualport type %s is "
                         "currently not supported on interfaces of type "
                         "hostdev"),
                       virNetDevVPortTypeToString(virtPort->virtPortType));
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
        break;

    case VIR_NETDEV_VPORT_PROFILE_8021QBH:
        if (associate)
            ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr,
                                                 linkdev, vf, uuid,
                                                 VIR_NETDEV_VPORT_PROFILE_OP_CREATE, false);
        else
            ret = virNetDevVPortProfileDisassociate(NULL, virtPort,
                                                    macaddr, linkdev, vf,
                                                    VIR_NETDEV_VPORT_PROFILE_OP_DESTROY);
        break;
    }

    return ret;
}

int
qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
                                  const unsigned char *uuid,
                                  char *stateDir)
{
    char *linkdev = NULL;
374
    virNetDevVlanPtr vlan;
375 376 377 378 379 380 381 382 383
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
    int vlanid = -1;
    int port_profile_associate = 1;
    int isvf;

    isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
    if (isvf <= 0) {
384 385 386
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
387 388 389 390 391 392
        return ret;
    }

    if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
        return ret;

393
    vlan = virDomainNetGetActualVlan(hostdev->parent.data.net);
394 395
    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
396 397 398 399 400 401 402 403
    if (virtPort) {
        if (vlan) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("direct setting of the vlan tag is not allowed "
                             "for hostdev devices using %s mode"),
                           virNetDevVPortTypeToString(virtPort->virtPortType));
            goto cleanup;
        }
404
        ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf,
405
                            virtPort, &hostdev->parent.data.net->mac, uuid,
406
                            port_profile_associate);
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    } else {
        /* Set only mac and vlan */
        if (vlan) {
            if (vlan->nTags != 1 || vlan->trunk) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("vlan trunking is not supported "
                                 "by SR-IOV network devices"));
                goto cleanup;
            }
            if (vf == -1) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("vlan can only be set for SR-IOV VFs, but "
                                 "%s is not a VF"), linkdev);
                goto cleanup;
            }
            vlanid = vlan->tag[0];
        } else  if (vf >= 0) {
            vlanid = 0; /* assure any current vlan tag is reset */
        }

427
        ret = virNetDevReplaceNetConfig(linkdev, vf,
428 429 430 431
                                        &hostdev->parent.data.net->mac,
                                        vlanid, stateDir);
    }
cleanup:
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    VIR_FREE(linkdev);
    return ret;
}

int
qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
                                  char *stateDir)
{
    char *linkdev = NULL;
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
    int port_profile_associate = 0;
    int isvf;

    isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
    if (isvf <= 0) {
449 450 451
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
452 453 454 455 456 457 458 459 460 461
        return ret;
    }

    if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
        return ret;

    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
    if (virtPort)
        ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
462
                                          &hostdev->parent.data.net->mac, NULL,
463 464 465 466 467 468 469 470 471
                                          port_profile_associate);
    else
        ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);

    VIR_FREE(linkdev);

    return ret;
}

472
int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
473
                                 const char *name,
474
                                 const unsigned char *uuid,
475 476 477
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
478
    virPCIDeviceListPtr pcidevs;
479
    int last_processed_hostdev_vf = -1;
480 481
    int i;
    int ret = -1;
482
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
483

484 485 486
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

487
    if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
488
        goto cleanup;
489

490
    /* We have to use 9 loops here. *All* devices must
491 492 493 494 495 496
     * be detached before we reset any of them, because
     * in some cases you have to reset the whole PCI,
     * which impacts all devices on it. Also, all devices
     * must be reset before being marked as active.
     */

497
    /* Loop 1: validate that non-managed device isn't in use, eg
498 499 500 501
     * by checking that device is either un-bound, or bound
     * to pci-stub.ko
     */

502 503 504
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr other;
505

506
        if (!virPCIDeviceIsAssignable(dev, !cfg->relaxedACS)) {
507 508
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is not assignable"),
509
                           virPCIDeviceGetName(dev));
510 511 512 513 514
            goto cleanup;
        }
        /* The device is in use by other active domain if
         * the dev is in list driver->activePciHostdevs.
         */
515 516
        if ((other = virPCIDeviceListFind(driver->activePciHostdevs, dev))) {
            const char *other_name = virPCIDeviceGetUsedBy(other);
517 518

            if (other_name)
519 520
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("PCI device %s is in use by domain %s"),
521
                               virPCIDeviceGetName(dev), other_name);
522
            else
523 524
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("PCI device %s is already in use"),
525
                               virPCIDeviceGetName(dev));
526 527 528 529
            goto cleanup;
        }
    }

530
    /* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */
531 532 533
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceGetManaged(dev) &&
534
            virPCIDeviceDetach(dev, driver->activePciHostdevs, NULL, NULL) < 0)
535
            goto reattachdevs;
536 537
    }

538 539
    /* Loop 3: Now that all the PCI hostdevs have been detached, we
     * can safely reset them */
540 541 542 543
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceReset(dev, driver->activePciHostdevs,
                              driver->inactivePciHostdevs) < 0)
544
            goto reattachdevs;
545 546
    }

547 548 549 550 551 552 553 554 555 556 557
    /* Loop 4: For SRIOV network devices, Now that we have detached the
     * the network device, set the netdev config */
    for (i = 0; i < nhostdevs; i++) {
         virDomainHostdevDefPtr hostdev = hostdevs[i];
         if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
             continue;
         if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
             continue;
         if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
             hostdev->parent.data.net) {
             if (qemuDomainHostdevNetConfigReplace(hostdev, uuid,
558
                                                   cfg->stateDir) < 0) {
559 560 561 562 563 564 565
                 goto resetvfnetconfig;
             }
         }
         last_processed_hostdev_vf = i;
    }

    /* Loop 5: Now mark all the devices as active */
566 567 568
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0)
569
            goto inactivedevs;
570 571
    }

572
    /* Loop 6: Now remove the devices from inactive list. */
573 574 575
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
         virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
         virPCIDeviceListDel(driver->inactivePciHostdevs, dev);
576 577
    }

578
    /* Loop 7: Now set the used_by_domain of the device in
579 580
     * driver->activePciHostdevs as domain name.
     */
581 582
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev, activeDev;
583

584 585
        dev = virPCIDeviceListGet(pcidevs, i);
        activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
586

587
        if (activeDev)
588
            virPCIDeviceSetUsedBy(activeDev, name);
589 590
    }

591
    /* Loop 8: Now set the original states for hostdev def */
592
    for (i = 0; i < nhostdevs; i++) {
593 594
        virPCIDevicePtr dev;
        virPCIDevicePtr pcidev;
595 596 597 598 599 600 601
        virDomainHostdevDefPtr hostdev = hostdevs[i];

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

602 603 604 605
        dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
                              hostdev->source.subsys.u.pci.addr.bus,
                              hostdev->source.subsys.u.pci.addr.slot,
                              hostdev->source.subsys.u.pci.addr.function);
606 607 608 609 610

        /* original states "unbind_from_stub", "remove_slot",
         * "reprobe" were already set by pciDettachDevice in
         * loop 2.
         */
611
        if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) {
612
            hostdev->origstates.states.pci.unbind_from_stub =
613
                virPCIDeviceGetUnbindFromStub(pcidev);
614
            hostdev->origstates.states.pci.remove_slot =
615
                virPCIDeviceGetRemoveSlot(pcidev);
616
            hostdev->origstates.states.pci.reprobe =
617
                virPCIDeviceGetReprobe(pcidev);
618 619
        }

620
        virPCIDeviceFree(dev);
621 622
    }

623
    /* Loop 9: Now steal all the devices from pcidevs */
624 625
    while (virPCIDeviceListCount(pcidevs) > 0)
        virPCIDeviceListStealIndex(pcidevs, 0);
626

627
    ret = 0;
628 629 630 631
    goto cleanup;

inactivedevs:
    /* Only steal all the devices from driver->activePciHostdevs. We will
632
     * free them in virObjectUnref().
633
     */
634 635 636
    while (virPCIDeviceListCount(pcidevs) > 0) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, 0);
        virPCIDeviceListSteal(driver->activePciHostdevs, dev);
637
    }
638

639 640 641 642 643
resetvfnetconfig:
    for (i = 0; i < last_processed_hostdev_vf; i++) {
         virDomainHostdevDefPtr hostdev = hostdevs[i];
         if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
             hostdev->parent.data.net) {
644
             qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
645 646 647
         }
    }

648
reattachdevs:
649 650
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
651 652 653 654

        /* NB: This doesn't actually re-bind to original driver, just
         * unbinds from the stub driver
         */
655
        virPCIDeviceReattach(dev, driver->activePciHostdevs, NULL);
656 657
    }

658
cleanup:
659 660
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
661
    virObjectUnref(pcidevs);
662
    virObjectUnref(cfg);
663 664 665
    return ret;
}

666
int
667
qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
668
                             const char *name,
669
                             virUSBDeviceListPtr list)
670
{
671
    int i, j;
672
    unsigned int count;
673
    virUSBDevicePtr tmp;
674

675
    virObjectLock(driver->activeUsbHostdevs);
676
    count = virUSBDeviceListCount(list);
677 678

    for (i = 0; i < count; i++) {
679 680 681
        virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
        if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) {
            const char *other_name = virUSBDeviceGetUsedBy(tmp);
682 683

            if (other_name)
684 685
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is in use by domain %s"),
686
                               virUSBDeviceGetName(tmp), other_name);
687
            else
688 689
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is already in use"),
690
                               virUSBDeviceGetName(tmp));
691
            goto error;
692 693
        }

694
        virUSBDeviceSetUsedBy(usb, name);
695
        VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
696
                  virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
697 698
        /*
         * The caller is responsible to steal these usb devices
699
         * from the virUSBDeviceList that passed in on success,
700 701
         * perform rollback on failure.
         */
702
        if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0)
703
            goto error;
704
    }
705 706

    virObjectUnlock(driver->activeUsbHostdevs);
707
    return 0;
708 709 710

error:
    for (j = 0; j < i; j++) {
711 712
        tmp = virUSBDeviceListGet(list, i);
        virUSBDeviceListSteal(driver->activeUsbHostdevs, tmp);
713
    }
714
    virObjectUnlock(driver->activeUsbHostdevs);
715
    return -1;
716 717
}

718 719 720
int
qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
                         bool mandatory,
721
                         virUSBDevicePtr *usb)
722 723 724 725 726
{
    unsigned vendor = hostdev->source.subsys.u.usb.vendor;
    unsigned product = hostdev->source.subsys.u.usb.product;
    unsigned bus = hostdev->source.subsys.u.usb.bus;
    unsigned device = hostdev->source.subsys.u.usb.device;
727
    bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
728
    int rc;
729

730
    *usb = NULL;
731

732
    if (vendor && bus) {
733 734 735 736
        rc = virUSBDeviceFind(vendor, product, bus, device,
                              NULL,
                              autoAddress ? false : mandatory,
                              usb);
737
        if (rc < 0) {
738
            return -1;
739 740 741 742 743 744 745 746 747 748 749 750 751 752
        } else if (!autoAddress) {
            goto out;
        } else {
            VIR_INFO("USB device %x:%x could not be found at previous"
                     " address (bus:%u device:%u)",
                     vendor, product, bus, device);
        }
    }

    /* When vendor is specified, its USB address is either unspecified or the
     * device could not be found at the USB device where it had been
     * automatically found before.
     */
    if (vendor) {
753
        virUSBDeviceListPtr devs;
754

755
        rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
756 757 758 759
        if (rc < 0)
            return -1;

        if (rc == 1) {
760 761
            *usb = virUSBDeviceListGet(devs, 0);
            virUSBDeviceListSteal(devs, *usb);
762
        }
763
        virObjectUnref(devs);
764

765 766 767
        if (rc == 0) {
            goto out;
        } else if (rc > 1) {
768 769 770 771 772 773 774 775 776 777 778
            if (autoAddress) {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("Multiple USB devices for %x:%x were found,"
                                 " but none of them is at bus:%u device:%u"),
                               vendor, product, bus, device);
            } else {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("Multiple USB devices for %x:%x, "
                                 "use <address> to specify one"),
                               vendor, product);
            }
779 780
            return -1;
        }
781

782 783
        hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
        hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
784 785 786 787 788 789 790 791 792 793
        hostdev->source.subsys.u.usb.autoAddress = true;

        if (autoAddress) {
            VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
                     " from bus:%u device:%u)",
                     vendor, product,
                     hostdev->source.subsys.u.usb.bus,
                     hostdev->source.subsys.u.usb.device,
                     bus, device);
        }
794
    } else if (!vendor && bus) {
795
        if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
796
            return -1;
797 798
    }

799 800
out:
    if (!*usb)
801
        hostdev->missing = true;
802
    return 0;
803 804
}

805
static int
806
qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
807 808
                          virDomainDefPtr def,
                          bool coldBoot)
809 810
{
    int i, ret = -1;
811 812
    virUSBDeviceListPtr list;
    virUSBDevicePtr tmp;
813 814
    virDomainHostdevDefPtr *hostdevs = def->hostdevs;
    int nhostdevs = def->nhostdevs;
815 816 817 818 819 820

    /* To prevent situation where USB device is assigned to two domains
     * we need to keep a list of currently assigned USB devices.
     * This is done in several loops which cannot be joined into one big
     * loop. See qemuPrepareHostdevPCIDevices()
     */
821
    if (!(list = virUSBDeviceListNew()))
822 823
        goto cleanup;

824
    /* Loop 1: build temporary list
825
     */
826
    for (i = 0; i < nhostdevs; i++) {
827
        virDomainHostdevDefPtr hostdev = hostdevs[i];
828
        bool required = true;
829
        virUSBDevicePtr usb;
830 831 832 833 834 835

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

836 837 838 839 840 841
        if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
            (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
             !coldBoot))
            required = false;

        if (qemuFindHostdevUSBDevice(hostdev, required, &usb) < 0)
842
            goto cleanup;
843

844 845
        if (usb && virUSBDeviceListAdd(list, usb) < 0) {
            virUSBDeviceFree(usb);
846
            goto cleanup;
847 848 849
        }
    }

850
    /* Mark devices in temporary list as used by @name
851 852 853
     * and add them do driver list. However, if something goes
     * wrong, perform rollback.
     */
854
    if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0)
855
        goto cleanup;
856

857
    /* Loop 2: Temporary list was successfully merged with
858 859 860
     * driver list, so steal all items to avoid freeing them
     * in cleanup label.
     */
861 862 863
    while (virUSBDeviceListCount(list) > 0) {
        tmp = virUSBDeviceListGet(list, 0);
        virUSBDeviceListSteal(list, tmp);
864 865 866 867 868
    }

    ret = 0;

cleanup:
869
    virObjectUnref(list);
870
    return ret;
871 872
}

873 874 875 876 877 878 879 880 881 882
int
qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
                              const char *name,
                              virDomainHostdevDefPtr *hostdevs,
                              int nhostdevs)
{
    int i, j, count;
    virSCSIDeviceListPtr list;
    virSCSIDevicePtr tmp;

883 884 885 886 887 888 889 890 891 892 893
    /* Loop 1: Add the shared scsi host device to shared device
     * table.
     */
    for (i = 0; i < nhostdevs; i++) {
        virDomainDeviceDef dev;

        dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
        dev.data.hostdev = hostdevs[i];

        if (qemuAddSharedDevice(driver, &dev, name) < 0)
            return -1;
894 895 896

        if (qemuSetUnprivSGIO(&dev) < 0)
            return -1;
897 898
    }

899 900 901 902 903 904 905 906
    /* To prevent situation where SCSI device is assigned to two domains
     * we need to keep a list of currently assigned SCSI devices.
     * This is done in several loops which cannot be joined into one big
     * loop. See qemuPrepareHostdevPCIDevices()
     */
    if (!(list = virSCSIDeviceListNew()))
        goto cleanup;

907
    /* Loop 2: build temporary list */
908
    for (i = 0; i < nhostdevs; i++) {
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
        virDomainHostdevDefPtr hostdev = hostdevs[i];
        virSCSIDevicePtr scsi;

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

        if (hostdev->managed) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("SCSI host device doesn't support managed mode"));
            goto cleanup;
        }

        if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
                                      hostdev->readonly)))
            goto cleanup;

        if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) {
            virSCSIDeviceFree(scsi);
            goto cleanup;
        }
    }

935
    /* Loop 3: Mark devices in temporary list as used by @name
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
     * and add them to driver list. However, if something goes
     * wrong, perform rollback.
     */
    virObjectLock(driver->activeScsiHostdevs);
    count = virSCSIDeviceListCount(list);

    for (i = 0; i < count; i++) {
        virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
        if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) {
            const char *other_name = virSCSIDeviceGetUsedBy(tmp);

            if (other_name)
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("SCSI device %s is in use by domain %s"),
                               virSCSIDeviceGetName(tmp), other_name);
            else
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("SCSI device %s is already in use"),
                               virSCSIDeviceGetName(tmp));
            goto error;
        }

        virSCSIDeviceSetUsedBy(scsi, name);
        VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi));

        if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0)
            goto error;
    }

    virObjectUnlock(driver->activeScsiHostdevs);

967
    /* Loop 4: Temporary list was successfully merged with
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
     * driver list, so steal all items to avoid freeing them
     * when freeing temporary list.
     */
    while (virSCSIDeviceListCount(list) > 0) {
        tmp = virSCSIDeviceListGet(list, 0);
        virSCSIDeviceListSteal(list, tmp);
    }

    virObjectUnref(list);
    return 0;

error:
    for (j = 0; j < i; j++) {
        tmp = virSCSIDeviceListGet(list, i);
        virSCSIDeviceListSteal(driver->activeScsiHostdevs, tmp);
    }
    virObjectUnlock(driver->activeScsiHostdevs);
cleanup:
    virObjectUnref(list);
    return -1;
}

990
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
991 992
                           virDomainDefPtr def,
                           bool coldBoot)
993 994 995 996
{
    if (!def->nhostdevs)
        return 0;

997 998
    if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
                                     def->hostdevs, def->nhostdevs) < 0)
999 1000
        return -1;

1001
    if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
1002 1003
        return -1;

1004 1005 1006 1007
    if (qemuPrepareHostdevSCSIDevices(driver, def->name,
                                      def->hostdevs, def->nhostdevs) < 0)
        return -1;

1008 1009 1010 1011
    return 0;
}


1012 1013 1014 1015
/*
 * Pre-condition: driver->inactivePciHostdevs & driver->activePciHostdevs
 * are locked
 */
1016
void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver)
1017 1018 1019
{
    int retries = 100;

1020 1021 1022
    /* If the device is not managed and was attached to guest
     * successfully, it must have been inactive.
     */
1023 1024 1025
    if (!virPCIDeviceGetManaged(dev)) {
        if (virPCIDeviceListAdd(driver->inactivePciHostdevs, dev) < 0)
            virPCIDeviceFree(dev);
1026
        return;
1027
    }
1028

1029
    while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
1030 1031 1032 1033 1034
           && retries) {
        usleep(100*1000);
        retries--;
    }

1035
    if (virPCIDeviceReattach(dev, driver->activePciHostdevs,
1036
                             driver->inactivePciHostdevs) < 0) {
1037 1038 1039 1040
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to re-attach PCI device: %s"),
                  err ? err->message : _("unknown error"));
        virResetError(err);
1041
    }
1042
    virPCIDeviceFree(dev);
1043 1044 1045
}


1046
void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
1047
                                      const char *name,
1048 1049 1050
                                      virDomainHostdevDefPtr *hostdevs,
                                      int nhostdevs)
{
1051
    virPCIDeviceListPtr pcidevs;
1052
    int i;
1053
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
1054

1055 1056 1057
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

1058 1059 1060
    if (!(pcidevs = qemuGetActivePciHostDeviceList(driver,
                                                   hostdevs,
                                                   nhostdevs))) {
1061
        virErrorPtr err = virGetLastError();
1062
        VIR_ERROR(_("Failed to allocate PCI device list: %s"),
1063 1064
                  err ? err->message : _("unknown error"));
        virResetError(err);
1065
        goto cleanup;
1066 1067
    }

1068 1069 1070 1071
    /* Again 4 loops; mark all devices as inactive before reset
     * them and reset all the devices before re-attach.
     * Attach mac and port profile parameters to devices
     */
1072 1073 1074
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr activeDev = NULL;
1075 1076 1077 1078

        /* Never delete the dev from list driver->activePciHostdevs
         * if it's used by other domain.
         */
1079
        activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
1080
        if (activeDev &&
1081 1082
            STRNEQ_NULLABLE(name, virPCIDeviceGetUsedBy(activeDev))) {
            virPCIDeviceListSteal(pcidevs, dev);
1083
            continue;
1084
        }
1085

1086
        /* virObjectUnref() will take care of freeing the dev. */
1087
        virPCIDeviceListSteal(driver->activePciHostdevs, dev);
1088 1089
    }

1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
    /*
     * For SRIOV net host devices, unset mac and port profile before
     * reset and reattach device
     */
    for (i = 0; i < nhostdevs; i++) {
         virDomainHostdevDefPtr hostdev = hostdevs[i];
         if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
             continue;
         if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
             continue;
         if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
             hostdev->parent.data.net) {
1102
             qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
1103 1104 1105
         }
    }

1106 1107 1108 1109
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceReset(dev, driver->activePciHostdevs,
                              driver->inactivePciHostdevs) < 0) {
1110 1111 1112 1113 1114 1115 1116
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to reset PCI device: %s"),
                      err ? err->message : _("unknown error"));
            virResetError(err);
        }
    }

1117 1118
    while (virPCIDeviceListCount(pcidevs) > 0) {
        virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
1119 1120 1121
        qemuReattachPciDevice(dev, driver);
    }

1122
    virObjectUnref(pcidevs);
1123
cleanup:
1124 1125
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
1126
    virObjectUnref(cfg);
1127 1128
}

1129
static void
1130
qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
1131 1132 1133 1134 1135 1136
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
    int i;

1137
    virObjectLock(driver->activeUsbHostdevs);
1138 1139
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
1140
        virUSBDevicePtr usb, tmp;
1141 1142 1143 1144 1145 1146
        const char *used_by = NULL;

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

1150 1151 1152
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167

        if (!usb) {
            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
                     hostdev->source.subsys.u.usb.bus,
                     hostdev->source.subsys.u.usb.device,
                     name);
            continue;
        }

        /* Delete only those USB devices which belongs
         * to domain @name because qemuProcessStart() might
         * have failed because USB device is already taken.
         * Therefore we want to steal only those devices from
         * the list which were taken by @name */

1168 1169
        tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb);
        virUSBDeviceFree(usb);
1170 1171 1172 1173 1174 1175 1176 1177 1178

        if (!tmp) {
            VIR_WARN("Unable to find device %03d.%03d "
                     "in list of active USB devices",
                     hostdev->source.subsys.u.usb.bus,
                     hostdev->source.subsys.u.usb.device);
            continue;
        }

1179
        used_by = virUSBDeviceGetUsedBy(tmp);
1180 1181 1182 1183 1184 1185
        if (STREQ_NULLABLE(used_by, name)) {
            VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
                      hostdev->source.subsys.u.usb.bus,
                      hostdev->source.subsys.u.usb.device,
                      name);

1186
            virUSBDeviceListDel(driver->activeUsbHostdevs, tmp);
1187 1188
        }
    }
1189
    virObjectUnlock(driver->activeUsbHostdevs);
1190
}
1191

1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
void
qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
                                  const char *name,
                                  virDomainHostdevDefPtr *hostdevs,
                                  int nhostdevs)
{
    int i;

    virObjectLock(driver->activeScsiHostdevs);
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
        virSCSIDevicePtr scsi, tmp;
        const char *used_by = NULL;
1205 1206 1207 1208 1209 1210
        virDomainDeviceDef dev;

        dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
        dev.data.hostdev = hostdev;

        ignore_value(qemuRemoveSharedDevice(driver, &dev, name));
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260

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

        if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
                                      hostdev->readonly))) {
            VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on domain %s",
                     hostdev->source.subsys.u.scsi.adapter,
                     hostdev->source.subsys.u.scsi.bus,
                     hostdev->source.subsys.u.scsi.target,
                     hostdev->source.subsys.u.scsi.unit,
                     name);
            continue;
        }

        /* Only delete the devices which are marked as being used by @name,
         * because qemuProcessStart could fail on the half way. */

        tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi);
        virSCSIDeviceFree(scsi);

        if (!tmp) {
            VIR_WARN("Unable to find device %s:%d:%d:%d "
                     "in list of active SCSI devices",
                     hostdev->source.subsys.u.scsi.adapter,
                     hostdev->source.subsys.u.scsi.bus,
                     hostdev->source.subsys.u.scsi.target,
                     hostdev->source.subsys.u.scsi.unit);
            continue;
        }

        used_by = virSCSIDeviceGetUsedBy(tmp);
        if (STREQ_NULLABLE(used_by, name)) {
            VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs",
                      hostdev->source.subsys.u.scsi.adapter,
                      hostdev->source.subsys.u.scsi.bus,
                      hostdev->source.subsys.u.scsi.target,
                      hostdev->source.subsys.u.scsi.unit,
                      name);

            virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp);
        }
    }
    virObjectUnlock(driver->activeScsiHostdevs);
}

1261
void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
1262 1263 1264 1265 1266
                                   virDomainDefPtr def)
{
    if (!def->nhostdevs)
        return;

1267 1268
    qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
1269 1270 1271

    qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
1272 1273 1274

    qemuDomainReAttachHostScsiDevices(driver, def->name, def->hostdevs,
                                      def->nhostdevs);
1275
}