qemu_hostdev.c 33.5 KB
Newer Older
1 2 3
/*
 * qemu_hostdev.c: QEMU hostdev management
 *
4
 * Copyright (C) 2006-2007, 2009-2012 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

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

34 35
#define VIR_FROM_THIS VIR_FROM_QEMU

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

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

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

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

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

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

69
        virPCIDeviceSetManaged(dev, hostdev->managed);
70 71 72 73 74
    }

    return list;
}

75 76 77
/*
 * Pre-condition: driver->activePciHostdevs is locked
 */
78
static virPCIDeviceListPtr
79
qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver,
80 81 82
                               virDomainHostdevDefPtr *hostdevs,
                               int nhostdevs)
{
83
    virPCIDeviceListPtr list;
84 85
    int i;

86
    if (!(list = virPCIDeviceListNew()))
87 88 89 90
        return NULL;

    for (i = 0 ; i < nhostdevs ; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
91 92
        virPCIDevicePtr dev;
        virPCIDevicePtr activeDev;
93 94 95 96 97 98

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

99 100 101 102
        dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.domain,
                              hostdev->source.subsys.u.pci.bus,
                              hostdev->source.subsys.u.pci.slot,
                              hostdev->source.subsys.u.pci.function);
103
        if (!dev) {
104
            virObjectUnref(list);
105 106 107
            return NULL;
        }

108 109 110
        if ((activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev))) {
            if (virPCIDeviceListAdd(list, activeDev) < 0) {
                virPCIDeviceFree(dev);
111
                virObjectUnref(list);
112 113 114 115
                return NULL;
            }
        }

116
        virPCIDeviceFree(dev);
117 118 119 120
    }

    return list;
}
121

122
int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
123 124
                                virDomainDefPtr def)
{
125 126
    virDomainHostdevDefPtr hostdev = NULL;
    int i;
127
    int ret = -1;
128 129 130 131

    if (!def->nhostdevs)
        return 0;

132 133 134
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

135
    for (i = 0; i < def->nhostdevs; i++) {
136
        virPCIDevicePtr dev = NULL;
137 138 139 140 141 142 143
        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;

144 145 146 147
        dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.domain,
                              hostdev->source.subsys.u.pci.bus,
                              hostdev->source.subsys.u.pci.slot,
                              hostdev->source.subsys.u.pci.function);
148 149

        if (!dev)
150
            goto cleanup;
151

152 153
        virPCIDeviceSetManaged(dev, hostdev->managed);
        virPCIDeviceSetUsedBy(dev, def->name);
154 155

        /* Setup the original states for the PCI device */
156 157 158
        virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub);
        virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot);
        virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe);
159

160 161
        if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
            virPCIDeviceFree(dev);
162
            goto cleanup;
163 164 165
        }
    }

166 167 168 169
cleanup:
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
    return ret;
170 171 172
}

int
173
qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
174 175 176 177
                            virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
    int i;
178
    int ret = -1;
179 180 181 182

    if (!def->nhostdevs)
        return 0;

183
    virObjectLock(driver->activeUsbHostdevs);
184
    for (i = 0; i < def->nhostdevs; i++) {
185
        virUSBDevicePtr usb = NULL;
186 187 188 189 190 191 192
        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;

193 194 195
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
196 197 198 199 200 201 202 203
        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;
        }

204
        virUSBDeviceSetUsedBy(usb, def->name);
205

206 207
        if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
            virUSBDeviceFree(usb);
208
            goto cleanup;
209 210
        }
    }
211 212 213 214
    ret = 0;
cleanup:
    virObjectUnlock(driver->activeUsbHostdevs);
    return ret;
215 216
}

217 218 219
static int
qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, char **sysfs_path)
{
220
    virPCIDeviceAddress config_address;
221 222 223 224 225 226

    config_address.domain = hostdev->source.subsys.u.pci.domain;
    config_address.bus = hostdev->source.subsys.u.pci.bus;
    config_address.slot = hostdev->source.subsys.u.pci.slot;
    config_address.function = hostdev->source.subsys.u.pci.function;

227
    return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
228 229 230 231 232 233 234 235 236 237 238
}

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

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

239
    ret = virPCIIsVirtualFunction(sysfs_path);
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

    VIR_FREE(sysfs_path);

    return ret;
}

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

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

256 257 258
    if (virPCIIsVirtualFunction(sysfs_path) == 1) {
        if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev,
                                         vf) < 0)
259 260
            goto cleanup;
    } else {
261
        if (virPCIGetNetName(sysfs_path, linkdev) < 0)
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
            goto cleanup;
        *vf = -1;
    }

    ret = 0;

cleanup:
    VIR_FREE(sysfs_path);

    return ret;
}

static int
qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
                                          virNetDevVPortProfilePtr virtPort,
277
                                          const virMacAddrPtr macaddr,
278 279 280 281 282 283 284 285
                                          const unsigned char *uuid,
                                          int associate)
{
    int ret = -1;

    if (!virtPort)
        return ret;

286
    switch (virtPort->virtPortType) {
287 288 289 290
    case VIR_NETDEV_VPORT_PROFILE_NONE:
    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
    case VIR_NETDEV_VPORT_PROFILE_8021QBG:
    case VIR_NETDEV_VPORT_PROFILE_LAST:
291 292 293 294 295
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("virtualport type %s is "
                         "currently not supported on interfaces of type "
                         "hostdev"),
                       virNetDevVPortTypeToString(virtPort->virtPortType));
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
        break;

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

    return ret;
}

int
qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
                                  const unsigned char *uuid,
                                  char *stateDir)
{
    char *linkdev = NULL;
319
    virNetDevVlanPtr vlan;
320 321 322 323 324 325 326 327 328
    virNetDevVPortProfilePtr virtPort;
    int ret = -1;
    int vf = -1;
    int vlanid = -1;
    int port_profile_associate = 1;
    int isvf;

    isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
    if (isvf <= 0) {
329 330 331
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Interface type hostdev is currently supported on"
                         " SR-IOV Virtual Functions only"));
332 333 334 335 336 337
        return ret;
    }

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

338
    vlan = virDomainNetGetActualVlan(hostdev->parent.data.net);
339 340
    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
341 342 343 344 345 346 347 348
    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;
        }
349
        ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf,
350
                            virtPort, &hostdev->parent.data.net->mac, uuid,
351
                            port_profile_associate);
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
    } 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 */
        }

372
        ret = virNetDevReplaceNetConfig(linkdev, vf,
373 374 375 376
                                        &hostdev->parent.data.net->mac,
                                        vlanid, stateDir);
    }
cleanup:
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
    VIR_FREE(linkdev);
    return ret;
}

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

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

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

    virtPort = virDomainNetGetActualVirtPortProfile(
                                 hostdev->parent.data.net);
    if (virtPort)
        ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
407
                                          &hostdev->parent.data.net->mac, NULL,
408 409 410 411 412 413 414 415 416
                                          port_profile_associate);
    else
        ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);

    VIR_FREE(linkdev);

    return ret;
}

417
int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
418
                                 const char *name,
419
                                 const unsigned char *uuid,
420 421 422
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
423
    virPCIDeviceListPtr pcidevs;
424
    int last_processed_hostdev_vf = -1;
425 426
    int i;
    int ret = -1;
427
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
428

429 430 431
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

432
    if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
433
        goto cleanup;
434

435
    /* We have to use 9 loops here. *All* devices must
436 437 438 439 440 441
     * 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.
     */

442
    /* Loop 1: validate that non-managed device isn't in use, eg
443 444 445 446
     * by checking that device is either un-bound, or bound
     * to pci-stub.ko
     */

447 448 449
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr other;
450

451
        if (!virPCIDeviceIsAssignable(dev, !cfg->relaxedACS)) {
452 453
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is not assignable"),
454
                           virPCIDeviceGetName(dev));
455 456 457 458 459
            goto cleanup;
        }
        /* The device is in use by other active domain if
         * the dev is in list driver->activePciHostdevs.
         */
460 461
        if ((other = virPCIDeviceListFind(driver->activePciHostdevs, dev))) {
            const char *other_name = virPCIDeviceGetUsedBy(other);
462 463

            if (other_name)
464 465
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("PCI device %s is in use by domain %s"),
466
                               virPCIDeviceGetName(dev), other_name);
467
            else
468 469
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("PCI device %s is already in use"),
470
                               virPCIDeviceGetName(dev));
471 472 473 474 475
            goto cleanup;
        }
    }

    /* Loop 2: detach managed devices */
476 477 478 479
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceGetManaged(dev) &&
            virPCIDeviceDetach(dev, driver->activePciHostdevs, NULL, "pci-stub") < 0)
480
            goto reattachdevs;
481 482
    }

483 484
    /* Loop 3: Now that all the PCI hostdevs have been detached, we
     * can safely reset them */
485 486 487 488
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceReset(dev, driver->activePciHostdevs,
                              driver->inactivePciHostdevs) < 0)
489
            goto reattachdevs;
490 491
    }

492 493 494 495 496 497 498 499 500 501 502
    /* Loop 4: For SRIOV network devices, Now that we have detached the
     * the network device, set the netdev config */
    for (i = 0; i < nhostdevs; i++) {
         virDomainHostdevDefPtr hostdev = hostdevs[i];
         if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
             continue;
         if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
             continue;
         if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
             hostdev->parent.data.net) {
             if (qemuDomainHostdevNetConfigReplace(hostdev, uuid,
503
                                                   cfg->stateDir) < 0) {
504 505 506 507 508 509 510
                 goto resetvfnetconfig;
             }
         }
         last_processed_hostdev_vf = i;
    }

    /* Loop 5: Now mark all the devices as active */
511 512 513
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0)
514
            goto inactivedevs;
515 516
    }

517
    /* Loop 6: Now remove the devices from inactive list. */
518 519 520
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
         virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
         virPCIDeviceListDel(driver->inactivePciHostdevs, dev);
521 522
    }

523
    /* Loop 7: Now set the used_by_domain of the device in
524 525
     * driver->activePciHostdevs as domain name.
     */
526 527
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev, activeDev;
528

529 530
        dev = virPCIDeviceListGet(pcidevs, i);
        activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
531

532
        if (activeDev)
533
            virPCIDeviceSetUsedBy(activeDev, name);
534 535
    }

536
    /* Loop 8: Now set the original states for hostdev def */
537
    for (i = 0; i < nhostdevs; i++) {
538 539
        virPCIDevicePtr dev;
        virPCIDevicePtr pcidev;
540 541 542 543 544 545 546
        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;

547 548 549 550
        dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.domain,
                              hostdev->source.subsys.u.pci.bus,
                              hostdev->source.subsys.u.pci.slot,
                              hostdev->source.subsys.u.pci.function);
551 552 553 554 555

        /* original states "unbind_from_stub", "remove_slot",
         * "reprobe" were already set by pciDettachDevice in
         * loop 2.
         */
556
        if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) {
557
            hostdev->origstates.states.pci.unbind_from_stub =
558
                virPCIDeviceGetUnbindFromStub(pcidev);
559
            hostdev->origstates.states.pci.remove_slot =
560
                virPCIDeviceGetRemoveSlot(pcidev);
561
            hostdev->origstates.states.pci.reprobe =
562
                virPCIDeviceGetReprobe(pcidev);
563 564
        }

565
        virPCIDeviceFree(dev);
566 567
    }

568
    /* Loop 9: Now steal all the devices from pcidevs */
569 570
    while (virPCIDeviceListCount(pcidevs) > 0)
        virPCIDeviceListStealIndex(pcidevs, 0);
571

572
    ret = 0;
573 574 575 576
    goto cleanup;

inactivedevs:
    /* Only steal all the devices from driver->activePciHostdevs. We will
577
     * free them in virObjectUnref().
578
     */
579 580 581
    while (virPCIDeviceListCount(pcidevs) > 0) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, 0);
        virPCIDeviceListSteal(driver->activePciHostdevs, dev);
582
    }
583

584 585 586 587 588
resetvfnetconfig:
    for (i = 0; i < last_processed_hostdev_vf; i++) {
         virDomainHostdevDefPtr hostdev = hostdevs[i];
         if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
             hostdev->parent.data.net) {
589
             qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
590 591 592
         }
    }

593
reattachdevs:
594 595 596
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDeviceReattach(dev, driver->activePciHostdevs, NULL, "pci-stub");
597 598
    }

599
cleanup:
600 601
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
602
    virObjectUnref(pcidevs);
603
    virObjectUnref(cfg);
604 605 606
    return ret;
}

607
int
608
qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
609
                             const char *name,
610
                             virUSBDeviceListPtr list)
611
{
612
    int i, j;
613
    unsigned int count;
614
    virUSBDevicePtr tmp;
615

616
    virObjectLock(driver->activeUsbHostdevs);
617
    count = virUSBDeviceListCount(list);
618 619

    for (i = 0; i < count; i++) {
620 621 622
        virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
        if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) {
            const char *other_name = virUSBDeviceGetUsedBy(tmp);
623 624

            if (other_name)
625 626
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is in use by domain %s"),
627
                               virUSBDeviceGetName(tmp), other_name);
628
            else
629 630
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is already in use"),
631
                               virUSBDeviceGetName(tmp));
632
            goto error;
633 634
        }

635
        virUSBDeviceSetUsedBy(usb, name);
636
        VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
637
                  virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
638 639
        /*
         * The caller is responsible to steal these usb devices
640
         * from the virUSBDeviceList that passed in on success,
641 642
         * perform rollback on failure.
         */
643
        if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0)
644
            goto error;
645
    }
646 647

    virObjectUnlock(driver->activeUsbHostdevs);
648
    return 0;
649 650 651

error:
    for (j = 0; j < i; j++) {
652 653
        tmp = virUSBDeviceListGet(list, i);
        virUSBDeviceListSteal(driver->activeUsbHostdevs, tmp);
654
    }
655
    virObjectUnlock(driver->activeUsbHostdevs);
656
    return -1;
657 658
}

659 660 661
int
qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
                         bool mandatory,
662
                         virUSBDevicePtr *usb)
663 664 665 666 667
{
    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;
668
    bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
669
    int rc;
670

671
    *usb = NULL;
672

673
    if (vendor && bus) {
674 675 676 677
        rc = virUSBDeviceFind(vendor, product, bus, device,
                              NULL,
                              autoAddress ? false : mandatory,
                              usb);
678
        if (rc < 0) {
679
            return -1;
680 681 682 683 684 685 686 687 688 689 690 691 692 693
        } 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) {
694
        virUSBDeviceListPtr devs;
695

696
        rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
697 698 699 700
        if (rc < 0)
            return -1;

        if (rc == 1) {
701 702
            *usb = virUSBDeviceListGet(devs, 0);
            virUSBDeviceListSteal(devs, *usb);
703
        }
704
        virObjectUnref(devs);
705

706 707 708
        if (rc == 0) {
            goto out;
        } else if (rc > 1) {
709 710 711 712 713 714 715 716 717 718 719
            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);
            }
720 721
            return -1;
        }
722

723 724
        hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
        hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
725 726 727 728 729 730 731 732 733 734
        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);
        }
735
    } else if (!vendor && bus) {
736
        if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
737
            return -1;
738 739
    }

740 741
out:
    if (!*usb)
742
        hostdev->missing = true;
743
    return 0;
744 745
}

746
static int
747
qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
748 749
                          virDomainDefPtr def,
                          bool coldBoot)
750 751
{
    int i, ret = -1;
752 753
    virUSBDeviceListPtr list;
    virUSBDevicePtr tmp;
754 755
    virDomainHostdevDefPtr *hostdevs = def->hostdevs;
    int nhostdevs = def->nhostdevs;
756 757 758 759 760 761

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

765
    /* Loop 1: build temporary list
766 767 768
     */
    for (i = 0 ; i < nhostdevs ; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
769
        bool required = true;
770
        virUSBDevicePtr usb;
771 772 773 774 775 776

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

777 778 779 780 781 782
        if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
            (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
             !coldBoot))
            required = false;

        if (qemuFindHostdevUSBDevice(hostdev, required, &usb) < 0)
783
            goto cleanup;
784

785 786
        if (usb && virUSBDeviceListAdd(list, usb) < 0) {
            virUSBDeviceFree(usb);
787
            goto cleanup;
788 789 790
        }
    }

791
    /* Mark devices in temporary list as used by @name
792 793 794
     * and add them do driver list. However, if something goes
     * wrong, perform rollback.
     */
795
    if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0)
796
        goto cleanup;
797

798
    /* Loop 2: Temporary list was successfully merged with
799 800 801
     * driver list, so steal all items to avoid freeing them
     * in cleanup label.
     */
802 803 804
    while (virUSBDeviceListCount(list) > 0) {
        tmp = virUSBDeviceListGet(list, 0);
        virUSBDeviceListSteal(list, tmp);
805 806 807 808 809
    }

    ret = 0;

cleanup:
810
    virObjectUnref(list);
811
    return ret;
812 813
}

814
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
815 816
                           virDomainDefPtr def,
                           bool coldBoot)
817 818 819 820
{
    if (!def->nhostdevs)
        return 0;

821 822
    if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
                                     def->hostdevs, def->nhostdevs) < 0)
823 824
        return -1;

825
    if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
826 827 828 829 830 831
        return -1;

    return 0;
}


832 833 834 835
/*
 * Pre-condition: driver->inactivePciHostdevs & driver->activePciHostdevs
 * are locked
 */
836
void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver)
837 838 839
{
    int retries = 100;

840 841 842
    /* If the device is not managed and was attached to guest
     * successfully, it must have been inactive.
     */
843 844 845
    if (!virPCIDeviceGetManaged(dev)) {
        if (virPCIDeviceListAdd(driver->inactivePciHostdevs, dev) < 0)
            virPCIDeviceFree(dev);
846
        return;
847
    }
848

849
    while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
850 851 852 853 854
           && retries) {
        usleep(100*1000);
        retries--;
    }

855 856
    if (virPCIDeviceReattach(dev, driver->activePciHostdevs,
                             driver->inactivePciHostdevs, "pci-stub") < 0) {
857 858 859 860
        virErrorPtr err = virGetLastError();
        VIR_ERROR(_("Failed to re-attach PCI device: %s"),
                  err ? err->message : _("unknown error"));
        virResetError(err);
861
    }
862
    virPCIDeviceFree(dev);
863 864 865
}


866
void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
867
                                      const char *name,
868 869 870
                                      virDomainHostdevDefPtr *hostdevs,
                                      int nhostdevs)
{
871
    virPCIDeviceListPtr pcidevs;
872
    int i;
873
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
874

875 876 877
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);

878 879 880
    if (!(pcidevs = qemuGetActivePciHostDeviceList(driver,
                                                   hostdevs,
                                                   nhostdevs))) {
881
        virErrorPtr err = virGetLastError();
882
        VIR_ERROR(_("Failed to allocate PCI device list: %s"),
883 884
                  err ? err->message : _("unknown error"));
        virResetError(err);
885
        goto cleanup;
886 887
    }

888 889 890 891
    /* 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
     */
892 893 894
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        virPCIDevicePtr activeDev = NULL;
895 896 897 898

        /* Never delete the dev from list driver->activePciHostdevs
         * if it's used by other domain.
         */
899
        activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
900
        if (activeDev &&
901 902
            STRNEQ_NULLABLE(name, virPCIDeviceGetUsedBy(activeDev))) {
            virPCIDeviceListSteal(pcidevs, dev);
903
            continue;
904
        }
905

906
        /* virObjectUnref() will take care of freeing the dev. */
907
        virPCIDeviceListSteal(driver->activePciHostdevs, dev);
908 909
    }

910 911 912 913 914 915 916 917 918 919 920 921
    /*
     * For SRIOV net host devices, unset mac and port profile before
     * reset and reattach device
     */
    for (i = 0; i < nhostdevs; i++) {
         virDomainHostdevDefPtr hostdev = hostdevs[i];
         if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
             continue;
         if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
             continue;
         if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
             hostdev->parent.data.net) {
922
             qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
923 924 925
         }
    }

926 927 928 929
    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
        virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
        if (virPCIDeviceReset(dev, driver->activePciHostdevs,
                              driver->inactivePciHostdevs) < 0) {
930 931 932 933 934 935 936
            virErrorPtr err = virGetLastError();
            VIR_ERROR(_("Failed to reset PCI device: %s"),
                      err ? err->message : _("unknown error"));
            virResetError(err);
        }
    }

937 938
    while (virPCIDeviceListCount(pcidevs) > 0) {
        virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
939 940 941
        qemuReattachPciDevice(dev, driver);
    }

942
    virObjectUnref(pcidevs);
943
cleanup:
944 945
    virObjectUnlock(driver->activePciHostdevs);
    virObjectUnlock(driver->inactivePciHostdevs);
946
    virObjectUnref(cfg);
947 948
}

949
static void
950
qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
951 952 953 954 955 956
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
    int i;

957
    virObjectLock(driver->activeUsbHostdevs);
958 959
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
960
        virUSBDevicePtr usb, tmp;
961 962 963 964 965 966
        const char *used_by = NULL;

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

970 971 972
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987

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

988 989
        tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb);
        virUSBDeviceFree(usb);
990 991 992 993 994 995 996 997 998

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

999
        used_by = virUSBDeviceGetUsedBy(tmp);
1000 1001 1002 1003 1004 1005
        if (STREQ_NULLABLE(used_by, name)) {
            VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
                      hostdev->source.subsys.u.usb.bus,
                      hostdev->source.subsys.u.usb.device,
                      name);

1006
            virUSBDeviceListDel(driver->activeUsbHostdevs, tmp);
1007 1008
        }
    }
1009
    virObjectUnlock(driver->activeUsbHostdevs);
1010
}
1011

1012
void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
1013 1014 1015 1016 1017
                                   virDomainDefPtr def)
{
    if (!def->nhostdevs)
        return;

1018 1019
    qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
1020 1021 1022

    qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
1023
}