qemu_hostdev.c 25.0 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 45 46 47 48 49 50 51 52
int
qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
                            virDomainDefPtr def)
{
    virHostdevManagerPtr mgr = driver->hostdevMgr;

    if (!def->nhostdevs)
        return 0;

53
    return virHostdevUpdateActivePciHostdevs(mgr, QEMU_DRIVER_NAME, def);
54 55
}

56 57 58 59 60 61 62 63 64
int
qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
                            virDomainDefPtr def)
{
    virHostdevManagerPtr mgr = driver->hostdevMgr;

    if (!def->nhostdevs)
        return 0;

65
    return virHostdevUpdateActiveUsbHostdevs(mgr, QEMU_DRIVER_NAME, def);
66 67
}

68 69 70 71 72 73 74 75 76
int
qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
                             virDomainDefPtr def)
{
    virHostdevManagerPtr mgr = driver->hostdevMgr;

    if (!def->nhostdevs)
        return 0;

77
    return virHostdevUpdateActiveScsiHostdevs(mgr, QEMU_DRIVER_NAME, def);
78 79
}

80

81
bool
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
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>
121
bool
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
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
143
bool
144 145 146 147 148 149 150 151 152
qemuHostdevHostSupportsPassthroughLegacy(void)
{
    return false;
}
#endif


static bool
qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
153 154
                                  size_t nhostdevs,
                                  virQEMUCapsPtr qemuCaps)
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
{
    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) {
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
        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;

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
        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;
}

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
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;

228 229
    ret = virHostdevPreparePCIDevices(hostdev_mgr, QEMU_DRIVER_NAME,
                                      name, uuid, hostdevs,
230
                                      nhostdevs, flags);
231
out:
232 233 234
    return ret;
}

235

236
static int
237 238 239
virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr,
                          const char *name,
                          virUSBDeviceListPtr list)
240
{
241
    size_t i, j;
242
    unsigned int count;
243
    virUSBDevicePtr tmp;
244

245
    virObjectLock(mgr->activeUsbHostdevs);
246
    count = virUSBDeviceListCount(list);
247 248

    for (i = 0; i < count; i++) {
249
        virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
250
        if ((tmp = virUSBDeviceListFind(mgr->activeUsbHostdevs, usb))) {
C
Chunyan Liu 已提交
251 252
            const char *other_drvname;
            const char *other_domname;
253

C
Chunyan Liu 已提交
254 255
            virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
            if (other_drvname && other_domname)
256
                virReportError(VIR_ERR_OPERATION_INVALID,
C
Chunyan Liu 已提交
257 258 259 260
                               _("USB device %s is in use by "
                                 "driver %s, domain %s"),
                               virUSBDeviceGetName(tmp),
                               other_drvname, other_domname);
261
            else
262 263
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("USB device %s is already in use"),
264
                               virUSBDeviceGetName(tmp));
265
            goto error;
266 267
        }

C
Chunyan Liu 已提交
268
        virUSBDeviceSetUsedBy(usb, QEMU_DRIVER_NAME, name);
269
        VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
270
                  virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
271 272
        /*
         * The caller is responsible to steal these usb devices
273
         * from the virUSBDeviceList that passed in on success,
274 275
         * perform rollback on failure.
         */
276
        if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0)
277
            goto error;
278
    }
279

280
    virObjectUnlock(mgr->activeUsbHostdevs);
281
    return 0;
282 283 284

error:
    for (j = 0; j < i; j++) {
285
        tmp = virUSBDeviceListGet(list, i);
286
        virUSBDeviceListSteal(mgr->activeUsbHostdevs, tmp);
287
    }
288
    virObjectUnlock(mgr->activeUsbHostdevs);
289
    return -1;
290 291
}

292

293
static int
294 295 296
virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
                        bool mandatory,
                        virUSBDevicePtr *usb)
297 298 299 300 301
{
    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;
302
    bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
303
    int rc;
304

305
    *usb = NULL;
306

307
    if (vendor && bus) {
308 309 310 311
        rc = virUSBDeviceFind(vendor, product, bus, device,
                              NULL,
                              autoAddress ? false : mandatory,
                              usb);
312
        if (rc < 0) {
313
            return -1;
314 315 316 317 318 319 320 321 322 323 324 325 326 327
        } 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) {
328
        virUSBDeviceListPtr devs;
329

330
        rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
331 332 333 334
        if (rc < 0)
            return -1;

        if (rc == 1) {
335 336
            *usb = virUSBDeviceListGet(devs, 0);
            virUSBDeviceListSteal(devs, *usb);
337
        }
338
        virObjectUnref(devs);
339

340 341 342
        if (rc == 0) {
            goto out;
        } else if (rc > 1) {
343 344 345 346 347 348 349 350 351 352 353
            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);
            }
354 355
            return -1;
        }
356

357 358
        hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
        hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
359 360 361 362 363 364 365 366 367 368
        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);
        }
369
    } else if (!vendor && bus) {
370
        if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
371
            return -1;
372 373
    }

374 375
out:
    if (!*usb)
376
        hostdev->missing = true;
377
    return 0;
378 379
}

380 381 382 383 384 385
static int
virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr,
                            const char *name,
                            virDomainHostdevDefPtr *hostdevs,
                            int nhostdevs,
                            unsigned int flags)
386
{
387 388
    size_t i;
    int ret = -1;
389 390
    virUSBDeviceListPtr list;
    virUSBDevicePtr tmp;
391
    bool coldBoot = !!(flags & VIR_HOSTDEV_COLD_BOOT);
392 393 394 395

    /* 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
396
     * loop. See virHostdevPreparePCIDevices()
397
     */
398
    if (!(list = virUSBDeviceListNew()))
399 400
        goto cleanup;

401
    /* Loop 1: build temporary list
402
     */
403
    for (i = 0; i < nhostdevs; i++) {
404
        virDomainHostdevDefPtr hostdev = hostdevs[i];
405
        bool required = true;
406
        virUSBDevicePtr usb;
407 408 409 410 411 412

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

413 414 415 416 417
        if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
            (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
             !coldBoot))
            required = false;

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

421 422
        if (usb && virUSBDeviceListAdd(list, usb) < 0) {
            virUSBDeviceFree(usb);
423
            goto cleanup;
424 425 426
        }
    }

427
    /* Mark devices in temporary list as used by @name
428 429 430
     * and add them do driver list. However, if something goes
     * wrong, perform rollback.
     */
431
    if (virHostdevMarkUsbHostdevs(hostdev_mgr, name, list) < 0)
432
        goto cleanup;
433

434
    /* Loop 2: Temporary list was successfully merged with
435 436 437
     * driver list, so steal all items to avoid freeing them
     * in cleanup label.
     */
438 439 440
    while (virUSBDeviceListCount(list) > 0) {
        tmp = virUSBDeviceListGet(list, 0);
        virUSBDeviceListSteal(list, tmp);
441 442 443 444 445
    }

    ret = 0;

cleanup:
446
    virObjectUnref(list);
447
    return ret;
448 449
}

450 451 452 453 454 455 456 457 458 459 460 461 462
int
qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
                          const char *name,
                          virDomainHostdevDefPtr *hostdevs,
                          int nhostdevs,
                          unsigned int flags)
{
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    return virHostdevPrepareUSBDevices(hostdev_mgr, name,
                                       hostdevs, nhostdevs, flags);
}

463

464 465 466 467 468 469
int
qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
                              const char *name,
                              virDomainHostdevDefPtr *hostdevs,
                              int nhostdevs)
{
470 471
    size_t i, j;
    int count;
472 473
    virSCSIDeviceListPtr list;
    virSCSIDevicePtr tmp;
474
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
475

476 477 478 479 480 481 482 483 484 485 486
    /* 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;
487 488 489

        if (qemuSetUnprivSGIO(&dev) < 0)
            return -1;
490 491
    }

492 493 494
    /* 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
495
     * loop. See virHostdevPreparePCIDevices()
496 497 498 499
     */
    if (!(list = virSCSIDeviceListNew()))
        goto cleanup;

500
    /* Loop 2: build temporary list */
501
    for (i = 0; i < nhostdevs; i++) {
502 503 504 505 506 507 508 509 510 511 512 513 514
        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;
        }

515 516
        if (!(scsi = virSCSIDeviceNew(NULL,
                                      hostdev->source.subsys.u.scsi.adapter,
517 518 519
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
520 521
                                      hostdev->readonly,
                                      hostdev->shareable)))
522 523 524 525 526 527 528 529
            goto cleanup;

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

530
    /* Loop 3: Mark devices in temporary list as used by @name
531 532 533
     * and add them to driver list. However, if something goes
     * wrong, perform rollback.
     */
534
    virObjectLock(hostdev_mgr->activeScsiHostdevs);
535 536 537 538
    count = virSCSIDeviceListCount(list);

    for (i = 0; i < count; i++) {
        virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
539 540
        if ((tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs,
                                         scsi))) {
541 542
            bool scsi_shareable = virSCSIDeviceGetShareable(scsi);
            bool tmp_shareable = virSCSIDeviceGetShareable(tmp);
543

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

C
Chunyan Liu 已提交
553
            if (virSCSIDeviceSetUsedBy(tmp, QEMU_DRIVER_NAME, name) < 0)
554 555
                goto error;
        } else {
C
Chunyan Liu 已提交
556
            if (virSCSIDeviceSetUsedBy(scsi, QEMU_DRIVER_NAME, name) < 0)
557
                goto error;
558

559 560
            VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi));

561
            if (virSCSIDeviceListAdd(hostdev_mgr->activeScsiHostdevs, scsi) < 0)
562 563
                goto error;
        }
564 565
    }

566
    virObjectUnlock(hostdev_mgr->activeScsiHostdevs);
567

568
    /* Loop 4: Temporary list was successfully merged with
569 570 571 572 573 574 575 576 577 578 579 580 581 582
     * 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);
583
        virSCSIDeviceListSteal(hostdev_mgr->activeScsiHostdevs, tmp);
584
    }
585
    virObjectUnlock(hostdev_mgr->activeScsiHostdevs);
586 587 588 589 590
cleanup:
    virObjectUnref(list);
    return -1;
}

591 592 593 594

int
qemuPrepareHostDevices(virQEMUDriverPtr driver,
                       virDomainDefPtr def,
595
                       virQEMUCapsPtr qemuCaps,
596
                       unsigned int flags)
597 598 599 600
{
    if (!def->nhostdevs)
        return 0;

601
    if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
602
                                     def->hostdevs, def->nhostdevs,
603
                                     qemuCaps, flags) < 0)
604 605
        return -1;

606
    if (qemuPrepareHostUSBDevices(driver, def->name,
607
                                  def->hostdevs, def->nhostdevs, flags) < 0)
608 609
        return -1;

610 611 612 613
    if (qemuPrepareHostdevSCSIDevices(driver, def->name,
                                      def->hostdevs, def->nhostdevs) < 0)
        return -1;

614 615 616
    return 0;
}

617 618 619 620 621 622 623 624 625 626
void
qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    char *oldStateDir = cfg->stateDir;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

627
    virHostdevReAttachPCIDevices(hostdev_mgr, QEMU_DRIVER_NAME, name,
628 629
                                 hostdevs, nhostdevs, oldStateDir);

630
    virObjectUnref(cfg);
631 632
}

633

634
void
635
qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
636 637 638 639
                                 const char *name,
                                 virDomainHostdevDefPtr *hostdevs,
                                 int nhostdevs)
{
640
    size_t i;
641
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
642

643
    virObjectLock(hostdev_mgr->activeUsbHostdevs);
644 645
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
646
        virUSBDevicePtr usb, tmp;
C
Chunyan Liu 已提交
647 648
        const char *usedby_drvname;
        const char *usedby_domname;
649 650 651 652 653

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

657 658 659
        usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
                              hostdev->source.subsys.u.usb.device,
                              NULL);
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674

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

675
        tmp = virUSBDeviceListFind(hostdev_mgr->activeUsbHostdevs, usb);
676
        virUSBDeviceFree(usb);
677 678 679 680 681 682 683 684 685

        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 已提交
686 687 688
        virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname);
        if (STREQ_NULLABLE(QEMU_DRIVER_NAME, usedby_drvname) &&
            STREQ_NULLABLE(name, usedby_domname)) {
689 690 691 692 693
            VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
                      hostdev->source.subsys.u.usb.bus,
                      hostdev->source.subsys.u.usb.device,
                      name);

694
            virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, tmp);
695 696
        }
    }
697
    virObjectUnlock(hostdev_mgr->activeUsbHostdevs);
698
}
699

700

701 702 703 704 705 706
void
qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
                                  const char *name,
                                  virDomainHostdevDefPtr *hostdevs,
                                  int nhostdevs)
{
707
    size_t i;
708
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
709

710
    virObjectLock(hostdev_mgr->activeScsiHostdevs);
711 712
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
713 714
        virSCSIDevicePtr scsi;
        virSCSIDevicePtr tmp;
715 716 717 718 719 720
        virDomainDeviceDef dev;

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

        ignore_value(qemuRemoveSharedDevice(driver, &dev, name));
721 722 723 724 725

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

726 727
        if (!(scsi = virSCSIDeviceNew(NULL,
                                      hostdev->source.subsys.u.scsi.adapter,
728 729 730
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
731 732
                                      hostdev->readonly,
                                      hostdev->shareable))) {
733 734 735 736 737 738 739 740 741 742 743 744
            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. */

745
        if (!(tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, scsi))) {
746 747 748 749 750 751
            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);
752
            virSCSIDeviceFree(scsi);
753 754 755
            continue;
        }

756 757 758 759 760 761
        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);
762

763
        virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, QEMU_DRIVER_NAME, name);
764
        virSCSIDeviceFree(scsi);
765
    }
766
    virObjectUnlock(hostdev_mgr->activeScsiHostdevs);
767 768
}

769 770 771
void
qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
                              virDomainDefPtr def)
772 773 774 775
{
    if (!def->nhostdevs)
        return;

776 777
    qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
778 779 780

    qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
                                     def->nhostdevs);
781 782 783

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