libvirt/src/util/virmdev.h

154 lines
4.5 KiB
C
Raw Normal View History

/*
* virmdev.h: helper APIs for managing host mediated devices
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "internal.h"
#include "virobject.h"
#include "virenum.h"
typedef enum {
VIR_MDEV_MODEL_TYPE_VFIO_PCI = 0,
VIR_MDEV_MODEL_TYPE_VFIO_CCW = 1,
VIR_MDEV_MODEL_TYPE_VFIO_AP = 2,
VIR_MDEV_MODEL_TYPE_LAST
} virMediatedDeviceModelType;
VIR_ENUM_DECL(virMediatedDeviceModel);
typedef struct _virMediatedDevice virMediatedDevice;
typedef struct _virMediatedDeviceList virMediatedDeviceList;
typedef struct _virMediatedDeviceAttr virMediatedDeviceAttr;
struct _virMediatedDeviceAttr {
char *name;
char *value;
};
virMediatedDeviceAttr *virMediatedDeviceAttrNew(void);
void virMediatedDeviceAttrFree(virMediatedDeviceAttr *attr);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virMediatedDeviceAttr, virMediatedDeviceAttrFree);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virMediatedDeviceList, virObjectUnref);
typedef struct _virMediatedDeviceType virMediatedDeviceType;
struct _virMediatedDeviceType {
char *id;
char *name;
char *device_api;
unsigned int available_instances;
};
typedef int (*virMediatedDeviceCallback)(virMediatedDevice *dev,
const char *path, void *opaque);
virMediatedDevice *
virMediatedDeviceNew(const char *uuidstr, virMediatedDeviceModelType model);
virMediatedDevice *
virMediatedDeviceCopy(virMediatedDevice *dev);
void
virMediatedDeviceFree(virMediatedDevice *dev);
const char *
virMediatedDeviceGetPath(virMediatedDevice *dev);
void
virMediatedDeviceGetUsedBy(virMediatedDevice *dev,
const char **drvname, const char **domname);
int
virMediatedDeviceSetUsedBy(virMediatedDevice *dev,
const char *drvname,
const char *domname);
char *
virMediatedDeviceGetIOMMUGroupDev(const char *uuidstr);
int
virMediatedDeviceGetIOMMUGroupNum(const char *uuidstr);
char *
virMediatedDeviceGetSysfsPath(const char *uuidstr);
bool
virMediatedDeviceIsUsed(virMediatedDevice *dev,
virMediatedDeviceList *list);
bool
virMediatedDeviceIsUsed(virMediatedDevice *dev,
virMediatedDeviceList *list);
virMediatedDeviceList *
virMediatedDeviceListNew(void);
int
virMediatedDeviceListAdd(virMediatedDeviceList *list,
virMediatedDevice **dev);
virMediatedDevice *
virMediatedDeviceListGet(virMediatedDeviceList *list,
ssize_t idx);
size_t
virMediatedDeviceListCount(virMediatedDeviceList *list);
virMediatedDevice *
virMediatedDeviceListSteal(virMediatedDeviceList *list,
virMediatedDevice *dev);
virMediatedDevice *
virMediatedDeviceListStealIndex(virMediatedDeviceList *list,
ssize_t idx);
void
virMediatedDeviceListDel(virMediatedDeviceList *list,
virMediatedDevice *dev);
virMediatedDevice *
virMediatedDeviceListFind(virMediatedDeviceList *list,
hostdev: mdev: Lookup mdevs by sysfs path rather than mdev struct The lookup didn't do anything apart from comparing the sysfs paths anyway since that's what makes each mdev unique. The most ridiculous usage of the old logic was in virHostdevReAttachMediatedDevices where in order to drop an mdev hostdev from the list of active devices we first had to create a new mdev and use it in the lookup call. Why couldn't we have used the hostdev directly? Because the hostdev and mdev structures are incompatible. The way mdevs are currently removed is via a write to a specific sysfs attribute. If you do it while the machine which has the mdev assigned is running, the write call may block (with a new enough kernel, with older kernels it would return a write error!) until the device is no longer in use which is when the QEMU process exits. The interesting part here comes afterwards when we're cleaning up and call virHostdevReAttachMediatedDevices. The domain doesn't exist anymore, so the list of active hostdevs needs to be updated and the respective hostdevs removed from the list, but remember we had to create an mdev object in the memory in order to find it in the list first which will fail because the write to sysfs had already removed the mdev instance from the host system. And so the next time you try to start the same domain you'll get: "Requested operation is not valid: mediated device <path> is in use by driver QEMU, domain <name>" Fixes: https://gitlab.com/libvirt/libvirt/-/issues/119 Signed-off-by: Erik Skultety <eskultet@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-01-07 15:53:21 +00:00
const char *sysfspath);
int
virMediatedDeviceListFindIndex(virMediatedDeviceList *list,
hostdev: mdev: Lookup mdevs by sysfs path rather than mdev struct The lookup didn't do anything apart from comparing the sysfs paths anyway since that's what makes each mdev unique. The most ridiculous usage of the old logic was in virHostdevReAttachMediatedDevices where in order to drop an mdev hostdev from the list of active devices we first had to create a new mdev and use it in the lookup call. Why couldn't we have used the hostdev directly? Because the hostdev and mdev structures are incompatible. The way mdevs are currently removed is via a write to a specific sysfs attribute. If you do it while the machine which has the mdev assigned is running, the write call may block (with a new enough kernel, with older kernels it would return a write error!) until the device is no longer in use which is when the QEMU process exits. The interesting part here comes afterwards when we're cleaning up and call virHostdevReAttachMediatedDevices. The domain doesn't exist anymore, so the list of active hostdevs needs to be updated and the respective hostdevs removed from the list, but remember we had to create an mdev object in the memory in order to find it in the list first which will fail because the write to sysfs had already removed the mdev instance from the host system. And so the next time you try to start the same domain you'll get: "Requested operation is not valid: mediated device <path> is in use by driver QEMU, domain <name>" Fixes: https://gitlab.com/libvirt/libvirt/-/issues/119 Signed-off-by: Erik Skultety <eskultet@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
2021-01-07 15:53:21 +00:00
const char *sysfspath);
int
virMediatedDeviceListMarkDevices(virMediatedDeviceList *dst,
virMediatedDeviceList *src,
const char *drvname,
const char *domname);
void
virMediatedDeviceTypeFree(virMediatedDeviceType *type);
int
virMediatedDeviceTypeReadAttrs(const char *sysfspath,
virMediatedDeviceType **type);
ssize_t
virMediatedDeviceGetMdevTypes(const char *sysfspath,
virMediatedDeviceType ***types,
size_t *ntypes);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virMediatedDevice, virMediatedDeviceFree);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virMediatedDeviceType, virMediatedDeviceTypeFree);