On Fri, Jan 05, 2024 at 03:20:16 -0500, Laine Stump wrote:
Rather than always binding to the vfio-pci driver, use the new
function virPCIDeviceFindBestVFIOVariant() to see if the running
kernel has a VFIO variant driver available that is a better match for
the device, and if one is found, use that instead.
virPCIDeviceFindBestVFIOVariant() function reads the modalias file for
the given device from sysfs, then looks through
/lib/modules/${kernel_release}/modules.alias for the vfio_pci alias
that matches with the least number of wildcard ('*') fields.
The appropriate "VFIO variant" driver for a device will be the PCI
driver implemented by the discovered module - these drivers are
compatible with (and provide the entire API of) the standard vfio-pci
driver, but have additional device-specific APIs that can be useful
for, e.g., saving/restoring state for migration.
If a specific driver is named (using <driver model='blah'/> in the
device XML), that will still be used rather than searching
modules.alias; this makes it possible to force binding of vfio-pci if
there is an issue with the auto-selected variant driver.
Signed-off-by: Laine Stump <laine(a)redhat.com>
---
Changes from V2:
* fail if device modalias file isn't found.
This [1] ...
* use unsigned int instead of int for wildcardCt
* increase file memory buffer from 4MB to 8MB
* other minor nits pointed out by Peter
[...]
+/* virPCIDeviceFindBestVFIOVariant:
+ *
+ * Find the "best" match of all vfio_pci aliases for @dev in the host
+ * modules.alias file. This uses the algorithm of finding every
+ * modules.alias line that begins with "vfio_pci:", then picking the
+ * one that matches the device's own modalias value (from the file of
+ * that name in the device's sysfs directory) with the fewest
+ * "wildcards" (* character, meaning "match any value for this
+ * attribute").
+ */
+int
+virPCIDeviceFindBestVFIOVariant(virPCIDevice *dev,
+ char **moduleName)
+{
+ g_autofree char *devModAliasPath = NULL;
+ g_autofree char *devModAliasContent = NULL;
+ const char *devModAlias;
+ g_autoptr(virPCIDeviceAliasInfo) devModAliasInfo = NULL;
+ struct utsname unameInfo;
+ g_autofree char *modulesAliasPath = NULL;
+ g_autofree char *modulesAliasContent = NULL;
+ const char *line;
+ unsigned int currentBestWildcardCt = INT_MAX;
UINT_MAX
+
+ *moduleName = NULL;
+
+ /* get the modalias values for the device from sysfs */
+ devModAliasPath = virPCIFile(dev->name, "modalias");
+ if (virFileReadAll(devModAliasPath, 100, &devModAliasContent) < 0)
... [1] isn't true.
+ return -1;
+
+ VIR_DEBUG("modalias path: '%s' contents: '%s'",
+ devModAliasPath, devModAliasContent);
+
+ /* "pci:vNNNNNNNNdNNNNNNNNsvNNNNNNNNsdNNNNNNNNbcNNscNNiNN\n" */
+ if ((devModAlias = STRSKIP(devModAliasContent, "pci:")) == NULL ||
+ !(devModAliasInfo = virPCIDeviceAliasInfoNew(devModAlias))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("device modalias file %1$s content has improper
format"),
+ devModAliasPath);
+ return -1;
+ }
+
+ uname(&unameInfo);
+ modulesAliasPath = g_strdup_printf("/lib/modules/%s/modules.alias",
unameInfo.release);
+ if (virFileReadAll(modulesAliasPath, 8 * 1024 * 1024, &modulesAliasContent) <
0)
+ return -1;
IIUC this is picking a driver which is 'better' than the default
'vfio_pci', but the device itself would still work if the default were
used, right?
In such case do we really want to treat any of the errors above as
failures? I presueme a workaround for if any of the above breaks is to
use an explicitly specified driver, right?
+
+ /* Look for all lines that are aliases for vfio_pci drivers.
+ * (The first line is always a comment, so we can be sure "alias"
+ * is preceded by a newline)
+ */
+ line = modulesAliasContent;
+