virhostdev.c 55.5 KB
Newer Older
1 2
/* virhostdev.c: hostdev management
 *
3
 * Copyright (C) 2006-2007, 2009-2015 Red Hat, Inc.
4
 * Copyright (C) 2006 Daniel P. Berrange
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
 *
 * 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
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
21
 * Author: Daniel P. Berrange <berrange@redhat.com>
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 * Author: Chunyan Liu <cyliu@suse.com>
 */

#include <config.h>

#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include "virhostdev.h"
#include "viralloc.h"
#include "virstring.h"
#include "virfile.h"
#include "virerror.h"
#include "virlog.h"
#include "virutil.h"
42
#include "virnetdev.h"
43 44 45
#include "configmake.h"

#define VIR_FROM_THIS VIR_FROM_NONE
46 47 48

VIR_LOG_INIT("util.hostdev");

49 50
#define HOSTDEV_STATE_DIR LOCALSTATEDIR "/run/libvirt/hostdevmgr"

51 52 53 54 55 56
static virHostdevManagerPtr manager; /* global hostdev manager, never freed */

static virClassPtr virHostdevManagerClass;
static void virHostdevManagerDispose(void *obj);
static virHostdevManagerPtr virHostdevManagerNew(void);

57
struct virHostdevIsPCINodeDeviceUsedData {
58
    virHostdevManagerPtr mgr;
59
    const char *domainName;
60
    const bool usesVFIO;
61 62
};

63 64 65 66
static int virHostdevIsPCINodeDeviceUsed(virPCIDeviceAddressPtr devAddr, void *opaque)
{
    virPCIDevicePtr other;
    int ret = -1;
67
    struct virHostdevIsPCINodeDeviceUsedData *helperData = opaque;
68

69
    other = virPCIDeviceListFindByIDs(helperData->mgr->activePCIHostdevs,
70 71
                                      devAddr->domain, devAddr->bus,
                                      devAddr->slot, devAddr->function);
72 73 74 75 76
    if (other) {
        const char *other_drvname = NULL;
        const char *other_domname = NULL;
        virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname);

77
        if (helperData->usesVFIO &&
78 79 80 81
            (other_domname && helperData->domainName) &&
            (STREQ(other_domname, helperData->domainName)))
            goto iommu_owner;

82 83 84 85
        if (other_drvname && other_domname)
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is in use by "
                             "driver %s, domain %s"),
86
                           virPCIDeviceGetName(other),
87 88 89 90
                           other_drvname, other_domname);
        else
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is in use"),
91
                           virPCIDeviceGetName(other));
92 93
        goto cleanup;
    }
94
 iommu_owner:
95 96 97 98 99
    ret = 0;
 cleanup:
    return ret;
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
static int virHostdevManagerOnceInit(void)
{
    if (!(virHostdevManagerClass = virClassNew(virClassForObject(),
                                               "virHostdevManager",
                                               sizeof(virHostdevManager),
                                               virHostdevManagerDispose)))
        return -1;

    if (!(manager = virHostdevManagerNew()))
        return -1;

    return 0;
}

VIR_ONCE_GLOBAL_INIT(virHostdevManager)
115 116

static void
117
virHostdevManagerDispose(void *obj)
118
{
119 120
    virHostdevManagerPtr hostdevMgr = obj;

121 122 123
    if (!hostdevMgr)
        return;

124 125 126 127
    virObjectUnref(hostdevMgr->activePCIHostdevs);
    virObjectUnref(hostdevMgr->inactivePCIHostdevs);
    virObjectUnref(hostdevMgr->activeUSBHostdevs);
    virObjectUnref(hostdevMgr->activeSCSIHostdevs);
128 129 130
    VIR_FREE(hostdevMgr->stateDir);
}

131 132
static virHostdevManagerPtr
virHostdevManagerNew(void)
133
{
134
    virHostdevManagerPtr hostdevMgr;
135
    bool privileged = geteuid() == 0;
136 137 138

    if (!(hostdevMgr = virObjectNew(virHostdevManagerClass)))
        return NULL;
139

140
    if (!(hostdevMgr->activePCIHostdevs = virPCIDeviceListNew()))
141 142
        goto error;

143
    if (!(hostdevMgr->activeUSBHostdevs = virUSBDeviceListNew()))
144 145
        goto error;

146
    if (!(hostdevMgr->inactivePCIHostdevs = virPCIDeviceListNew()))
147 148
        goto error;

149
    if (!(hostdevMgr->activeSCSIHostdevs = virSCSIDeviceListNew()))
150 151
        goto error;

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
    if (privileged) {
        if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0)
            goto error;

        if (virFileMakePath(hostdevMgr->stateDir) < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("Failed to create state dir '%s'"),
                           hostdevMgr->stateDir);
            goto error;
        }
    } else {
        char *rundir = NULL;
        mode_t old_umask;

        if (!(rundir = virGetUserRuntimeDirectory()))
            goto error;

        if (virAsprintf(&hostdevMgr->stateDir, "%s/hostdevmgr", rundir) < 0) {
            VIR_FREE(rundir);
            goto error;
        }
        VIR_FREE(rundir);

        old_umask = umask(077);

        if (virFileMakePath(hostdevMgr->stateDir) < 0) {
            umask(old_umask);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("Failed to create state dir '%s'"),
                           hostdevMgr->stateDir);
            goto error;
        }
        umask(old_umask);
185 186
    }

187
    return hostdevMgr;
188

189
 error:
190 191
    virObjectUnref(hostdevMgr);
    return NULL;
192 193 194 195 196
}

virHostdevManagerPtr
virHostdevManagerGetDefault(void)
{
197
    if (virHostdevManagerInitialize() < 0)
198
        return NULL;
199 200

    return virObjectRef(manager);
201
}
202 203

static virPCIDeviceListPtr
204
virHostdevGetPCIHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
205 206 207 208 209 210 211 212 213
{
    virPCIDeviceListPtr list;
    size_t i;

    if (!(list = virPCIDeviceListNew()))
        return NULL;

    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
214
        virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
215 216 217 218 219 220 221
        virPCIDevicePtr dev;

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

222 223
        dev = virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                              pcisrc->addr.slot, pcisrc->addr.function);
224 225 226 227 228 229 230 231 232 233 234
        if (!dev) {
            virObjectUnref(list);
            return NULL;
        }
        if (virPCIDeviceListAdd(list, dev) < 0) {
            virPCIDeviceFree(dev);
            virObjectUnref(list);
            return NULL;
        }

        virPCIDeviceSetManaged(dev, hostdev->managed);
235 236 237 238 239 240 241

        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
            virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_VFIO);
        else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN)
            virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_XEN);
        else
            virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_KVM);
242 243 244 245 246 247 248
    }

    return list;
}


static int
249
virHostdevPCISysfsPath(virDomainHostdevDefPtr hostdev,
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
                       char **sysfs_path)
{
    virPCIDeviceAddress config_address;

    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;

    return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
}


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

269
    if (virHostdevPCISysfsPath(hostdev, &sysfs_path) < 0)
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
        return ret;

    ret = virPCIIsVirtualFunction(sysfs_path);

    VIR_FREE(sysfs_path);

    return ret;
}


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

287
    if (virHostdevPCISysfsPath(hostdev, &sysfs_path) < 0)
288 289 290 291 292 293 294 295 296 297 298 299 300 301
        return ret;

    if (virPCIIsVirtualFunction(sysfs_path) == 1) {
        if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev,
                                         vf) < 0)
            goto cleanup;
    } else {
        if (virPCIGetNetName(sysfs_path, linkdev) < 0)
            goto cleanup;
        *vf = -1;
    }

    ret = 0;

302
 cleanup:
303 304 305 306 307 308
    VIR_FREE(sysfs_path);

    return ret;
}


309
static bool
310 311 312 313 314 315 316 317 318
virHostdevIsPCINetDevice(virDomainHostdevDefPtr hostdev)
{
    return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
        hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
        hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
        hostdev->parent.data.net;
}


319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
static int
virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
                                   virNetDevVPortProfilePtr virtPort,
                                   const virMacAddr *macaddr,
                                   const unsigned char *uuid,
                                   bool associate)
{
    int ret = -1;

    if (!virtPort)
        return ret;

    switch (virtPort->virtPortType) {
    case VIR_NETDEV_VPORT_PROFILE_NONE:
    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
    case VIR_NETDEV_VPORT_PROFILE_8021QBG:
    case VIR_NETDEV_VPORT_PROFILE_LAST:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("virtualport type %s is "
                         "currently not supported on interfaces of type "
                         "hostdev"),
                       virNetDevVPortTypeToString(virtPort->virtPortType));
        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;
}


static int
virHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
                           const unsigned char *uuid,
362
                           const char *stateDir)
363 364 365 366 367 368 369 370 371
{
    char *linkdev = NULL;
    virNetDevVlanPtr vlan;
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
    int vlanid = -1;
    bool port_profile_associate = true;

372
    if (virHostdevIsVirtualFunction(hostdev) != 1) {
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
        return ret;
    }

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

    vlan = virDomainNetGetActualVlan(hostdev->parent.data.net);
    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
    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;
        }
        ret = virHostdevNetConfigVirtPortProfile(linkdev, vf,
                            virtPort, &hostdev->parent.data.net->mac, uuid,
                            port_profile_associate);
    } 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 */
        }

        ret = virNetDevReplaceNetConfig(linkdev, vf,
                                        &hostdev->parent.data.net->mac,
                                        vlanid, stateDir);
    }
420
 cleanup:
421 422 423 424 425 426 427 428
    VIR_FREE(linkdev);
    return ret;
}

/* @oldStateDir:
 * For upgrade purpose:
 * To an existing VM on QEMU, the hostdev netconfig file is originally stored
 * in cfg->stateDir (/var/run/libvirt/qemu). Switch to new version, it uses new
429
 * location (mgr->stateDir) but certainly will not find it. In this
430 431 432 433
 * case, try to find in the old state dir.
 */
static int
virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
434 435
                           const char *stateDir,
                           const char *oldStateDir)
436 437 438 439 440 441 442 443 444 445
{
    char *linkdev = NULL;
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
    bool port_profile_associate = false;

    /* This is only needed for PCI devices that have been defined
     * using <interface type='hostdev'>. For all others, it is a NOP.
     */
446
    if (!virHostdevIsPCINetDevice(hostdev))
447 448
       return 0;

449
    if (virHostdevIsVirtualFunction(hostdev) != 1) {
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
        return ret;
    }

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

    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
    if (virtPort) {
        ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
                                                 &hostdev->parent.data.net->mac,
                                                 NULL,
                                                 port_profile_associate);
    } else {
        ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);
        if (ret < 0 && oldStateDir != NULL)
            ret = virNetDevRestoreNetConfig(linkdev, vf, oldStateDir);
    }

    VIR_FREE(linkdev);

    return ret;
}

int
478
virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
479
                            const char *drv_name,
480
                            const char *dom_name,
481 482 483 484 485 486 487 488 489
                            const unsigned char *uuid,
                            virDomainHostdevDefPtr *hostdevs,
                            int nhostdevs,
                            unsigned int flags)
{
    virPCIDeviceListPtr pcidevs = NULL;
    int last_processed_hostdev_vf = -1;
    size_t i;
    int ret = -1;
490
    virPCIDeviceAddressPtr devAddr = NULL;
491

492 493 494
    if (!nhostdevs)
        return 0;

495 496
    virObjectLock(mgr->activePCIHostdevs);
    virObjectLock(mgr->inactivePCIHostdevs);
497

498
    if (!(pcidevs = virHostdevGetPCIHostDeviceList(hostdevs, nhostdevs)))
499 500
        goto cleanup;

501 502 503 504 505 506 507 508 509
    /* Detaching devices from the host involves several steps; each
     * of them is described at length below.
     *
     * All devices must 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 */

    /* Step 1: validate that non-managed device isn't in use, eg
510 511 512 513 514 515
     * by checking that device is either un-bound, or bound
     * to pci-stub.ko
     */
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
516 517
        bool usesVFIO = (virPCIDeviceGetStubDriver(dev) == VIR_PCI_STUB_DRIVER_VFIO);
        struct virHostdevIsPCINodeDeviceUsedData data = { mgr, dom_name, usesVFIO };
518

519
        if (!usesVFIO && !virPCIDeviceIsAssignable(dev, strict_acs_check)) {
520 521 522 523 524
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is not assignable"),
                           virPCIDeviceGetName(dev));
            goto cleanup;
        }
525

526
        /* The device is in use by other active domain if
527
         * the dev is in list activePCIHostdevs. VFIO devices
M
Martin Kletzander 已提交
528
         * belonging to same iommu group can't be shared
529
         * across guests.
530
         */
531
        devAddr = virPCIDeviceGetAddress(dev);
532
        if (usesVFIO) {
533 534
            if (virPCIDeviceAddressIOMMUGroupIterate(devAddr,
                                                     virHostdevIsPCINodeDeviceUsed,
535
                                                     &data) < 0)
536
                goto cleanup;
537
        } else if (virHostdevIsPCINodeDeviceUsed(devAddr, &data)) {
538 539 540 541
            goto cleanup;
        }
    }

542
    /* Step 2: detach managed devices (i.e. bind to appropriate stub driver) */
543 544
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
545

546 547 548 549
        if (virPCIDeviceGetManaged(dev)) {
            VIR_DEBUG("Detaching managed PCI device %s",
                      virPCIDeviceGetName(dev));
            if (virPCIDeviceDetach(dev,
550 551
                                   mgr->activePCIHostdevs,
                                   mgr->inactivePCIHostdevs) < 0)
552
                goto reattachdevs;
553 554 555 556
        } else {
            VIR_DEBUG("Not detaching unmanaged PCI device %s",
                      virPCIDeviceGetName(dev));
        }
557 558
    }

559 560 561
    /* At this point, all devices are attached to the stub driver and have
     * been marked as inactive */

562
    /* Step 3: Now that all the PCI hostdevs have been detached, we
563 564 565 566
     * can safely reset them */
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

567
        VIR_DEBUG("Resetting PCI device %s", virPCIDeviceGetName(dev));
568 569
        if (virPCIDeviceReset(dev, mgr->activePCIHostdevs,
                              mgr->inactivePCIHostdevs) < 0)
570 571 572
            goto reattachdevs;
    }

573
    /* Step 4: For SRIOV network devices, Now that we have detached the
574 575 576
     * the network device, set the netdev config */
    for (i = 0; i < nhostdevs; i++) {
         virDomainHostdevDefPtr hostdev = hostdevs[i];
577
         if (!virHostdevIsPCINetDevice(hostdev))
578
             continue;
579
         if (virHostdevNetConfigReplace(hostdev, uuid,
580
                                        mgr->stateDir) < 0) {
581
             goto resetvfnetconfig;
582 583 584 585
         }
         last_processed_hostdev_vf = i;
    }

586
    /* Step 5: Now mark all the devices as active */
587 588
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
589 590 591

        VIR_DEBUG("Adding PCI device %s to active list",
                  virPCIDeviceGetName(dev));
592
        if (virPCIDeviceListAdd(mgr->activePCIHostdevs, dev) < 0)
593 594 595
            goto inactivedevs;
    }

596
    /* Step 6: Now remove the devices from inactive list. */
597
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
598 599 600 601
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

        VIR_DEBUG("Removing PCI device %s from inactive list",
                  virPCIDeviceGetName(dev));
602
        virPCIDeviceListDel(mgr->inactivePCIHostdevs, dev);
603 604
    }

605
    /* Step 7: Now set the used_by_domain of the device in
606
     * activePCIHostdevs as domain name.
607 608 609 610 611
     */
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev, activeDev;

        dev = virPCIDeviceListGet(pcidevs, i);
612
        activeDev = virPCIDeviceListFind(mgr->activePCIHostdevs, dev);
613

614 615
        VIR_DEBUG("Setting driver and domain information for PCI device %s",
                  virPCIDeviceGetName(dev));
616
        if (activeDev)
617
            virPCIDeviceSetUsedBy(activeDev, drv_name, dom_name);
618 619
    }

620
    /* Step 8: Now set the original states for hostdev def */
621 622 623
    for (i = 0; i < nhostdevs; i++) {
        virPCIDevicePtr dev;
        virDomainHostdevDefPtr hostdev = hostdevs[i];
624
        virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
625 626 627 628 629 630

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

631 632 633 634 635
        dev = virPCIDeviceListFindByIDs(pcidevs,
                                        pcisrc->addr.domain,
                                        pcisrc->addr.bus,
                                        pcisrc->addr.slot,
                                        pcisrc->addr.function);
636

637 638 639
        /* Appropriate values for the unbind_from_stub, remove_slot
         * and reprobe properties of the device were set earlier
         * by virPCIDeviceDetach() */
640 641 642
        if (dev) {
            VIR_DEBUG("Saving network configuration of PCI device %s",
                      virPCIDeviceGetName(dev));
643
            hostdev->origstates.states.pci.unbind_from_stub =
644
                virPCIDeviceGetUnbindFromStub(dev);
645
            hostdev->origstates.states.pci.remove_slot =
646
                virPCIDeviceGetRemoveSlot(dev);
647
            hostdev->origstates.states.pci.reprobe =
648
                virPCIDeviceGetReprobe(dev);
649 650 651
        }
    }

652
    /* Step 9: Now steal all the devices from pcidevs */
653 654 655 656 657 658
    while (virPCIDeviceListCount(pcidevs) > 0)
        virPCIDeviceListStealIndex(pcidevs, 0);

    ret = 0;
    goto cleanup;

659
 inactivedevs:
660
    /* Only steal all the devices from activePCIHostdevs. We will
661 662 663 664
     * free them in virObjectUnref().
     */
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
665 666 667

        VIR_DEBUG("Removing PCI device %s from active list",
                  virPCIDeviceGetName(dev));
668
        virPCIDeviceListSteal(mgr->activePCIHostdevs, dev);
669 670
    }

671
 resetvfnetconfig:
672 673
    if (last_processed_hostdev_vf >= 0) {
        for (i = 0; i <= last_processed_hostdev_vf; i++)
674
            virHostdevNetConfigRestore(hostdevs[i], mgr->stateDir, NULL);
675
    }
676

677
 reattachdevs:
678 679 680
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

681
        if (virPCIDeviceGetManaged(dev)) {
682 683
            VIR_DEBUG("Reattaching managed PCI device %s",
                      virPCIDeviceGetName(dev));
684
            ignore_value(virPCIDeviceReattach(dev,
685 686
                                              mgr->activePCIHostdevs,
                                              mgr->inactivePCIHostdevs));
687 688 689
        } else {
            VIR_DEBUG("Not reattaching unmanaged PCI device %s",
                      virPCIDeviceGetName(dev));
690
        }
691 692
    }

693
 cleanup:
694
    virObjectUnref(pcidevs);
695 696
    virObjectUnlock(mgr->activePCIHostdevs);
    virObjectUnlock(mgr->inactivePCIHostdevs);
697

698 699 700 701
    return ret;
}

/*
702
 * Pre-condition: inactivePCIHostdevs & activePCIHostdevs
703 704 705
 * are locked
 */
static void
706 707
virHostdevReattachPCIDevice(virHostdevManagerPtr mgr,
                            virPCIDevicePtr dev)
708 709 710 711 712
{
    /* If the device is not managed and was attached to guest
     * successfully, it must have been inactive.
     */
    if (!virPCIDeviceGetManaged(dev)) {
713 714
        VIR_DEBUG("Adding unmanaged PCI device %s to inactive list",
                  virPCIDeviceGetName(dev));
715
        if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, dev) < 0)
716 717 718 719 720
            virPCIDeviceFree(dev);
        return;
    }

    /* Wait for device cleanup if it is qemu/kvm */
721
    if (virPCIDeviceGetStubDriver(dev) == VIR_PCI_STUB_DRIVER_KVM) {
722 723 724 725 726 727 728 729
        int retries = 100;
        while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
               && retries) {
            usleep(100*1000);
            retries--;
        }
    }

730
    VIR_DEBUG("Reattaching PCI device %s", virPCIDeviceGetName(dev));
731 732
    if (virPCIDeviceReattach(dev, mgr->activePCIHostdevs,
                             mgr->inactivePCIHostdevs) < 0) {
733 734 735 736 737 738 739 740 741 742 743 744
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to re-attach PCI device: %s"),
                  err ? err->message : _("unknown error"));
        virResetError(err);
    }
    virPCIDeviceFree(dev);
}

/* @oldStateDir:
 * For upgrade purpose: see virHostdevNetConfigRestore
 */
void
745
virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr,
746
                             const char *drv_name,
747
                             const char *dom_name,
748 749
                             virDomainHostdevDefPtr *hostdevs,
                             int nhostdevs,
750
                             const char *oldStateDir)
751 752 753 754
{
    virPCIDeviceListPtr pcidevs;
    size_t i;

755 756 757
    if (!nhostdevs)
        return;

758 759
    virObjectLock(mgr->activePCIHostdevs);
    virObjectLock(mgr->inactivePCIHostdevs);
760

761
    if (!(pcidevs = virHostdevGetPCIHostDeviceList(hostdevs, nhostdevs))) {
762 763 764 765 766 767 768
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to allocate PCI device list: %s"),
                  err ? err->message : _("unknown error"));
        virResetError(err);
        goto cleanup;
    }

769 770
    /* Reattaching devices to the host involves several steps; each
     * of them is described at length below */
771

772
    /* Step 1: verify that each device in the hostdevs list really was in use
773
     * by this domain, and remove them all from the activePCIHostdevs list.
774
     */
775 776
    i = 0;
    while (i < virPCIDeviceListCount(pcidevs)) {
777 778 779
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr activeDev = NULL;

780
        activeDev = virPCIDeviceListFind(mgr->activePCIHostdevs, dev);
781 782 783 784 785
        if (activeDev) {
            const char *usedby_drvname;
            const char *usedby_domname;
            virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname);
            if (STRNEQ_NULLABLE(drv_name, usedby_drvname) ||
786
                STRNEQ_NULLABLE(dom_name, usedby_domname)) {
A
Andrea Bolognani 已提交
787 788 789 790

                virPCIDeviceListDel(pcidevs, dev);
                continue;
            }
791 792 793
        } else {
            virPCIDeviceListDel(pcidevs, dev);
            continue;
794 795
        }

796 797
        VIR_DEBUG("Removing PCI device %s from active list",
                  virPCIDeviceGetName(dev));
798
        virPCIDeviceListDel(mgr->activePCIHostdevs, dev);
799
        i++;
800 801 802
    }

    /* At this point, any device that had been used by the guest is in
803
     * pcidevs, but has been removed from activePCIHostdevs.
804 805
     */

806
    /* Step 2: restore original network config of hostdevs that used
807
     * <interface type='hostdev'>
808
     */
809 810 811 812 813
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];

        if (virHostdevIsPCINetDevice(hostdev)) {
            virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
814 815 816 817 818 819 820 821
            virPCIDevicePtr dev;

            dev = virPCIDeviceListFindByIDs(pcidevs,
                                            pcisrc->addr.domain,
                                            pcisrc->addr.bus,
                                            pcisrc->addr.slot,
                                            pcisrc->addr.function);

822
            if (dev) {
823 824
                VIR_DEBUG("Restoring network configuration of PCI device %s",
                          virPCIDeviceGetName(dev));
825
                virHostdevNetConfigRestore(hostdev, mgr->stateDir,
826
                                           oldStateDir);
827 828 829
            }
        }
    }
830

831
    /* Step 3: perform a PCI Reset on all devices */
832 833 834
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

835
        VIR_DEBUG("Resetting PCI device %s", virPCIDeviceGetName(dev));
836 837
        if (virPCIDeviceReset(dev, mgr->activePCIHostdevs,
                              mgr->inactivePCIHostdevs) < 0) {
838 839 840 841 842 843 844
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to reset PCI device: %s"),
                      err ? err->message : _("unknown error"));
            virResetError(err);
        }
    }

845
    /* Step 4: reattach devices to their host drivers (if managed) or place
846
     * them on the inactive list (if not managed)
847
     */
848 849
    while (virPCIDeviceListCount(pcidevs) > 0) {
        virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
850
        virHostdevReattachPCIDevice(mgr, dev);
851 852 853
    }

    virObjectUnref(pcidevs);
854
 cleanup:
855 856
    virObjectUnlock(mgr->activePCIHostdevs);
    virObjectUnlock(mgr->inactivePCIHostdevs);
857
}
858 859

int
860
virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr,
861 862
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs,
863
                                 const char *drv_name,
864
                                 const char *dom_name)
865 866 867 868 869 870
{
    virDomainHostdevDefPtr hostdev = NULL;
    virPCIDevicePtr dev = NULL;
    size_t i;
    int ret = -1;

871 872 873
    if (!nhostdevs)
        return 0;

874 875
    virObjectLock(mgr->activePCIHostdevs);
    virObjectLock(mgr->inactivePCIHostdevs);
876

877
    for (i = 0; i < nhostdevs; i++) {
878
        virDomainHostdevSubsysPCIPtr pcisrc;
879
        hostdev = hostdevs[i];
880
        pcisrc = &hostdev->source.subsys.u.pci;
881 882 883 884 885 886

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

887 888
        dev = virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                              pcisrc->addr.slot, pcisrc->addr.function);
889 890 891 892 893

        if (!dev)
            goto cleanup;

        virPCIDeviceSetManaged(dev, hostdev->managed);
894
        virPCIDeviceSetUsedBy(dev, drv_name, dom_name);
895

896 897 898 899 900 901 902
        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
            virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_VFIO);
        else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN)
            virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_XEN);
        else
            virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_KVM);

903 904 905 906 907
        /* Setup the original states for the PCI device */
        virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub);
        virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot);
        virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe);

908
        if (virPCIDeviceListAdd(mgr->activePCIHostdevs, dev) < 0)
909 910 911 912 913
            goto cleanup;
        dev = NULL;
    }

    ret = 0;
914
 cleanup:
915
    virPCIDeviceFree(dev);
916 917
    virObjectUnlock(mgr->activePCIHostdevs);
    virObjectUnlock(mgr->inactivePCIHostdevs);
918 919 920 921
    return ret;
}

int
922
virHostdevUpdateActiveUSBDevices(virHostdevManagerPtr mgr,
923 924
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs,
925
                                 const char *drv_name,
926
                                 const char *dom_name)
927 928 929 930 931
{
    virDomainHostdevDefPtr hostdev = NULL;
    size_t i;
    int ret = -1;

932 933 934
    if (!nhostdevs)
        return 0;

935
    virObjectLock(mgr->activeUSBHostdevs);
936
    for (i = 0; i < nhostdevs; i++) {
937
        virDomainHostdevSubsysUSBPtr usbsrc;
938
        virUSBDevicePtr usb = NULL;
939
        hostdev = hostdevs[i];
940
        usbsrc = &hostdev->source.subsys.u.usb;
941 942 943 944 945 946

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

947
        if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL))) {
948
            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
949
                     usbsrc->bus, usbsrc->device, dom_name);
950 951 952
            continue;
        }

953
        virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
954

955
        if (virUSBDeviceListAdd(mgr->activeUSBHostdevs, usb) < 0) {
956 957 958 959 960
            virUSBDeviceFree(usb);
            goto cleanup;
        }
    }
    ret = 0;
961
 cleanup:
962
    virObjectUnlock(mgr->activeUSBHostdevs);
963 964 965
    return ret;
}

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 993 994 995 996 997 998 999 1000 1001 1002
static int
virHostdevUpdateActiveSCSIHostDevices(virHostdevManagerPtr mgr,
                                      virDomainHostdevDefPtr hostdev,
                                      virDomainHostdevSubsysSCSIPtr scsisrc,
                                      const char *drv_name,
                                      const char *dom_name)
{
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
    virSCSIDevicePtr scsi = NULL;
    virSCSIDevicePtr tmp = NULL;
    int ret = -1;

    if (!(scsi = virSCSIDeviceNew(NULL,
                                  scsihostsrc->adapter, scsihostsrc->bus,
                                  scsihostsrc->target, scsihostsrc->unit,
                                  hostdev->readonly, hostdev->shareable)))
        goto cleanup;

    if ((tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs, scsi))) {
        if (virSCSIDeviceSetUsedBy(tmp, drv_name, dom_name) < 0) {
            virSCSIDeviceFree(scsi);
            goto cleanup;
        }
        virSCSIDeviceFree(scsi);
    } else {
        if (virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name) < 0 ||
            virSCSIDeviceListAdd(mgr->activeSCSIHostdevs, scsi) < 0) {
            virSCSIDeviceFree(scsi);
            goto cleanup;
        }
    }
    ret = 0;

 cleanup:
    return ret;
}

1003
int
1004
virHostdevUpdateActiveSCSIDevices(virHostdevManagerPtr mgr,
1005 1006
                                  virDomainHostdevDefPtr *hostdevs,
                                  int nhostdevs,
1007
                                  const char *drv_name,
1008
                                  const char *dom_name)
1009 1010 1011 1012 1013
{
    virDomainHostdevDefPtr hostdev = NULL;
    size_t i;
    int ret = -1;

1014 1015 1016
    if (!nhostdevs)
        return 0;

1017
    virObjectLock(mgr->activeSCSIHostdevs);
1018
    for (i = 0; i < nhostdevs; i++) {
1019
        virDomainHostdevSubsysSCSIPtr scsisrc;
1020
        hostdev = hostdevs[i];
1021
        scsisrc = &hostdev->source.subsys.u.scsi;
1022 1023 1024 1025 1026

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

1027 1028
        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
            continue;  /* Not supported for iSCSI */
1029
        } else {
1030 1031
            if (virHostdevUpdateActiveSCSIHostDevices(mgr, hostdev, scsisrc,
                                                      drv_name, dom_name) < 0)
1032 1033 1034 1035 1036
                goto cleanup;
        }
    }
    ret = 0;

1037
 cleanup:
1038
    virObjectUnlock(mgr->activeSCSIHostdevs);
1039 1040
    return ret;
}
1041 1042

static int
1043 1044 1045 1046
virHostdevMarkUSBDevices(virHostdevManagerPtr mgr,
                         const char *drv_name,
                         const char *dom_name,
                         virUSBDeviceListPtr list)
1047 1048 1049 1050 1051
{
    size_t i, j;
    unsigned int count;
    virUSBDevicePtr tmp;

1052
    virObjectLock(mgr->activeUSBHostdevs);
1053 1054 1055 1056
    count = virUSBDeviceListCount(list);

    for (i = 0; i < count; i++) {
        virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
1057
        if ((tmp = virUSBDeviceListFind(mgr->activeUSBHostdevs, usb))) {
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
            const char *other_drvname;
            const char *other_domname;

            virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
            if (other_drvname && other_domname)
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is in use by "
                                 "driver %s, domain %s"),
                               virUSBDeviceGetName(tmp),
                               other_drvname, other_domname);
            else
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is already in use"),
                               virUSBDeviceGetName(tmp));
            goto error;
        }

1075
        virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
1076
        VIR_DEBUG("Adding %03d.%03d dom=%s to activeUSBHostdevs",
1077 1078
                  virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb),
                  dom_name);
1079 1080 1081 1082 1083
        /*
         * The caller is responsible to steal these usb devices
         * from the virUSBDeviceList that passed in on success,
         * perform rollback on failure.
         */
1084
        if (virUSBDeviceListAdd(mgr->activeUSBHostdevs, usb) < 0)
1085 1086 1087
            goto error;
    }

1088
    virObjectUnlock(mgr->activeUSBHostdevs);
1089 1090
    return 0;

1091
 error:
1092 1093
    for (j = 0; j < i; j++) {
        tmp = virUSBDeviceListGet(list, i);
1094
        virUSBDeviceListSteal(mgr->activeUSBHostdevs, tmp);
1095
    }
1096
    virObjectUnlock(mgr->activeUSBHostdevs);
1097 1098 1099 1100 1101 1102 1103 1104 1105
    return -1;
}


static int
virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
                        bool mandatory,
                        virUSBDevicePtr *usb)
{
1106 1107 1108 1109 1110 1111
    virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb;
    unsigned vendor = usbsrc->vendor;
    unsigned product = usbsrc->product;
    unsigned bus = usbsrc->bus;
    unsigned device = usbsrc->device;
    bool autoAddress = usbsrc->autoAddress;
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
    int rc;

    *usb = NULL;

    if (vendor && bus) {
        rc = virUSBDeviceFind(vendor, product, bus, device,
                              NULL,
                              autoAddress ? false : mandatory,
                              usb);
        if (rc < 0) {
            return -1;
        } 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) {
        virUSBDeviceListPtr devs;

        rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
        if (rc < 0)
            return -1;

        if (rc == 1) {
            *usb = virUSBDeviceListGet(devs, 0);
            virUSBDeviceListSteal(devs, *usb);
        }
        virObjectUnref(devs);

        if (rc == 0) {
            goto out;
        } else if (rc > 1) {
            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);
            }
            return -1;
        }

1166 1167 1168
        usbsrc->bus = virUSBDeviceGetBus(*usb);
        usbsrc->device = virUSBDeviceGetDevno(*usb);
        usbsrc->autoAddress = true;
1169 1170 1171 1172 1173

        if (autoAddress) {
            VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
                     " from bus:%u device:%u)",
                     vendor, product,
1174
                     usbsrc->bus, usbsrc->device,
1175 1176 1177 1178 1179 1180 1181
                     bus, device);
        }
    } else if (!vendor && bus) {
        if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
            return -1;
    }

1182
 out:
1183 1184 1185 1186 1187 1188
    if (!*usb)
        hostdev->missing = true;
    return 0;
}

int
1189
virHostdevPrepareUSBDevices(virHostdevManagerPtr mgr,
1190
                            const char *drv_name,
1191
                            const char *dom_name,
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
                            virDomainHostdevDefPtr *hostdevs,
                            int nhostdevs,
                            unsigned int flags)
{
    size_t i;
    int ret = -1;
    virUSBDeviceListPtr list;
    virUSBDevicePtr tmp;
    bool coldBoot = !!(flags & VIR_HOSTDEV_COLD_BOOT);

1202 1203 1204
    if (!nhostdevs)
        return 0;

1205 1206 1207 1208 1209 1210 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
    /* 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 virHostdevPreparePCIDevices()
     */
    if (!(list = virUSBDeviceListNew()))
        goto cleanup;

    /* Loop 1: build temporary list
     */
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
        bool required = true;
        virUSBDevicePtr usb;

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

        if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
            (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
             !coldBoot))
            required = false;

        if (virHostdevFindUSBDevice(hostdev, required, &usb) < 0)
            goto cleanup;

        if (usb && virUSBDeviceListAdd(list, usb) < 0) {
            virUSBDeviceFree(usb);
            goto cleanup;
        }
    }

1239
    /* Mark devices in temporary list as used by @dom_name
1240 1241 1242
     * and add them do driver list. However, if something goes
     * wrong, perform rollback.
     */
1243
    if (virHostdevMarkUSBDevices(mgr, drv_name, dom_name, list) < 0)
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
        goto cleanup;

    /* Loop 2: Temporary list was successfully merged with
     * driver list, so steal all items to avoid freeing them
     * in cleanup label.
     */
    while (virUSBDeviceListCount(list) > 0) {
        tmp = virUSBDeviceListGet(list, 0);
        virUSBDeviceListSteal(list, tmp);
    }

    ret = 0;

1257
 cleanup:
1258 1259 1260
    virObjectUnref(list);
    return ret;
}
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
static int
virHostdevPrepareSCSIHostDevices(virDomainHostdevDefPtr hostdev,
                                 virDomainHostdevSubsysSCSIPtr scsisrc,
                                 virSCSIDeviceListPtr list)
{
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
    virSCSIDevicePtr scsi;
    int ret = -1;

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

    if (!(scsi = virSCSIDeviceNew(NULL,
                                  scsihostsrc->adapter, scsihostsrc->bus,
                                  scsihostsrc->target, scsihostsrc->unit,
                                  hostdev->readonly, hostdev->shareable)))
        goto cleanup;

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

    ret = 0;

 cleanup:
    return ret;
}

1294
int
1295
virHostdevPrepareSCSIDevices(virHostdevManagerPtr mgr,
1296
                             const char *drv_name,
1297
                             const char *dom_name,
1298 1299 1300 1301 1302 1303 1304 1305
                             virDomainHostdevDefPtr *hostdevs,
                             int nhostdevs)
{
    size_t i, j;
    int count;
    virSCSIDeviceListPtr list;
    virSCSIDevicePtr tmp;

1306 1307 1308
    if (!nhostdevs)
        return 0;

1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
    /* 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 virHostdevPreparePCIDevices()
     */
    if (!(list = virSCSIDeviceListNew()))
        goto cleanup;

    /* Loop 1: build temporary list */
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
1320
        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
1321 1322 1323 1324 1325

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

1326 1327 1328 1329 1330
        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
            continue;  /* Not supported for iSCSI */
        } else {
            if (virHostdevPrepareSCSIHostDevices(hostdev, scsisrc, list) < 0)
                goto cleanup;
1331 1332 1333 1334 1335 1336 1337
        }
    }

    /* Loop 2: Mark devices in temporary list as used by @name
     * and add them to driver list. However, if something goes
     * wrong, perform rollback.
     */
1338
    virObjectLock(mgr->activeSCSIHostdevs);
1339 1340 1341 1342
    count = virSCSIDeviceListCount(list);

    for (i = 0; i < count; i++) {
        virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
1343
        if ((tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs,
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
                                         scsi))) {
            bool scsi_shareable = virSCSIDeviceGetShareable(scsi);
            bool tmp_shareable = virSCSIDeviceGetShareable(tmp);

            if (!(scsi_shareable && tmp_shareable)) {
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("SCSI device %s is already in use by "
                                 "other domain(s) as '%s'"),
                               virSCSIDeviceGetName(tmp),
                               tmp_shareable ? "shareable" : "non-shareable");
                goto error;
            }

1357
            if (virSCSIDeviceSetUsedBy(tmp, drv_name, dom_name) < 0)
1358 1359
                goto error;
        } else {
1360
            if (virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name) < 0)
1361 1362
                goto error;

1363
            VIR_DEBUG("Adding %s to activeSCSIHostdevs", virSCSIDeviceGetName(scsi));
1364

1365
            if (virSCSIDeviceListAdd(mgr->activeSCSIHostdevs, scsi) < 0)
1366 1367 1368 1369
                goto error;
        }
    }

1370
    virObjectUnlock(mgr->activeSCSIHostdevs);
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383

    /* Loop 3: Temporary list was successfully merged with
     * 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;

1384
 error:
1385 1386
    for (j = 0; j < i; j++) {
        tmp = virSCSIDeviceListGet(list, i);
1387
        virSCSIDeviceListSteal(mgr->activeSCSIHostdevs, tmp);
1388
    }
1389
    virObjectUnlock(mgr->activeSCSIHostdevs);
1390
 cleanup:
1391 1392 1393
    virObjectUnref(list);
    return -1;
}
1394 1395

void
1396
virHostdevReAttachUSBDevices(virHostdevManagerPtr mgr,
1397 1398 1399 1400
                             const char *drv_name,
                             const char *dom_name,
                             virDomainHostdevDefPtr *hostdevs,
                             int nhostdevs)
1401 1402 1403
{
    size_t i;

1404 1405 1406
    if (!nhostdevs)
        return;

1407
    virObjectLock(mgr->activeUSBHostdevs);
1408 1409
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
1410
        virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb;
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
        virUSBDevicePtr usb, tmp;
        const char *usedby_drvname;
        const char *usedby_domname;

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

1422
        if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL))) {
1423
            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
1424
                     usbsrc->bus, usbsrc->device, dom_name);
1425 1426 1427 1428 1429 1430 1431 1432 1433
            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 */

1434
        tmp = virUSBDeviceListFind(mgr->activeUSBHostdevs, usb);
1435 1436 1437 1438 1439
        virUSBDeviceFree(usb);

        if (!tmp) {
            VIR_WARN("Unable to find device %03d.%03d "
                     "in list of active USB devices",
1440
                     usbsrc->bus, usbsrc->device);
1441 1442 1443 1444 1445
            continue;
        }

        virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname);
        if (STREQ_NULLABLE(drv_name, usedby_drvname) &&
1446
            STREQ_NULLABLE(dom_name, usedby_domname)) {
1447
            VIR_DEBUG("Removing %03d.%03d dom=%s from activeUSBHostdevs",
1448
                      usbsrc->bus, usbsrc->device, dom_name);
1449
            virUSBDeviceListDel(mgr->activeUSBHostdevs, tmp);
1450 1451
        }
    }
1452
    virObjectUnlock(mgr->activeUSBHostdevs);
1453
}
1454

1455
static void
1456
virHostdevReAttachSCSIHostDevices(virHostdevManagerPtr mgr,
1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
                                  virDomainHostdevDefPtr hostdev,
                                  virDomainHostdevSubsysSCSIPtr scsisrc,
                                  const char *drv_name,
                                  const char *dom_name)
{
    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
    virSCSIDevicePtr scsi;
    virSCSIDevicePtr tmp;

    if (!(scsi = virSCSIDeviceNew(NULL,
                                  scsihostsrc->adapter, scsihostsrc->bus,
                                  scsihostsrc->target, scsihostsrc->unit,
                                  hostdev->readonly, hostdev->shareable))) {
1470
        VIR_WARN("Unable to reattach SCSI device %s:%u:%u:%llu on domain %s",
1471 1472 1473 1474 1475 1476 1477 1478
                 scsihostsrc->adapter, scsihostsrc->bus, scsihostsrc->target,
                 scsihostsrc->unit, dom_name);
        return;
    }

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

1479
    if (!(tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs, scsi))) {
1480
        VIR_WARN("Unable to find device %s:%u:%u:%llu "
1481 1482 1483 1484 1485 1486 1487
                 "in list of active SCSI devices",
                 scsihostsrc->adapter, scsihostsrc->bus,
                 scsihostsrc->target, scsihostsrc->unit);
        virSCSIDeviceFree(scsi);
        return;
    }

1488
    VIR_DEBUG("Removing %s:%u:%u:%llu dom=%s from activeSCSIHostdevs",
1489 1490 1491
               scsihostsrc->adapter, scsihostsrc->bus, scsihostsrc->target,
               scsihostsrc->unit, dom_name);

1492
    virSCSIDeviceListDel(mgr->activeSCSIHostdevs, tmp,
1493 1494 1495 1496
                         drv_name, dom_name);
    virSCSIDeviceFree(scsi);
}

1497
void
1498
virHostdevReAttachSCSIDevices(virHostdevManagerPtr mgr,
1499 1500 1501 1502
                              const char *drv_name,
                              const char *dom_name,
                              virDomainHostdevDefPtr *hostdevs,
                              int nhostdevs)
1503 1504 1505
{
    size_t i;

1506 1507 1508
    if (!nhostdevs)
        return;

1509
    virObjectLock(mgr->activeSCSIHostdevs);
1510 1511
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
1512
        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
1513 1514 1515 1516 1517

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

1518 1519 1520
        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
            continue; /* Not supported for iSCSI */
        else
1521
            virHostdevReAttachSCSIHostDevices(mgr, hostdev, scsisrc,
1522
                                              drv_name, dom_name);
1523
    }
1524
    virObjectUnlock(mgr->activeSCSIHostdevs);
1525
}
1526 1527

int
1528
virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
1529 1530
                              virPCIDevicePtr pci)
{
1531
    struct virHostdevIsPCINodeDeviceUsedData data = { mgr, NULL, false };
1532 1533
    int ret = -1;

1534 1535
    virObjectLock(mgr->activePCIHostdevs);
    virObjectLock(mgr->inactivePCIHostdevs);
1536

1537
    if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
1538
        goto cleanup;
1539

1540 1541
    if (virPCIDeviceDetach(pci, mgr->activePCIHostdevs,
                           mgr->inactivePCIHostdevs) < 0)
1542
        goto cleanup;
1543 1544

    ret = 0;
1545 1546

 cleanup:
1547 1548
    virObjectUnlock(mgr->inactivePCIHostdevs);
    virObjectUnlock(mgr->activePCIHostdevs);
1549

1550 1551 1552 1553
    return ret;
}

int
1554
virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr mgr,
1555 1556
                                virPCIDevicePtr pci)
{
1557
    struct virHostdevIsPCINodeDeviceUsedData data = { mgr, NULL, false };
1558 1559
    int ret = -1;

1560 1561
    virObjectLock(mgr->activePCIHostdevs);
    virObjectLock(mgr->inactivePCIHostdevs);
1562

1563
    if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
1564
        goto cleanup;
1565

1566 1567 1568
    virPCIDeviceSetUnbindFromStub(pci, true);
    virPCIDeviceSetRemoveSlot(pci, true);
    virPCIDeviceSetReprobe(pci, true);
1569

1570 1571
    if (virPCIDeviceReattach(pci, mgr->activePCIHostdevs,
                             mgr->inactivePCIHostdevs) < 0)
1572
        goto cleanup;
1573 1574

    ret = 0;
1575 1576

 cleanup:
1577 1578
    virObjectUnlock(mgr->inactivePCIHostdevs);
    virObjectUnlock(mgr->activePCIHostdevs);
1579

1580 1581 1582 1583
    return ret;
}

int
1584
virHostdevPCINodeDeviceReset(virHostdevManagerPtr mgr,
1585 1586 1587 1588
                             virPCIDevicePtr pci)
{
    int ret = -1;

1589 1590 1591 1592
    virObjectLock(mgr->activePCIHostdevs);
    virObjectLock(mgr->inactivePCIHostdevs);
    if (virPCIDeviceReset(pci, mgr->activePCIHostdevs,
                          mgr->inactivePCIHostdevs) < 0)
1593 1594 1595
        goto out;

    ret = 0;
1596
 out:
1597 1598
    virObjectUnlock(mgr->inactivePCIHostdevs);
    virObjectUnlock(mgr->activePCIHostdevs);
1599 1600
    return ret;
}
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639

int
virHostdevPrepareDomainDevices(virHostdevManagerPtr mgr,
                               const char *driver,
                               virDomainDefPtr def,
                               unsigned int flags)
{
    if (!def->nhostdevs)
        return 0;

    if (mgr == NULL)
        return -1;

    if (flags & VIR_HOSTDEV_SP_PCI) {
        if (virHostdevPreparePCIDevices(mgr, driver,
                                        def->name, def->uuid,
                                        def->hostdevs,
                                        def->nhostdevs,
                                        flags) < 0)
            return -1;
    }

    if (flags & VIR_HOSTDEV_SP_USB) {
        if (virHostdevPrepareUSBDevices(mgr, driver, def->name,
                                         def->hostdevs, def->nhostdevs,
                                         flags) < 0)
            return -1;
    }

    if (flags & VIR_HOSTDEV_SP_SCSI) {
        if (virHostdevPrepareSCSIDevices(mgr, driver, def->name,
                                         def->hostdevs, def->nhostdevs) < 0)
        return -1;
    }

    return 0;
}

/* @oldStateDir
1640
 * For upgrade purpose: see virHostdevReAttachPCIHostdevs
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669
 */
void
virHostdevReAttachDomainDevices(virHostdevManagerPtr mgr,
                                const char *driver,
                                virDomainDefPtr def,
                                unsigned int flags,
                                const char *oldStateDir)
{
    if (!def->nhostdevs || !mgr)
        return;

    if (flags & VIR_HOSTDEV_SP_PCI) {
        virHostdevReAttachPCIDevices(mgr, driver, def->name,
                                     def->hostdevs, def->nhostdevs,
                                     oldStateDir);
    }

    if (flags & VIR_HOSTDEV_SP_USB) {
        virHostdevReAttachUSBDevices(mgr, driver, def->name,
                                     def->hostdevs, def->nhostdevs);
    }

    if (flags & VIR_HOSTDEV_SP_SCSI) {
        virHostdevReAttachSCSIDevices(mgr, driver, def->name,
                                      def->hostdevs, def->nhostdevs);
    }
}

int
1670
virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr,
1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703
                                    const char *driver,
                                    virDomainDefPtr def,
                                    unsigned int flags)
{
    if (!def->nhostdevs)
        return 0;

    if (flags & VIR_HOSTDEV_SP_PCI) {
        if (virHostdevUpdateActivePCIDevices(mgr,
                                             def->hostdevs,
                                             def->nhostdevs,
                                             driver, def->name) < 0)
            return -1;
    }

    if (flags & VIR_HOSTDEV_SP_USB) {
        if (virHostdevUpdateActiveUSBDevices(mgr,
                                             def->hostdevs,
                                             def->nhostdevs,
                                             driver, def->name) < 0)
            return -1;
    }

    if (flags & VIR_HOSTDEV_SP_SCSI) {
        if (virHostdevUpdateActiveSCSIDevices(mgr,
                                              def->hostdevs,
                                              def->nhostdevs,
                                              driver, def->name) < 0)
            return -1;
    }

    return 0;
}