qemu_hostdev.c 42.7 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
    size_t i;
42

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
            if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) {
                virObjectUnref(list);
                return NULL;
            }
77
        } else {
78 79 80 81
            if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) {
                virObjectUnref(list);
                return NULL;
            }
82
        }
83 84 85 86 87
    }

    return list;
}

88

89
/*
90 91 92 93 94 95
 * qemuGetActivePciHostDeviceList - make a new list with a *copy* of
 *   every virPCIDevice object that is found on the activePciHostdevs
 *   list *and* is in the hostdev list for this domain.
 *
 * Return the new list, or NULL if there was a failure.
 *
96 97
 * Pre-condition: driver->activePciHostdevs is locked
 */
98
static virPCIDeviceListPtr
99
qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver,
100 101 102
                               virDomainHostdevDefPtr *hostdevs,
                               int nhostdevs)
{
103
    virPCIDeviceListPtr list;
104
    size_t i;
105

106
    if (!(list = virPCIDeviceListNew()))
107 108
        return NULL;

109
    for (i = 0; i < nhostdevs; i++) {
110
        virDomainHostdevDefPtr hostdev = hostdevs[i];
111
        virDevicePCIAddressPtr addr;
112
        virPCIDevicePtr activeDev;
113 114 115 116 117 118

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

119 120 121 122 123
        addr = &hostdev->source.subsys.u.pci.addr;
        activeDev = virPCIDeviceListFindByIDs(driver->activePciHostdevs,
                                              addr->domain, addr->bus,
                                              addr->slot, addr->function);
        if (activeDev && virPCIDeviceListAddCopy(list, activeDev) < 0) {
124
            virObjectUnref(list);
125 126 127 128 129 130
            return NULL;
        }
    }

    return list;
}
131

132 133 134 135

int
qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
                            virDomainDefPtr def)
136
{
137
    virDomainHostdevDefPtr hostdev = NULL;
138
    virPCIDevicePtr dev = NULL;
139
    size_t i;
140
    int ret = -1;
141 142 143 144

    if (!def->nhostdevs)
        return 0;

145 146 147
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

148 149 150 151 152 153 154 155
    for (i = 0; i < def->nhostdevs; i++) {
        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;

156 157 158 159
        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);
160 161

        if (!dev)
162
            goto cleanup;
163

164
        virPCIDeviceSetManaged(dev, hostdev->managed);
165
        if (hostdev->source.subsys.u.pci.backend
166
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
167 168
            if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0)
                goto cleanup;
169
        } else {
170 171 172
            if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0)
                goto cleanup;

173
        }
174
        virPCIDeviceSetUsedBy(dev, def->name);
175 176

        /* Setup the original states for the PCI device */
177 178 179
        virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub);
        virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot);
        virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe);
180

181
        if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0)
182
            goto cleanup;
183
        dev = NULL;
184 185
    }

186
    ret = 0;
187
cleanup:
188
    virPCIDeviceFree(dev);
189 190 191
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
    return ret;
192 193
}

194

195
int
196
qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
197 198 199
                            virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
200
    size_t i;
201
    int ret = -1;
202 203 204 205

    if (!def->nhostdevs)
        return 0;

206
    virObjectLock(driver->activeUsbHostdevs);
207
    for (i = 0; i < def->nhostdevs; i++) {
208
        virUSBDevicePtr usb = NULL;
209 210 211 212 213 214 215
        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;

216 217 218
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
219 220 221 222 223 224 225 226
        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;
        }

227
        virUSBDeviceSetUsedBy(usb, def->name);
228

229 230
        if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
            virUSBDeviceFree(usb);
231
            goto cleanup;
232 233
        }
    }
234 235 236 237
    ret = 0;
cleanup:
    virObjectUnlock(driver->activeUsbHostdevs);
    return ret;
238 239
}

240 241 242 243 244
int
qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
                             virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
245
    size_t i;
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 272 273 274 275 276 277 278 279 280
    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;
}

281

282
static int
283 284
qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev,
                              char **sysfs_path)
285
{
286
    virPCIDeviceAddress config_address;
287

288 289 290 291
    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;
292

293
    return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
294 295
}

296

297 298 299 300 301 302 303 304 305
int
qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
{
    char *sysfs_path = NULL;
    int ret = -1;

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

306
    ret = virPCIIsVirtualFunction(sysfs_path);
307 308 309 310 311 312

    VIR_FREE(sysfs_path);

    return ret;
}

313

314 315 316 317 318 319 320 321 322 323
static int
qemuDomainHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
                           int *vf)
{
    int ret = -1;
    char *sysfs_path = NULL;

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

324 325 326
    if (virPCIIsVirtualFunction(sysfs_path) == 1) {
        if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev,
                                         vf) < 0)
327 328
            goto cleanup;
    } else {
329
        if (virPCIGetNetName(sysfs_path, linkdev) < 0)
330 331 332 333 334 335 336 337 338 339 340 341
            goto cleanup;
        *vf = -1;
    }

    ret = 0;

cleanup:
    VIR_FREE(sysfs_path);

    return ret;
}

342

343 344 345
static int
qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
                                          virNetDevVPortProfilePtr virtPort,
346
                                          const virMacAddrPtr macaddr,
347
                                          const unsigned char *uuid,
348
                                          bool associate)
349 350 351 352 353 354
{
    int ret = -1;

    if (!virtPort)
        return ret;

355
    switch (virtPort->virtPortType) {
356 357 358 359
    case VIR_NETDEV_VPORT_PROFILE_NONE:
    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
    case VIR_NETDEV_VPORT_PROFILE_8021QBG:
    case VIR_NETDEV_VPORT_PROFILE_LAST:
360 361 362 363 364
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("virtualport type %s is "
                         "currently not supported on interfaces of type "
                         "hostdev"),
                       virNetDevVPortTypeToString(virtPort->virtPortType));
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
        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;
}

382

383 384 385 386 387 388
int
qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
                                  const unsigned char *uuid,
                                  char *stateDir)
{
    char *linkdev = NULL;
389
    virNetDevVlanPtr vlan;
390 391 392 393
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
    int vlanid = -1;
394
    bool port_profile_associate = true;
395 396 397 398
    int isvf;

    isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
    if (isvf <= 0) {
399 400 401
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
402 403 404 405 406 407
        return ret;
    }

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

408
    vlan = virDomainNetGetActualVlan(hostdev->parent.data.net);
409 410
    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
411 412 413 414 415 416 417 418
    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;
        }
419
        ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf,
420
                            virtPort, &hostdev->parent.data.net->mac, uuid,
421
                            port_profile_associate);
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
    } 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 */
        }

442
        ret = virNetDevReplaceNetConfig(linkdev, vf,
443 444 445 446
                                        &hostdev->parent.data.net->mac,
                                        vlanid, stateDir);
    }
cleanup:
447 448 449 450
    VIR_FREE(linkdev);
    return ret;
}

451

452 453 454 455 456 457 458 459
int
qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
                                  char *stateDir)
{
    char *linkdev = NULL;
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
460
    bool port_profile_associate = false;
461 462 463 464
    int isvf;

    isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
    if (isvf <= 0) {
465 466 467
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
468 469 470 471 472 473 474 475 476 477
        return ret;
    }

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

    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
    if (virtPort)
        ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
478
                                          &hostdev->parent.data.net->mac, NULL,
479 480 481 482 483 484 485 486 487
                                          port_profile_associate);
    else
        ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);

    VIR_FREE(linkdev);

    return ret;
}

488 489 490 491 492 493 494

int
qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
                             const char *name,
                             const unsigned char *uuid,
                             virDomainHostdevDefPtr *hostdevs,
                             int nhostdevs)
495
{
496
    virPCIDeviceListPtr pcidevs;
497
    int last_processed_hostdev_vf = -1;
498
    size_t i;
499
    int ret = -1;
500
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
501

502 503 504
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

505
    if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
506
        goto cleanup;
507

508
    /* We have to use 9 loops here. *All* devices must
509 510 511 512 513 514
     * 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.
     */

515
    /* Loop 1: validate that non-managed device isn't in use, eg
516 517 518 519
     * by checking that device is either un-bound, or bound
     * to pci-stub.ko
     */

520 521 522
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr other;
523

524
        if (!virPCIDeviceIsAssignable(dev, !cfg->relaxedACS)) {
525 526
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is not assignable"),
527
                           virPCIDeviceGetName(dev));
528 529 530 531 532
            goto cleanup;
        }
        /* The device is in use by other active domain if
         * the dev is in list driver->activePciHostdevs.
         */
533 534
        if ((other = virPCIDeviceListFind(driver->activePciHostdevs, dev))) {
            const char *other_name = virPCIDeviceGetUsedBy(other);
535 536

            if (other_name)
537 538
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("PCI device %s is in use by domain %s"),
539
                               virPCIDeviceGetName(dev), other_name);
540
            else
541 542
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("PCI device %s is already in use"),
543
                               virPCIDeviceGetName(dev));
544 545 546 547
            goto cleanup;
        }
    }

548
    /* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */
549 550 551
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceGetManaged(dev) &&
552
            virPCIDeviceDetach(dev, driver->activePciHostdevs, NULL) < 0)
553
            goto reattachdevs;
554 555
    }

556 557
    /* Loop 3: Now that all the PCI hostdevs have been detached, we
     * can safely reset them */
558 559
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
560

561 562
        if (virPCIDeviceReset(dev, driver->activePciHostdevs,
                              driver->inactivePciHostdevs) < 0)
563
            goto reattachdevs;
564 565
    }

566 567 568 569 570 571 572 573 574 575 576
    /* 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,
577
                                                   cfg->stateDir) < 0) {
578 579 580 581 582 583 584
                 goto resetvfnetconfig;
             }
         }
         last_processed_hostdev_vf = i;
    }

    /* Loop 5: Now mark all the devices as active */
585 586 587
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0)
588
            goto inactivedevs;
589 590
    }

591
    /* Loop 6: Now remove the devices from inactive list. */
592 593 594
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
         virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
         virPCIDeviceListDel(driver->inactivePciHostdevs, dev);
595 596
    }

597
    /* Loop 7: Now set the used_by_domain of the device in
598 599
     * driver->activePciHostdevs as domain name.
     */
600 601
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev, activeDev;
602

603 604
        dev = virPCIDeviceListGet(pcidevs, i);
        activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
605

606
        if (activeDev)
607
            virPCIDeviceSetUsedBy(activeDev, name);
608 609
    }

610
    /* Loop 8: Now set the original states for hostdev def */
611
    for (i = 0; i < nhostdevs; i++) {
612 613
        virPCIDevicePtr dev;
        virPCIDevicePtr pcidev;
614 615 616 617 618 619 620
        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;

621 622 623 624
        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);
625 626 627 628 629

        /* original states "unbind_from_stub", "remove_slot",
         * "reprobe" were already set by pciDettachDevice in
         * loop 2.
         */
630
        if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) {
631
            hostdev->origstates.states.pci.unbind_from_stub =
632
                virPCIDeviceGetUnbindFromStub(pcidev);
633
            hostdev->origstates.states.pci.remove_slot =
634
                virPCIDeviceGetRemoveSlot(pcidev);
635
            hostdev->origstates.states.pci.reprobe =
636
                virPCIDeviceGetReprobe(pcidev);
637 638
        }

639
        virPCIDeviceFree(dev);
640 641
    }

642
    /* Loop 9: Now steal all the devices from pcidevs */
643 644
    while (virPCIDeviceListCount(pcidevs) > 0)
        virPCIDeviceListStealIndex(pcidevs, 0);
645

646
    ret = 0;
647 648 649 650
    goto cleanup;

inactivedevs:
    /* Only steal all the devices from driver->activePciHostdevs. We will
651
     * free them in virObjectUnref().
652
     */
653 654
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
655
        virPCIDeviceListSteal(driver->activePciHostdevs, dev);
656
    }
657

658
resetvfnetconfig:
659 660
    for (i = 0; last_processed_hostdev_vf != -1 &&
                i < last_processed_hostdev_vf; i++) {
661 662 663
         virDomainHostdevDefPtr hostdev = hostdevs[i];
         if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
             hostdev->parent.data.net) {
664
             qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
665 666 667
         }
    }

668
reattachdevs:
669 670
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
671 672 673 674

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

678
cleanup:
679 680
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
681
    virObjectUnref(pcidevs);
682
    virObjectUnref(cfg);
683 684 685
    return ret;
}

686

687
int
688
qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
689
                             const char *name,
690
                             virUSBDeviceListPtr list)
691
{
692
    size_t i, j;
693
    unsigned int count;
694
    virUSBDevicePtr tmp;
695

696
    virObjectLock(driver->activeUsbHostdevs);
697
    count = virUSBDeviceListCount(list);
698 699

    for (i = 0; i < count; i++) {
700 701 702
        virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
        if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) {
            const char *other_name = virUSBDeviceGetUsedBy(tmp);
703 704

            if (other_name)
705 706
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is in use by domain %s"),
707
                               virUSBDeviceGetName(tmp), other_name);
708
            else
709 710
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is already in use"),
711
                               virUSBDeviceGetName(tmp));
712
            goto error;
713 714
        }

715
        virUSBDeviceSetUsedBy(usb, name);
716
        VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
717
                  virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
718 719
        /*
         * The caller is responsible to steal these usb devices
720
         * from the virUSBDeviceList that passed in on success,
721 722
         * perform rollback on failure.
         */
723
        if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0)
724
            goto error;
725
    }
726 727

    virObjectUnlock(driver->activeUsbHostdevs);
728
    return 0;
729 730 731

error:
    for (j = 0; j < i; j++) {
732 733
        tmp = virUSBDeviceListGet(list, i);
        virUSBDeviceListSteal(driver->activeUsbHostdevs, tmp);
734
    }
735
    virObjectUnlock(driver->activeUsbHostdevs);
736
    return -1;
737 738
}

739

740 741 742
int
qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
                         bool mandatory,
743
                         virUSBDevicePtr *usb)
744 745 746 747 748
{
    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;
749
    bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
750
    int rc;
751

752
    *usb = NULL;
753

754
    if (vendor && bus) {
755 756 757 758
        rc = virUSBDeviceFind(vendor, product, bus, device,
                              NULL,
                              autoAddress ? false : mandatory,
                              usb);
759
        if (rc < 0) {
760
            return -1;
761 762 763 764 765 766 767 768 769 770 771 772 773 774
        } 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) {
775
        virUSBDeviceListPtr devs;
776

777
        rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
778 779 780 781
        if (rc < 0)
            return -1;

        if (rc == 1) {
782 783
            *usb = virUSBDeviceListGet(devs, 0);
            virUSBDeviceListSteal(devs, *usb);
784
        }
785
        virObjectUnref(devs);
786

787 788 789
        if (rc == 0) {
            goto out;
        } else if (rc > 1) {
790 791 792 793 794 795 796 797 798 799 800
            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);
            }
801 802
            return -1;
        }
803

804 805
        hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
        hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
806 807 808 809 810 811 812 813 814 815
        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);
        }
816
    } else if (!vendor && bus) {
817
        if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
818
            return -1;
819 820
    }

821 822
out:
    if (!*usb)
823
        hostdev->missing = true;
824
    return 0;
825 826
}

827

828
static int
829
qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
830 831
                          virDomainDefPtr def,
                          bool coldBoot)
832
{
833 834
    size_t i;
    int ret = -1;
835 836
    virUSBDeviceListPtr list;
    virUSBDevicePtr tmp;
837 838
    virDomainHostdevDefPtr *hostdevs = def->hostdevs;
    int nhostdevs = def->nhostdevs;
839 840 841 842 843 844

    /* 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()
     */
845
    if (!(list = virUSBDeviceListNew()))
846 847
        goto cleanup;

848
    /* Loop 1: build temporary list
849
     */
850
    for (i = 0; i < nhostdevs; i++) {
851
        virDomainHostdevDefPtr hostdev = hostdevs[i];
852
        bool required = true;
853
        virUSBDevicePtr usb;
854 855 856 857 858 859

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

860 861 862 863 864 865
        if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
            (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
             !coldBoot))
            required = false;

        if (qemuFindHostdevUSBDevice(hostdev, required, &usb) < 0)
866
            goto cleanup;
867

868 869
        if (usb && virUSBDeviceListAdd(list, usb) < 0) {
            virUSBDeviceFree(usb);
870
            goto cleanup;
871 872 873
        }
    }

874
    /* Mark devices in temporary list as used by @name
875 876 877
     * and add them do driver list. However, if something goes
     * wrong, perform rollback.
     */
878
    if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0)
879
        goto cleanup;
880

881
    /* Loop 2: Temporary list was successfully merged with
882 883 884
     * driver list, so steal all items to avoid freeing them
     * in cleanup label.
     */
885 886 887
    while (virUSBDeviceListCount(list) > 0) {
        tmp = virUSBDeviceListGet(list, 0);
        virUSBDeviceListSteal(list, tmp);
888 889 890 891 892
    }

    ret = 0;

cleanup:
893
    virObjectUnref(list);
894
    return ret;
895 896
}

897

898 899 900 901 902 903
int
qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
                              const char *name,
                              virDomainHostdevDefPtr *hostdevs,
                              int nhostdevs)
{
904 905
    size_t i, j;
    int count;
906 907 908
    virSCSIDeviceListPtr list;
    virSCSIDevicePtr tmp;

909 910 911 912 913 914 915 916 917 918 919
    /* 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;
920 921 922

        if (qemuSetUnprivSGIO(&dev) < 0)
            return -1;
923 924
    }

925 926 927 928 929 930 931 932
    /* 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;

933
    /* Loop 2: build temporary list */
934
    for (i = 0; i < nhostdevs; i++) {
935 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
        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;
        }
    }

961
    /* Loop 3: Mark devices in temporary list as used by @name
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
     * 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);

993
    /* Loop 4: Temporary list was successfully merged with
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
     * 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;
}

1016 1017 1018 1019 1020

int
qemuPrepareHostDevices(virQEMUDriverPtr driver,
                       virDomainDefPtr def,
                       bool coldBoot)
1021 1022 1023 1024
{
    if (!def->nhostdevs)
        return 0;

1025 1026
    if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
                                     def->hostdevs, def->nhostdevs) < 0)
1027 1028
        return -1;

1029
    if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
1030 1031
        return -1;

1032 1033 1034 1035
    if (qemuPrepareHostdevSCSIDevices(driver, def->name,
                                      def->hostdevs, def->nhostdevs) < 0)
        return -1;

1036 1037 1038 1039
    return 0;
}


1040 1041 1042 1043
/*
 * Pre-condition: driver->inactivePciHostdevs & driver->activePciHostdevs
 * are locked
 */
1044 1045
void
qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver)
1046 1047 1048
{
    int retries = 100;

1049 1050 1051
    /* If the device is not managed and was attached to guest
     * successfully, it must have been inactive.
     */
1052 1053 1054
    if (!virPCIDeviceGetManaged(dev)) {
        if (virPCIDeviceListAdd(driver->inactivePciHostdevs, dev) < 0)
            virPCIDeviceFree(dev);
1055
        return;
1056
    }
1057

1058
    while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
1059 1060 1061 1062 1063
           && retries) {
        usleep(100*1000);
        retries--;
    }

1064
    if (virPCIDeviceReattach(dev, driver->activePciHostdevs,
1065
                             driver->inactivePciHostdevs) < 0) {
1066 1067 1068 1069
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to re-attach PCI device: %s"),
                  err ? err->message : _("unknown error"));
        virResetError(err);
1070
    }
1071
    virPCIDeviceFree(dev);
1072 1073 1074
}


1075 1076 1077 1078 1079
void
qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
1080
{
1081
    virPCIDeviceListPtr pcidevs;
1082
    size_t i;
1083
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
1084

1085 1086 1087
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

1088 1089 1090
    if (!(pcidevs = qemuGetActivePciHostDeviceList(driver,
                                                   hostdevs,
                                                   nhostdevs))) {
1091
        virErrorPtr err = virGetLastError();
1092
        VIR_ERROR(_("Failed to allocate PCI device list: %s"),
1093 1094
                  err ? err->message : _("unknown error"));
        virResetError(err);
1095
        goto cleanup;
1096 1097
    }

1098 1099 1100 1101
    /* 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
     */
1102 1103 1104
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr activeDev = NULL;
1105

1106 1107 1108
        /* delete the copy of the dev from pcidevs if it's used by
         * other domain. Or delete it from activePciHostDevs if it had
         * been used by this domain.
1109
         */
1110
        activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
1111
        if (activeDev &&
1112
            STRNEQ_NULLABLE(name, virPCIDeviceGetUsedBy(activeDev))) {
1113
            virPCIDeviceListDel(pcidevs, dev);
1114
            continue;
1115
        }
1116

1117
        virPCIDeviceListDel(driver->activePciHostdevs, dev);
1118 1119
    }

1120 1121 1122 1123
    /* At this point, any device that had been used by the guest is in
     * pcidevs, but has been removed from activePciHostdevs.
     */

1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
    /*
     * 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) {
1136
             qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
1137 1138 1139
         }
    }

1140 1141
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
1142

1143 1144
        if (virPCIDeviceReset(dev, driver->activePciHostdevs,
                              driver->inactivePciHostdevs) < 0) {
1145 1146 1147 1148 1149 1150 1151
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to reset PCI device: %s"),
                      err ? err->message : _("unknown error"));
            virResetError(err);
        }
    }

1152 1153
    while (virPCIDeviceListCount(pcidevs) > 0) {
        virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
1154 1155 1156
        qemuReattachPciDevice(dev, driver);
    }

1157
    virObjectUnref(pcidevs);
1158
cleanup:
1159 1160
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
1161
    virObjectUnref(cfg);
1162 1163
}

1164

1165
static void
1166
qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
1167 1168 1169 1170
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
1171
    size_t i;
1172

1173
    virObjectLock(driver->activeUsbHostdevs);
1174 1175
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
1176
        virUSBDevicePtr usb, tmp;
1177 1178 1179 1180 1181 1182
        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;
1183 1184
        if (hostdev->missing)
            continue;
1185

1186 1187 1188
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203

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

1204 1205
        tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb);
        virUSBDeviceFree(usb);
1206 1207 1208 1209 1210 1211 1212 1213 1214

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

1215
        used_by = virUSBDeviceGetUsedBy(tmp);
1216 1217 1218 1219 1220 1221
        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);

1222
            virUSBDeviceListDel(driver->activeUsbHostdevs, tmp);
1223 1224
        }
    }
1225
    virObjectUnlock(driver->activeUsbHostdevs);
1226
}
1227

1228

1229 1230 1231 1232 1233 1234
void
qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
                                  const char *name,
                                  virDomainHostdevDefPtr *hostdevs,
                                  int nhostdevs)
{
1235
    size_t i;
1236 1237 1238 1239 1240 1241

    virObjectLock(driver->activeScsiHostdevs);
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
        virSCSIDevicePtr scsi, tmp;
        const char *used_by = NULL;
1242 1243 1244 1245 1246 1247
        virDomainDeviceDef dev;

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

        ignore_value(qemuRemoveSharedDevice(driver, &dev, name));
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297

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

1298 1299 1300
void
qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
                              virDomainDefPtr def)
1301 1302 1303 1304
{
    if (!def->nhostdevs)
        return;

1305 1306
    qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
1307 1308 1309

    qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
1310 1311 1312

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