qemu_hostdev.c 50.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
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

26 27 28 29 30
#include <dirent.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>

31
#include "qemu_hostdev.h"
32
#include "virlog.h"
33
#include "virerror.h"
34
#include "viralloc.h"
35
#include "virpci.h"
36
#include "virusb.h"
37
#include "virscsi.h"
38
#include "virnetdev.h"
39
#include "virfile.h"
40
#include "virhostdev.h"
41

42 43
#define VIR_FROM_THIS VIR_FROM_QEMU

44
static virPCIDeviceListPtr
45
virHostdevGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
46
{
47
    virPCIDeviceListPtr list;
48
    size_t i;
49

50
    if (!(list = virPCIDeviceListNew()))
51 52
        return NULL;

53
    for (i = 0; i < nhostdevs; i++) {
54
        virDomainHostdevDefPtr hostdev = hostdevs[i];
55
        virPCIDevicePtr dev;
56 57 58 59 60 61

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

62 63 64 65
        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);
66
        if (!dev) {
67
            virObjectUnref(list);
68 69 70
            return NULL;
        }

71 72
        if (virPCIDeviceListAdd(list, dev) < 0) {
            virPCIDeviceFree(dev);
73
            virObjectUnref(list);
74 75 76
            return NULL;
        }

77
        virPCIDeviceSetManaged(dev, hostdev->managed);
78
        if (hostdev->source.subsys.u.pci.backend
79
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
80 81 82 83
            if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) {
                virObjectUnref(list);
                return NULL;
            }
84
        } else {
85 86 87 88
            if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) {
                virObjectUnref(list);
                return NULL;
            }
89
        }
90 91 92 93 94
    }

    return list;
}

95

96
/*
97
 * virHostdevGetActivePciHostDeviceList - make a new list with a *copy* of
98 99 100 101 102
 *   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.
 *
103
 * Pre-condition: activePciHostdevs is locked
104
 */
105
static virPCIDeviceListPtr
106 107 108
virHostdevGetActivePciHostDeviceList(virHostdevManagerPtr mgr,
                                     virDomainHostdevDefPtr *hostdevs,
                                     int nhostdevs)
109
{
110
    virPCIDeviceListPtr list;
111
    size_t i;
112

113
    if (!(list = virPCIDeviceListNew()))
114 115
        return NULL;

116
    for (i = 0; i < nhostdevs; i++) {
117
        virDomainHostdevDefPtr hostdev = hostdevs[i];
118
        virDevicePCIAddressPtr addr;
119
        virPCIDevicePtr activeDev;
120 121 122 123 124 125

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

126
        addr = &hostdev->source.subsys.u.pci.addr;
127
        activeDev = virPCIDeviceListFindByIDs(mgr->activePciHostdevs,
128 129 130
                                              addr->domain, addr->bus,
                                              addr->slot, addr->function);
        if (activeDev && virPCIDeviceListAddCopy(list, activeDev) < 0) {
131
            virObjectUnref(list);
132 133 134 135 136 137
            return NULL;
        }
    }

    return list;
}
138

139 140 141 142

int
qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
                            virDomainDefPtr def)
143
{
144
    virDomainHostdevDefPtr hostdev = NULL;
145
    virPCIDevicePtr dev = NULL;
146
    size_t i;
147
    int ret = -1;
148
    virHostdevManagerPtr mgr = driver->hostdevMgr;
149 150 151 152

    if (!def->nhostdevs)
        return 0;

153 154
    virObjectLock(mgr->activePciHostdevs);
    virObjectLock(mgr->inactivePciHostdevs);
155

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

164 165 166 167
        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);
168 169

        if (!dev)
170
            goto cleanup;
171

172
        virPCIDeviceSetManaged(dev, hostdev->managed);
173
        if (hostdev->source.subsys.u.pci.backend
174
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
175 176
            if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0)
                goto cleanup;
177
        } else {
178 179 180
            if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0)
                goto cleanup;

181
        }
C
Chunyan Liu 已提交
182
        virPCIDeviceSetUsedBy(dev, QEMU_DRIVER_NAME, def->name);
183 184

        /* Setup the original states for the PCI device */
185 186 187
        virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub);
        virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot);
        virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe);
188

189
        if (virPCIDeviceListAdd(mgr->activePciHostdevs, dev) < 0)
190
            goto cleanup;
191
        dev = NULL;
192 193
    }

194
    ret = 0;
195
cleanup:
196
    virPCIDeviceFree(dev);
197 198
    virObjectUnlock(mgr->activePciHostdevs);
    virObjectUnlock(mgr->inactivePciHostdevs);
199
    return ret;
200 201 202
}

int
203
qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
204 205 206
                            virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
207
    size_t i;
208
    int ret = -1;
209
    virHostdevManagerPtr mgr = driver->hostdevMgr;
210 211 212 213

    if (!def->nhostdevs)
        return 0;

214
    virObjectLock(mgr->activeUsbHostdevs);
215
    for (i = 0; i < def->nhostdevs; i++) {
216
        virUSBDevicePtr usb = NULL;
217 218 219 220 221 222 223
        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;

224 225 226
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
227 228 229 230 231 232 233 234
        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;
        }

C
Chunyan Liu 已提交
235
        virUSBDeviceSetUsedBy(usb, QEMU_DRIVER_NAME, def->name);
236

237
        if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0) {
238
            virUSBDeviceFree(usb);
239
            goto cleanup;
240 241
        }
    }
242 243
    ret = 0;
cleanup:
244
    virObjectUnlock(mgr->activeUsbHostdevs);
245
    return ret;
246 247
}

248 249 250 251 252
int
qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
                             virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
253
    size_t i;
254
    int ret = -1;
255 256
    virSCSIDevicePtr scsi = NULL;
    virSCSIDevicePtr tmp = NULL;
257
    virHostdevManagerPtr mgr = driver->hostdevMgr;
258 259 260 261

    if (!def->nhostdevs)
        return 0;

262
    virObjectLock(mgr->activeScsiHostdevs);
263 264 265 266 267 268 269
    for (i = 0; i < def->nhostdevs; i++) {
        hostdev = def->hostdevs[i];

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

270 271
        if (!(scsi = virSCSIDeviceNew(NULL,
                                      hostdev->source.subsys.u.scsi.adapter,
272 273 274
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
275 276
                                      hostdev->readonly,
                                      hostdev->shareable)))
277 278
            goto cleanup;

279
        if ((tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi))) {
C
Chunyan Liu 已提交
280
            if (virSCSIDeviceSetUsedBy(tmp, QEMU_DRIVER_NAME, def->name) < 0) {
281 282 283
                virSCSIDeviceFree(scsi);
                goto cleanup;
            }
284
            virSCSIDeviceFree(scsi);
285
        } else {
C
Chunyan Liu 已提交
286
            if (virSCSIDeviceSetUsedBy(scsi, QEMU_DRIVER_NAME, def->name) < 0 ||
287
                virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0) {
288 289 290
                virSCSIDeviceFree(scsi);
                goto cleanup;
            }
291 292 293 294 295
        }
    }
    ret = 0;

cleanup:
296
    virObjectUnlock(mgr->activeScsiHostdevs);
297 298 299
    return ret;
}

300

301
static int
302 303
virHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev,
                       char **sysfs_path)
304
{
305
    virPCIDeviceAddress config_address;
306

307 308 309 310
    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;
311

312
    return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
313 314
}

315

316
static int
317
virHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
318 319 320 321
{
    char *sysfs_path = NULL;
    int ret = -1;

322
    if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
323 324
        return ret;

325
    ret = virPCIIsVirtualFunction(sysfs_path);
326 327 328 329 330 331

    VIR_FREE(sysfs_path);

    return ret;
}

332

333
static int
334 335
virHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
                    int *vf)
336 337 338 339
{
    int ret = -1;
    char *sysfs_path = NULL;

340
    if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
341 342
        return ret;

343 344 345
    if (virPCIIsVirtualFunction(sysfs_path) == 1) {
        if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev,
                                         vf) < 0)
346 347
            goto cleanup;
    } else {
348
        if (virPCIGetNetName(sysfs_path, linkdev) < 0)
349 350 351 352 353 354 355 356 357 358 359 360
            goto cleanup;
        *vf = -1;
    }

    ret = 0;

cleanup:
    VIR_FREE(sysfs_path);

    return ret;
}

361

362
static int
363 364 365 366 367
virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
                                   virNetDevVPortProfilePtr virtPort,
                                   const virMacAddr *macaddr,
                                   const unsigned char *uuid,
                                   bool associate)
368 369 370 371 372 373
{
    int ret = -1;

    if (!virtPort)
        return ret;

374
    switch (virtPort->virtPortType) {
375 376 377 378
    case VIR_NETDEV_VPORT_PROFILE_NONE:
    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
    case VIR_NETDEV_VPORT_PROFILE_8021QBG:
    case VIR_NETDEV_VPORT_PROFILE_LAST:
379 380 381 382 383
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("virtualport type %s is "
                         "currently not supported on interfaces of type "
                         "hostdev"),
                       virNetDevVPortTypeToString(virtPort->virtPortType));
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
        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;
}

401

402
static int
403 404 405
virHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
                           const unsigned char *uuid,
                           char *stateDir)
406 407
{
    char *linkdev = NULL;
408
    virNetDevVlanPtr vlan;
409 410 411 412
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
    int vlanid = -1;
413
    bool port_profile_associate = true;
414 415
    int isvf;

416
    isvf = virHostdevIsVirtualFunction(hostdev);
417
    if (isvf <= 0) {
418 419 420
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
421 422 423
        return ret;
    }

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

427
    vlan = virDomainNetGetActualVlan(hostdev->parent.data.net);
428 429
    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
430 431 432 433 434 435 436 437
    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;
        }
438
        ret = virHostdevNetConfigVirtPortProfile(linkdev, vf,
439
                            virtPort, &hostdev->parent.data.net->mac, uuid,
440
                            port_profile_associate);
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
    } 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 */
        }

461
        ret = virNetDevReplaceNetConfig(linkdev, vf,
462 463 464 465
                                        &hostdev->parent.data.net->mac,
                                        vlanid, stateDir);
    }
cleanup:
466 467 468 469
    VIR_FREE(linkdev);
    return ret;
}

470 471 472 473 474 475 476
/* @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
 * location (hostdev_mgr->stateDir) but certainly will not find it. In this
 * case, try to find in the old state dir.
 */
477
static int
478 479 480
virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
                           char *stateDir,
                           char *oldStateDir)
481 482 483 484 485
{
    char *linkdev = NULL;
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
486
    bool port_profile_associate = false;
487 488
    int isvf;

489 490 491 492 493 494 495 496 497
    /* This is only needed for PCI devices that have been defined
     * using <interface type='hostdev'>. For all others, it is a NOP.
     */
    if (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)
       return 0;

498
    isvf = virHostdevIsVirtualFunction(hostdev);
499
    if (isvf <= 0) {
500 501 502
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
503 504 505
        return ret;
    }

506
    if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
507 508 509 510
        return ret;

    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
511
    if (virtPort) {
512 513 514 515
        ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
                                                 &hostdev->parent.data.net->mac,
                                                 NULL,
                                                 port_profile_associate);
516
    } else {
517
        ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);
518 519 520
        if (ret < 0 && oldStateDir != NULL)
            ret = virNetDevRestoreNetConfig(linkdev, vf, oldStateDir);
    }
521 522 523 524 525 526

    VIR_FREE(linkdev);

    return ret;
}

527

528
bool
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
qemuHostdevHostSupportsPassthroughVFIO(void)
{
    DIR *iommuDir = NULL;
    struct dirent *iommuGroup = NULL;
    bool ret = false;

    /* condition 1 - /sys/kernel/iommu_groups/ contains entries */
    if (!(iommuDir = opendir("/sys/kernel/iommu_groups/")))
        goto cleanup;

    while ((iommuGroup = readdir(iommuDir))) {
        /* skip ./ ../ */
        if (STRPREFIX(iommuGroup->d_name, "."))
            continue;

        /* assume we found a group */
        break;
    }

    if (!iommuGroup)
        goto cleanup;
    /* okay, iommu is on and recognizes groups */

    /* condition 2 - /dev/vfio/vfio exists */
    if (!virFileExists("/dev/vfio/vfio"))
        goto cleanup;

    ret = true;

cleanup:
    if (iommuDir)
        closedir(iommuDir);

    return ret;
}


#if HAVE_LINUX_KVM_H
# include <linux/kvm.h>
568
bool
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
qemuHostdevHostSupportsPassthroughLegacy(void)
{
    int kvmfd = -1;
    bool ret = false;

    if ((kvmfd = open("/dev/kvm", O_RDONLY)) < 0)
        goto cleanup;

# ifdef KVM_CAP_IOMMU
    if ((ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_IOMMU)) <= 0)
        goto cleanup;

    ret = true;
# endif

cleanup:
    VIR_FORCE_CLOSE(kvmfd);

    return ret;
}
#else
590
bool
591 592 593 594 595 596 597 598 599
qemuHostdevHostSupportsPassthroughLegacy(void)
{
    return false;
}
#endif


static bool
qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
600 601
                                  size_t nhostdevs,
                                  virQEMUCapsPtr qemuCaps)
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
{
    bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
    bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
    size_t i;

    /* assign defaults for hostdev passthrough */
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
        int *backend = &hostdev->source.subsys.u.pci.backend;

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

        switch ((virDomainHostdevSubsysPciBackendType) *backend) {
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
            if (supportsPassthroughVFIO &&
                virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
                *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
            } else if (supportsPassthroughKVM &&
                       (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE) ||
                        virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
                *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
            } else {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("host doesn't support passthrough of "
                                 "host PCI devices"));
                return false;
            }

            break;

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
            if (!supportsPassthroughVFIO) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("host doesn't support VFIO PCI passthrough"));
                return false;
            }
            break;

        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
            if (!supportsPassthroughKVM) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("host doesn't support legacy PCI passthrough"));
                return false;
            }

            break;

        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
            break;
        }
    }

    return true;
}

660 661
static int
virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
662
                            const char *drv_name,
663 664 665 666 667
                            const char *name,
                            const unsigned char *uuid,
                            virDomainHostdevDefPtr *hostdevs,
                            int nhostdevs,
                            unsigned int flags)
668
{
669
    virPCIDeviceListPtr pcidevs = NULL;
670
    int last_processed_hostdev_vf = -1;
671
    size_t i;
672
    int ret = -1;
673

674 675
    virObjectLock(hostdev_mgr->activePciHostdevs);
    virObjectLock(hostdev_mgr->inactivePciHostdevs);
676

677
    if (!(pcidevs = virHostdevGetPciHostDeviceList(hostdevs, nhostdevs)))
678
        goto cleanup;
679

680
    /* We have to use 9 loops here. *All* devices must
681 682 683 684 685 686
     * 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.
     */

687
    /* Loop 1: validate that non-managed device isn't in use, eg
688 689 690 691
     * by checking that device is either un-bound, or bound
     * to pci-stub.ko
     */

692 693 694
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr other;
695
        bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
696

697
        if (!virPCIDeviceIsAssignable(dev, strict_acs_check)) {
698 699
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is not assignable"),
700
                           virPCIDeviceGetName(dev));
701 702 703
            goto cleanup;
        }
        /* The device is in use by other active domain if
704
         * the dev is in list activePciHostdevs.
705
         */
706
        if ((other = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev))) {
C
Chunyan Liu 已提交
707 708
            const char *other_drvname;
            const char *other_domname;
709

C
Chunyan Liu 已提交
710 711
            virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname);
            if (other_drvname && other_domname)
712
                virReportError(VIR_ERR_OPERATION_INVALID,
C
Chunyan Liu 已提交
713 714 715 716
                               _("PCI device %s is in use by "
                                 "driver %s, domain %s"),
                               virPCIDeviceGetName(dev),
                               other_drvname, other_domname);
717
            else
718 719
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("PCI device %s is already in use"),
720
                               virPCIDeviceGetName(dev));
721 722 723 724
            goto cleanup;
        }
    }

725
    /* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */
726 727 728
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceGetManaged(dev) &&
729
            virPCIDeviceDetach(dev, hostdev_mgr->activePciHostdevs, NULL) < 0)
730
            goto reattachdevs;
731 732
    }

733 734
    /* Loop 3: Now that all the PCI hostdevs have been detached, we
     * can safely reset them */
735 736
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
737

738 739
        if (virPCIDeviceReset(dev, hostdev_mgr->activePciHostdevs,
                              hostdev_mgr->inactivePciHostdevs) < 0)
740
            goto reattachdevs;
741 742
    }

743 744 745 746 747 748 749 750 751 752
    /* 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) {
753 754
             if (virHostdevNetConfigReplace(hostdev, uuid,
                                            hostdev_mgr->stateDir) < 0) {
755 756 757 758 759 760 761
                 goto resetvfnetconfig;
             }
         }
         last_processed_hostdev_vf = i;
    }

    /* Loop 5: Now mark all the devices as active */
762 763
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
764
        if (virPCIDeviceListAdd(hostdev_mgr->activePciHostdevs, dev) < 0)
765
            goto inactivedevs;
766 767
    }

768
    /* Loop 6: Now remove the devices from inactive list. */
769 770
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
         virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
771
         virPCIDeviceListDel(hostdev_mgr->inactivePciHostdevs, dev);
772 773
    }

774
    /* Loop 7: Now set the used_by_domain of the device in
775
     * activePciHostdevs as domain name.
776
     */
777 778
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev, activeDev;
779

780
        dev = virPCIDeviceListGet(pcidevs, i);
781
        activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev);
782

783
        if (activeDev)
784
            virPCIDeviceSetUsedBy(activeDev, drv_name, name);
785 786
    }

787
    /* Loop 8: Now set the original states for hostdev def */
788
    for (i = 0; i < nhostdevs; i++) {
789 790
        virPCIDevicePtr dev;
        virPCIDevicePtr pcidev;
791 792 793 794 795 796 797
        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;

798 799 800 801
        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);
802 803 804 805 806

        /* original states "unbind_from_stub", "remove_slot",
         * "reprobe" were already set by pciDettachDevice in
         * loop 2.
         */
807
        if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) {
808
            hostdev->origstates.states.pci.unbind_from_stub =
809
                virPCIDeviceGetUnbindFromStub(pcidev);
810
            hostdev->origstates.states.pci.remove_slot =
811
                virPCIDeviceGetRemoveSlot(pcidev);
812
            hostdev->origstates.states.pci.reprobe =
813
                virPCIDeviceGetReprobe(pcidev);
814 815
        }

816
        virPCIDeviceFree(dev);
817 818
    }

819
    /* Loop 9: Now steal all the devices from pcidevs */
820 821
    while (virPCIDeviceListCount(pcidevs) > 0)
        virPCIDeviceListStealIndex(pcidevs, 0);
822

823
    ret = 0;
824 825 826
    goto cleanup;

inactivedevs:
827
    /* Only steal all the devices from activePciHostdevs. We will
828
     * free them in virObjectUnref().
829
     */
830 831
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
832
        virPCIDeviceListSteal(hostdev_mgr->activePciHostdevs, dev);
833
    }
834

835
resetvfnetconfig:
836 837
    for (i = 0;
         last_processed_hostdev_vf != -1 && i < last_processed_hostdev_vf; i++)
838
        virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, NULL);
839

840
reattachdevs:
841 842
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
843 844 845 846

        /* NB: This doesn't actually re-bind to original driver, just
         * unbinds from the stub driver
         */
847
        ignore_value(virPCIDeviceReattach(dev, hostdev_mgr->activePciHostdevs,
848
                                          NULL));
849 850
    }

851
cleanup:
852 853
    virObjectUnlock(hostdev_mgr->activePciHostdevs);
    virObjectUnlock(hostdev_mgr->inactivePciHostdevs);
854
    virObjectUnref(pcidevs);
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
    return ret;
}

int
qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
                             const char *name,
                             const unsigned char *uuid,
                             virDomainHostdevDefPtr *hostdevs,
                             int nhostdevs,
                             virQEMUCapsPtr qemuCaps,
                             unsigned int flags)
{
    int ret = -1;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps))
        goto out;

873 874
    ret = virHostdevPreparePCIDevices(hostdev_mgr, QEMU_DRIVER_NAME,
                                      name, uuid, hostdevs,
875
                                      nhostdevs, flags);
876
out:
877 878 879
    return ret;
}

880

881
static int
882
qemuPrepareHostdevUSBDevices(virHostdevManagerPtr mgr,
883
                             const char *name,
884
                             virUSBDeviceListPtr list)
885
{
886
    size_t i, j;
887
    unsigned int count;
888
    virUSBDevicePtr tmp;
889

890
    virObjectLock(mgr->activeUsbHostdevs);
891
    count = virUSBDeviceListCount(list);
892 893

    for (i = 0; i < count; i++) {
894
        virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
895
        if ((tmp = virUSBDeviceListFind(mgr->activeUsbHostdevs, usb))) {
C
Chunyan Liu 已提交
896 897
            const char *other_drvname;
            const char *other_domname;
898

C
Chunyan Liu 已提交
899 900
            virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
            if (other_drvname && other_domname)
901
                virReportError(VIR_ERR_OPERATION_INVALID,
C
Chunyan Liu 已提交
902 903 904 905
                               _("USB device %s is in use by "
                                 "driver %s, domain %s"),
                               virUSBDeviceGetName(tmp),
                               other_drvname, other_domname);
906
            else
907 908
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is already in use"),
909
                               virUSBDeviceGetName(tmp));
910
            goto error;
911 912
        }

C
Chunyan Liu 已提交
913
        virUSBDeviceSetUsedBy(usb, QEMU_DRIVER_NAME, name);
914
        VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
915
                  virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
916 917
        /*
         * The caller is responsible to steal these usb devices
918
         * from the virUSBDeviceList that passed in on success,
919 920
         * perform rollback on failure.
         */
921
        if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0)
922
            goto error;
923
    }
924

925
    virObjectUnlock(mgr->activeUsbHostdevs);
926
    return 0;
927 928 929

error:
    for (j = 0; j < i; j++) {
930
        tmp = virUSBDeviceListGet(list, i);
931
        virUSBDeviceListSteal(mgr->activeUsbHostdevs, tmp);
932
    }
933
    virObjectUnlock(mgr->activeUsbHostdevs);
934
    return -1;
935 936
}

937

938
static int
939 940
qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
                         bool mandatory,
941
                         virUSBDevicePtr *usb)
942 943 944 945 946
{
    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;
947
    bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
948
    int rc;
949

950
    *usb = NULL;
951

952
    if (vendor && bus) {
953 954 955 956
        rc = virUSBDeviceFind(vendor, product, bus, device,
                              NULL,
                              autoAddress ? false : mandatory,
                              usb);
957
        if (rc < 0) {
958
            return -1;
959 960 961 962 963 964 965 966 967 968 969 970 971 972
        } 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) {
973
        virUSBDeviceListPtr devs;
974

975
        rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
976 977 978 979
        if (rc < 0)
            return -1;

        if (rc == 1) {
980 981
            *usb = virUSBDeviceListGet(devs, 0);
            virUSBDeviceListSteal(devs, *usb);
982
        }
983
        virObjectUnref(devs);
984

985 986 987
        if (rc == 0) {
            goto out;
        } else if (rc > 1) {
988 989 990 991 992 993 994 995 996 997 998
            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);
            }
999 1000
            return -1;
        }
1001

1002 1003
        hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
        hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
        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);
        }
1014
    } else if (!vendor && bus) {
1015
        if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
1016
            return -1;
1017 1018
    }

1019 1020
out:
    if (!*usb)
1021
        hostdev->missing = true;
1022
    return 0;
1023 1024
}

1025

1026
int
1027
qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
1028 1029 1030
                          const char *name,
                          virDomainHostdevDefPtr *hostdevs,
                          int nhostdevs,
1031
                          unsigned int flags)
1032
{
1033 1034
    size_t i;
    int ret = -1;
1035 1036
    virUSBDeviceListPtr list;
    virUSBDevicePtr tmp;
1037
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
1038
    bool coldBoot = !!(flags & VIR_HOSTDEV_COLD_BOOT);
1039 1040 1041 1042

    /* 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
1043
     * loop. See virHostdevPreparePCIDevices()
1044
     */
1045
    if (!(list = virUSBDeviceListNew()))
1046 1047
        goto cleanup;

1048
    /* Loop 1: build temporary list
1049
     */
1050
    for (i = 0; i < nhostdevs; i++) {
1051
        virDomainHostdevDefPtr hostdev = hostdevs[i];
1052
        bool required = true;
1053
        virUSBDevicePtr usb;
1054 1055 1056 1057 1058 1059

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

1060 1061 1062 1063 1064 1065
        if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
            (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
             !coldBoot))
            required = false;

        if (qemuFindHostdevUSBDevice(hostdev, required, &usb) < 0)
1066
            goto cleanup;
1067

1068 1069
        if (usb && virUSBDeviceListAdd(list, usb) < 0) {
            virUSBDeviceFree(usb);
1070
            goto cleanup;
1071 1072 1073
        }
    }

1074
    /* Mark devices in temporary list as used by @name
1075 1076 1077
     * and add them do driver list. However, if something goes
     * wrong, perform rollback.
     */
1078
    if (qemuPrepareHostdevUSBDevices(hostdev_mgr, name, list) < 0)
1079
        goto cleanup;
1080

1081
    /* Loop 2: Temporary list was successfully merged with
1082 1083 1084
     * driver list, so steal all items to avoid freeing them
     * in cleanup label.
     */
1085 1086 1087
    while (virUSBDeviceListCount(list) > 0) {
        tmp = virUSBDeviceListGet(list, 0);
        virUSBDeviceListSteal(list, tmp);
1088 1089 1090 1091 1092
    }

    ret = 0;

cleanup:
1093
    virObjectUnref(list);
1094
    return ret;
1095 1096
}

1097

1098 1099 1100 1101 1102 1103
int
qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
                              const char *name,
                              virDomainHostdevDefPtr *hostdevs,
                              int nhostdevs)
{
1104 1105
    size_t i, j;
    int count;
1106 1107
    virSCSIDeviceListPtr list;
    virSCSIDevicePtr tmp;
1108
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
1109

1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
    /* 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;
1121 1122 1123

        if (qemuSetUnprivSGIO(&dev) < 0)
            return -1;
1124 1125
    }

1126 1127 1128
    /* 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
1129
     * loop. See virHostdevPreparePCIDevices()
1130 1131 1132 1133
     */
    if (!(list = virSCSIDeviceListNew()))
        goto cleanup;

1134
    /* Loop 2: build temporary list */
1135
    for (i = 0; i < nhostdevs; i++) {
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
        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;
        }

1149 1150
        if (!(scsi = virSCSIDeviceNew(NULL,
                                      hostdev->source.subsys.u.scsi.adapter,
1151 1152 1153
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
1154 1155
                                      hostdev->readonly,
                                      hostdev->shareable)))
1156 1157 1158 1159 1160 1161 1162 1163
            goto cleanup;

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

1164
    /* Loop 3: Mark devices in temporary list as used by @name
1165 1166 1167
     * and add them to driver list. However, if something goes
     * wrong, perform rollback.
     */
1168
    virObjectLock(hostdev_mgr->activeScsiHostdevs);
1169 1170 1171 1172
    count = virSCSIDeviceListCount(list);

    for (i = 0; i < count; i++) {
        virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
1173 1174
        if ((tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs,
                                         scsi))) {
1175 1176
            bool scsi_shareable = virSCSIDeviceGetShareable(scsi);
            bool tmp_shareable = virSCSIDeviceGetShareable(tmp);
1177

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

C
Chunyan Liu 已提交
1187
            if (virSCSIDeviceSetUsedBy(tmp, QEMU_DRIVER_NAME, name) < 0)
1188 1189
                goto error;
        } else {
C
Chunyan Liu 已提交
1190
            if (virSCSIDeviceSetUsedBy(scsi, QEMU_DRIVER_NAME, name) < 0)
1191
                goto error;
1192

1193 1194
            VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi));

1195
            if (virSCSIDeviceListAdd(hostdev_mgr->activeScsiHostdevs, scsi) < 0)
1196 1197
                goto error;
        }
1198 1199
    }

1200
    virObjectUnlock(hostdev_mgr->activeScsiHostdevs);
1201

1202
    /* Loop 4: Temporary list was successfully merged with
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
     * 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);
1217
        virSCSIDeviceListSteal(hostdev_mgr->activeScsiHostdevs, tmp);
1218
    }
1219
    virObjectUnlock(hostdev_mgr->activeScsiHostdevs);
1220 1221 1222 1223 1224
cleanup:
    virObjectUnref(list);
    return -1;
}

1225 1226 1227 1228

int
qemuPrepareHostDevices(virQEMUDriverPtr driver,
                       virDomainDefPtr def,
1229
                       virQEMUCapsPtr qemuCaps,
1230
                       unsigned int flags)
1231 1232 1233 1234
{
    if (!def->nhostdevs)
        return 0;

1235
    if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
1236
                                     def->hostdevs, def->nhostdevs,
1237
                                     qemuCaps, flags) < 0)
1238 1239
        return -1;

1240
    if (qemuPrepareHostUSBDevices(driver, def->name,
1241
                                  def->hostdevs, def->nhostdevs, flags) < 0)
1242 1243
        return -1;

1244 1245 1246 1247
    if (qemuPrepareHostdevSCSIDevices(driver, def->name,
                                      def->hostdevs, def->nhostdevs) < 0)
        return -1;

1248 1249 1250 1251
    return 0;
}


1252
/*
1253
 * Pre-condition: inactivePciHostdevs & activePciHostdevs
1254 1255
 * are locked
 */
1256
static void
1257
qemuReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr)
1258
{
1259 1260 1261
    /* If the device is not managed and was attached to guest
     * successfully, it must have been inactive.
     */
1262
    if (!virPCIDeviceGetManaged(dev)) {
1263
        if (virPCIDeviceListAdd(mgr->inactivePciHostdevs, dev) < 0)
1264
            virPCIDeviceFree(dev);
1265
        return;
1266
    }
1267

1268 1269 1270 1271 1272 1273 1274 1275
    /* Wait for device cleanup if it is qemu/kvm */
    if (STREQ(virPCIDeviceGetStubDriver(dev), "pci-stub")) {
        int retries = 100;
        while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
               && retries) {
            usleep(100*1000);
            retries--;
        }
1276 1277
    }

1278 1279
    if (virPCIDeviceReattach(dev, mgr->activePciHostdevs,
                             mgr->inactivePciHostdevs) < 0) {
1280 1281 1282 1283
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to re-attach PCI device: %s"),
                  err ? err->message : _("unknown error"));
        virResetError(err);
1284
    }
1285
    virPCIDeviceFree(dev);
1286 1287
}

1288 1289 1290 1291 1292
/* @oldStateDir:
 * For upgrade purpose: see virHostdevNetConfigRestore
 */
static void
virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
1293
                             const char *drv_name,
1294 1295 1296 1297
                             const char *name,
                             virDomainHostdevDefPtr *hostdevs,
                             int nhostdevs,
                             char *oldStateDir)
1298
{
1299
    virPCIDeviceListPtr pcidevs;
1300
    size_t i;
1301

1302 1303
    virObjectLock(hostdev_mgr->activePciHostdevs);
    virObjectLock(hostdev_mgr->inactivePciHostdevs);
1304

1305 1306 1307
    if (!(pcidevs = virHostdevGetActivePciHostDeviceList(hostdev_mgr,
                                                         hostdevs,
                                                         nhostdevs))) {
1308
        virErrorPtr err = virGetLastError();
1309
        VIR_ERROR(_("Failed to allocate PCI device list: %s"),
1310 1311
                  err ? err->message : _("unknown error"));
        virResetError(err);
1312
        goto cleanup;
1313 1314
    }

1315 1316 1317 1318
    /* 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
     */
1319 1320 1321
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr activeDev = NULL;
1322

1323 1324 1325
        /* 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.
1326
         */
1327
        activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev);
C
Chunyan Liu 已提交
1328 1329 1330 1331
        if (activeDev) {
            const char *usedby_drvname;
            const char *usedby_domname;
            virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname);
1332
            if (STRNEQ_NULLABLE(drv_name, usedby_drvname) ||
C
Chunyan Liu 已提交
1333 1334 1335 1336
                STRNEQ_NULLABLE(name, usedby_domname)) {
                    virPCIDeviceListDel(pcidevs, dev);
                    continue;
                }
1337
        }
1338

1339
        virPCIDeviceListDel(hostdev_mgr->activePciHostdevs, dev);
1340 1341
    }

1342 1343 1344 1345
    /* At this point, any device that had been used by the guest is in
     * pcidevs, but has been removed from activePciHostdevs.
     */

1346 1347 1348 1349
    /*
     * For SRIOV net host devices, unset mac and port profile before
     * reset and reattach device
     */
1350
    for (i = 0; i < nhostdevs; i++)
1351 1352
        virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir,
                                   oldStateDir);
1353

1354 1355
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
1356

1357 1358
        if (virPCIDeviceReset(dev, hostdev_mgr->activePciHostdevs,
                              hostdev_mgr->inactivePciHostdevs) < 0) {
1359 1360 1361 1362 1363 1364 1365
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to reset PCI device: %s"),
                      err ? err->message : _("unknown error"));
            virResetError(err);
        }
    }

1366 1367
    while (virPCIDeviceListCount(pcidevs) > 0) {
        virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
1368
        qemuReattachPciDevice(dev, hostdev_mgr);
1369 1370
    }

1371
    virObjectUnref(pcidevs);
1372
cleanup:
1373 1374
    virObjectUnlock(hostdev_mgr->activePciHostdevs);
    virObjectUnlock(hostdev_mgr->inactivePciHostdevs);
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
}

void
qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    char *oldStateDir = cfg->stateDir;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

1387
    virHostdevReAttachPCIDevices(hostdev_mgr, QEMU_DRIVER_NAME, name,
1388 1389
                                 hostdevs, nhostdevs, oldStateDir);

1390
    virObjectUnref(cfg);
1391 1392
}

1393

1394
void
1395
qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
1396 1397 1398 1399
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
1400
    size_t i;
1401
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
1402

1403
    virObjectLock(hostdev_mgr->activeUsbHostdevs);
1404 1405
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
1406
        virUSBDevicePtr usb, tmp;
C
Chunyan Liu 已提交
1407 1408
        const char *usedby_drvname;
        const char *usedby_domname;
1409 1410 1411 1412 1413

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

1417 1418 1419
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434

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

1435
        tmp = virUSBDeviceListFind(hostdev_mgr->activeUsbHostdevs, usb);
1436
        virUSBDeviceFree(usb);
1437 1438 1439 1440 1441 1442 1443 1444 1445

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

C
Chunyan Liu 已提交
1446 1447 1448
        virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname);
        if (STREQ_NULLABLE(QEMU_DRIVER_NAME, usedby_drvname) &&
            STREQ_NULLABLE(name, usedby_domname)) {
1449 1450 1451 1452 1453
            VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
                      hostdev->source.subsys.u.usb.bus,
                      hostdev->source.subsys.u.usb.device,
                      name);

1454
            virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, tmp);
1455 1456
        }
    }
1457
    virObjectUnlock(hostdev_mgr->activeUsbHostdevs);
1458
}
1459

1460

1461 1462 1463 1464 1465 1466
void
qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
                                  const char *name,
                                  virDomainHostdevDefPtr *hostdevs,
                                  int nhostdevs)
{
1467
    size_t i;
1468
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
1469

1470
    virObjectLock(hostdev_mgr->activeScsiHostdevs);
1471 1472
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
1473 1474
        virSCSIDevicePtr scsi;
        virSCSIDevicePtr tmp;
1475 1476 1477 1478 1479 1480
        virDomainDeviceDef dev;

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

        ignore_value(qemuRemoveSharedDevice(driver, &dev, name));
1481 1482 1483 1484 1485

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

1486 1487
        if (!(scsi = virSCSIDeviceNew(NULL,
                                      hostdev->source.subsys.u.scsi.adapter,
1488 1489 1490
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
1491 1492
                                      hostdev->readonly,
                                      hostdev->shareable))) {
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
            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. */

1505
        if (!(tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, scsi))) {
1506 1507 1508 1509 1510 1511
            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);
1512
            virSCSIDeviceFree(scsi);
1513 1514 1515
            continue;
        }

1516 1517 1518 1519 1520 1521
        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);
1522

1523
        virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, QEMU_DRIVER_NAME, name);
1524
        virSCSIDeviceFree(scsi);
1525
    }
1526
    virObjectUnlock(hostdev_mgr->activeScsiHostdevs);
1527 1528
}

1529 1530 1531
void
qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
                              virDomainDefPtr def)
1532 1533 1534 1535
{
    if (!def->nhostdevs)
        return;

1536 1537
    qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
1538 1539 1540

    qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
1541 1542 1543

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