[libvirt] [PATCH 00/15] Nodedev-mdev overhaul

TL;DR: nodedev: - contained a decent amount of redundant code handling the same thing, now it doesn't. - only updated dynamic capabilities during dumpXML, now it does every time it touches them mdev: - didn't update mdev capabilities at all, now it does This series combines some long-needed refactor changes to the nodedev driver with some necessary mdev fixes based on Wu Zongyong's patch series [1]. There's a lot of simple code movement due to the fact that update of the device capabilities is strictly bound to the nodedev driver. The problem with the existing approach is that in order to properly update all capabilities, especially mdev, we would have to violate the logical code flow we have and call back into the driver to have access to sysfs, i.e. driver->(conf|obj) handling->util_helpers->DRIVER. Therefore to resolve it, along with all the compilation dependencies, I moved most of the capability handling out of the driver into src/conf/node_device_conf.c which already contained more than just parsing and formatting of the capabilities. I also had to move the existing virNodeDevCapMdevType into src/util so that the util helpers would know the type they're working with. [1] https://www.redhat.com/archives/libvir-list/2018-January/msg00315.html Erik Skultety (15): conf: nodedev: Rename virNodeDevObjHasCap to virNodeDevObjHasCapStr conf: nodedev: Rename virNodeDeviceCapMatch to virNodeDevObjHasCap conf: nodedev: Convert virNodeDevObjHasCapStr to a simple wrapper nodedev: Drop the nodeDeviceSysfsGetSCSIHostCaps wrapper nodedev: Move the sysfs-related cap handling to node_device_conf.c nodedev: Export nodeDeviceUpdateCaps from node_device_conf.c nodedev: Introduce virNodeDeviceCapsListExport conf: nodedev: Refresh capabilities before touching them util: mdev: Drop some unused symbols/includes from the header util: mdev: Introduce virMediatedDeviceType structure util: mdev: Introduce virMediatedDeviceTypeReadAttrs getter util: pci: Introduce virPCIGetMdevTypes helper nodedev: udev: Drop the unused mdev type helpers conf: Replace usage of virNodeDevCapMdevType with virMediatedDeviceType conf: nodedev: Update PCI mdev capabilities dynamically src/Makefile.am | 4 +- src/conf/node_device_conf.c | 343 ++++++++++++++++++++++++++++-- src/conf/node_device_conf.h | 29 +-- src/conf/virnodedeviceobj.c | 74 ++----- src/libvirt_private.syms | 7 +- src/node_device/node_device_driver.c | 130 ++--------- src/node_device/node_device_hal.c | 5 +- src/node_device/node_device_linux_sysfs.c | 218 ------------------- src/node_device/node_device_linux_sysfs.h | 34 --- src/node_device/node_device_udev.c | 127 +---------- src/util/virmdev.c | 47 ++++ src/util/virmdev.h | 20 +- src/util/virpci.c | 58 +++++ src/util/virpci.h | 4 + 14 files changed, 516 insertions(+), 584 deletions(-) delete mode 100644 src/node_device/node_device_linux_sysfs.c delete mode 100644 src/node_device/node_device_linux_sysfs.h -- 2.13.6

We currently have 2 methods that do the capability matching. This should be condensed to a single function and all the derivates should just call into that using a proper type conversion. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index c4e3a40d3..a4d38b3a1 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -53,6 +53,8 @@ static virClassPtr virNodeDeviceObjClass; static virClassPtr virNodeDeviceObjListClass; static void virNodeDeviceObjDispose(void *opaque); static void virNodeDeviceObjListDispose(void *opaque); +static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, + const char *cap); static int virNodeDeviceObjOnceInit(void) @@ -121,8 +123,8 @@ virNodeDeviceObjGetDef(virNodeDeviceObjPtr obj) static bool -virNodeDeviceObjHasCap(const virNodeDeviceObj *obj, - const char *cap) +virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, + const char *cap) { virNodeDevCapsDefPtr caps = obj->def->caps; const char *fc_host_cap = @@ -375,7 +377,7 @@ virNodeDeviceObjListFindByCapCallback(const void *payload, int want = 0; virObjectLock(obj); - if (virNodeDeviceObjHasCap(obj, matchstr)) + if (virNodeDeviceObjHasCapStr(obj, matchstr)) want = 1; virObjectUnlock(obj); return want; @@ -750,7 +752,7 @@ virNodeDeviceObjListNumOfDevicesCallback(void *payload, virObjectLock(obj); def = obj->def; if ((!filter || filter(data->conn, def)) && - (!data->matchstr || virNodeDeviceObjHasCap(obj, data->matchstr))) + (!data->matchstr || virNodeDeviceObjHasCapStr(obj, data->matchstr))) data->count++; virObjectUnlock(obj); @@ -805,7 +807,7 @@ virNodeDeviceObjListGetNamesCallback(void *payload, def = obj->def; if ((!filter || filter(data->conn, def)) && - (!data->matchstr || virNodeDeviceObjHasCap(obj, data->matchstr))) { + (!data->matchstr || virNodeDeviceObjHasCapStr(obj, data->matchstr))) { if (VIR_STRDUP(data->names[data->nnames], def->name) < 0) { data->error = true; goto cleanup; -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
We currently have 2 methods that do the capability matching. This should be condensed to a single function and all the derivates should just call into that using a proper type conversion.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index c4e3a40d3..a4d38b3a1 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -53,6 +53,8 @@ static virClassPtr virNodeDeviceObjClass; static virClassPtr virNodeDeviceObjListClass; static void virNodeDeviceObjDispose(void *opaque); static void virNodeDeviceObjListDispose(void *opaque); +static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, + const char *cap);
I'm failing to see why this needed. ACK to the rest though. Michal

We currently have 2 methods that do the capability matching. This should be condensed to a single function and all the derivates should just call into that using a proper type conversion. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index a4d38b3a1..ccad59a4b 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -55,6 +55,8 @@ static void virNodeDeviceObjDispose(void *opaque); static void virNodeDeviceObjListDispose(void *opaque); static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap); +static bool virNodeDeviceObjHasCap(const virNodeDeviceObj *obj, + int type); static int virNodeDeviceObjOnceInit(void) @@ -683,8 +685,8 @@ virNodeDeviceObjListGetParentHost(virNodeDeviceObjListPtr devs, static bool -virNodeDeviceCapMatch(virNodeDeviceObjPtr obj, - int type) +virNodeDeviceObjHasCap(const virNodeDeviceObj *obj, + int type) { virNodeDevCapsDefPtr cap = NULL; @@ -850,7 +852,7 @@ virNodeDeviceObjListGetNames(virNodeDeviceObjListPtr devs, #define MATCH(FLAG) ((flags & (VIR_CONNECT_LIST_NODE_DEVICES_CAP_ ## FLAG)) && \ - virNodeDeviceCapMatch(obj, VIR_NODE_DEV_CAP_ ## FLAG)) + virNodeDeviceObjHasCap(obj, VIR_NODE_DEV_CAP_ ## FLAG)) static bool virNodeDeviceMatch(virNodeDeviceObjPtr obj, unsigned int flags) -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
We currently have 2 methods that do the capability matching. This should be condensed to a single function and all the derivates should just call into that using a proper type conversion.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index a4d38b3a1..ccad59a4b 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -55,6 +55,8 @@ static void virNodeDeviceObjDispose(void *opaque); static void virNodeDeviceObjListDispose(void *opaque); static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap); +static bool virNodeDeviceObjHasCap(const virNodeDeviceObj *obj, + int type);
Again, I'm failing to see why the forward declaration is needed. ACk to the rest. Michal

On Fri, Jan 26, 2018 at 12:40:46PM +0100, Michal Privoznik wrote:
On 01/25/2018 10:23 AM, Erik Skultety wrote:
We currently have 2 methods that do the capability matching. This should be condensed to a single function and all the derivates should just call into that using a proper type conversion.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index a4d38b3a1..ccad59a4b 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -55,6 +55,8 @@ static void virNodeDeviceObjDispose(void *opaque); static void virNodeDeviceObjListDispose(void *opaque); static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap); +static bool virNodeDeviceObjHasCap(const virNodeDeviceObj *obj, + int type);
Again, I'm failing to see why the forward declaration is needed. ACk to the rest.
I can drop the one from patch 1 that one is really not needed, but dropping this one would cause the compilation to fail on patch 3. Now, sure I could very easily solve this by moving the function up, but I originally decided to go this way rather than creating 2 large hunks just because of the function move. Let me know whether you'd prefer to see the function to be moved or you're fine with the forward decl. in this case. Erik

On 01/29/2018 09:47 AM, Erik Skultety wrote:
On Fri, Jan 26, 2018 at 12:40:46PM +0100, Michal Privoznik wrote:
On 01/25/2018 10:23 AM, Erik Skultety wrote:
We currently have 2 methods that do the capability matching. This should be condensed to a single function and all the derivates should just call into that using a proper type conversion.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index a4d38b3a1..ccad59a4b 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -55,6 +55,8 @@ static void virNodeDeviceObjDispose(void *opaque); static void virNodeDeviceObjListDispose(void *opaque); static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap); +static bool virNodeDeviceObjHasCap(const virNodeDeviceObj *obj, + int type);
Again, I'm failing to see why the forward declaration is needed. ACk to the rest.
I can drop the one from patch 1 that one is really not needed, but dropping this one would cause the compilation to fail on patch 3. Now, sure I could very easily solve this by moving the function up, but I originally decided to go this way rather than creating 2 large hunks just because of the function move. Let me know whether you'd prefer to see the function to be moved or you're fine with the forward decl. in this case.
Ah, okay keep them in then. I just failed to see this reasoning. Michal

This patch drops the capability matching redundancy by simply converting the string input to our internal types which are then in turn used for the actual capability matching. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 50 +-------------------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index ccad59a4b..5360df805 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -128,55 +128,7 @@ static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap) { - virNodeDevCapsDefPtr caps = obj->def->caps; - const char *fc_host_cap = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_FC_HOST); - const char *vports_cap = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_VPORTS); - const char *mdev_types = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_MDEV_TYPES); - - while (caps) { - if (STREQ(cap, virNodeDevCapTypeToString(caps->data.type))) { - return true; - } else { - switch (caps->data.type) { - case VIR_NODE_DEV_CAP_PCI_DEV: - if ((STREQ(cap, mdev_types)) && - (caps->data.pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV)) - return true; - break; - - case VIR_NODE_DEV_CAP_SCSI_HOST: - if ((STREQ(cap, fc_host_cap) && - (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST)) || - (STREQ(cap, vports_cap) && - (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))) - return true; - break; - - case VIR_NODE_DEV_CAP_SYSTEM: - case VIR_NODE_DEV_CAP_USB_DEV: - case VIR_NODE_DEV_CAP_USB_INTERFACE: - case VIR_NODE_DEV_CAP_NET: - case VIR_NODE_DEV_CAP_SCSI_TARGET: - case VIR_NODE_DEV_CAP_SCSI: - case VIR_NODE_DEV_CAP_STORAGE: - case VIR_NODE_DEV_CAP_FC_HOST: - case VIR_NODE_DEV_CAP_VPORTS: - case VIR_NODE_DEV_CAP_SCSI_GENERIC: - case VIR_NODE_DEV_CAP_DRM: - case VIR_NODE_DEV_CAP_MDEV_TYPES: - case VIR_NODE_DEV_CAP_MDEV: - case VIR_NODE_DEV_CAP_CCW_DEV: - case VIR_NODE_DEV_CAP_LAST: - break; - } - } - - caps = caps->next; - } - return false; + return virNodeDeviceObjHasCap(obj, virNodeDevCapTypeFromString(cap)); } -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
This patch drops the capability matching redundancy by simply converting the string input to our internal types which are then in turn used for the actual capability matching.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 50 +-------------------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index ccad59a4b..5360df805 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -128,55 +128,7 @@ static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap) { - virNodeDevCapsDefPtr caps = obj->def->caps; - const char *fc_host_cap = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_FC_HOST); - const char *vports_cap = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_VPORTS); - const char *mdev_types = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_MDEV_TYPES); - - while (caps) { - if (STREQ(cap, virNodeDevCapTypeToString(caps->data.type))) { - return true; - } else { - switch (caps->data.type) { - case VIR_NODE_DEV_CAP_PCI_DEV: - if ((STREQ(cap, mdev_types)) && - (caps->data.pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV)) - return true; - break; - - case VIR_NODE_DEV_CAP_SCSI_HOST: - if ((STREQ(cap, fc_host_cap) && - (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST)) || - (STREQ(cap, vports_cap) && - (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))) - return true; - break; - - case VIR_NODE_DEV_CAP_SYSTEM: - case VIR_NODE_DEV_CAP_USB_DEV: - case VIR_NODE_DEV_CAP_USB_INTERFACE: - case VIR_NODE_DEV_CAP_NET: - case VIR_NODE_DEV_CAP_SCSI_TARGET: - case VIR_NODE_DEV_CAP_SCSI: - case VIR_NODE_DEV_CAP_STORAGE: - case VIR_NODE_DEV_CAP_FC_HOST: - case VIR_NODE_DEV_CAP_VPORTS: - case VIR_NODE_DEV_CAP_SCSI_GENERIC: - case VIR_NODE_DEV_CAP_DRM: - case VIR_NODE_DEV_CAP_MDEV_TYPES: - case VIR_NODE_DEV_CAP_MDEV: - case VIR_NODE_DEV_CAP_CCW_DEV: - case VIR_NODE_DEV_CAP_LAST: - break; - } - } - - caps = caps->next; - } - return false; + return virNodeDeviceObjHasCap(obj, virNodeDevCapTypeFromString(cap));
I wonder if we should check for the TypeFromString() conversion rather than pass it to the other function directly. Michal

On Fri, Jan 26, 2018 at 12:40:34PM +0100, Michal Privoznik wrote:
On 01/25/2018 10:23 AM, Erik Skultety wrote:
This patch drops the capability matching redundancy by simply converting the string input to our internal types which are then in turn used for the actual capability matching.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 50 +-------------------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index ccad59a4b..5360df805 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -128,55 +128,7 @@ static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap) { - virNodeDevCapsDefPtr caps = obj->def->caps; - const char *fc_host_cap = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_FC_HOST); - const char *vports_cap = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_VPORTS); - const char *mdev_types = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_MDEV_TYPES); - - while (caps) { - if (STREQ(cap, virNodeDevCapTypeToString(caps->data.type))) { - return true; - } else { - switch (caps->data.type) { - case VIR_NODE_DEV_CAP_PCI_DEV: - if ((STREQ(cap, mdev_types)) && - (caps->data.pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV)) - return true; - break; - - case VIR_NODE_DEV_CAP_SCSI_HOST: - if ((STREQ(cap, fc_host_cap) && - (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST)) || - (STREQ(cap, vports_cap) && - (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))) - return true; - break; - - case VIR_NODE_DEV_CAP_SYSTEM: - case VIR_NODE_DEV_CAP_USB_DEV: - case VIR_NODE_DEV_CAP_USB_INTERFACE: - case VIR_NODE_DEV_CAP_NET: - case VIR_NODE_DEV_CAP_SCSI_TARGET: - case VIR_NODE_DEV_CAP_SCSI: - case VIR_NODE_DEV_CAP_STORAGE: - case VIR_NODE_DEV_CAP_FC_HOST: - case VIR_NODE_DEV_CAP_VPORTS: - case VIR_NODE_DEV_CAP_SCSI_GENERIC: - case VIR_NODE_DEV_CAP_DRM: - case VIR_NODE_DEV_CAP_MDEV_TYPES: - case VIR_NODE_DEV_CAP_MDEV: - case VIR_NODE_DEV_CAP_CCW_DEV: - case VIR_NODE_DEV_CAP_LAST: - break; - } - } - - caps = caps->next; - } - return false; + return virNodeDeviceObjHasCap(obj, virNodeDevCapTypeFromString(cap));
I wonder if we should check for the TypeFromString() conversion rather than pass it to the other function directly.
Well, since the conversion function returns -1 on unknown types and none of our device cap enum types can ever be equal to -1, since that would make it non-deterministic, but I agree that by adding a check explicitly we can save a few cycles, may I assume this to be an ACK with the following squashed in? diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index 2f37c4a05..ccea10793 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -124,7 +124,12 @@ static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap) { - return virNodeDeviceObjHasCap(obj, virNodeDevCapTypeFromString(cap)); + int type; + + if ((type = virNodeDevCapTypeFromString(cap)) < 0) + return false; + + return virNodeDeviceObjHasCap(obj, type); } Erik

On 01/29/2018 09:42 AM, Erik Skultety wrote:
On Fri, Jan 26, 2018 at 12:40:34PM +0100, Michal Privoznik wrote:
On 01/25/2018 10:23 AM, Erik Skultety wrote:
This patch drops the capability matching redundancy by simply converting the string input to our internal types which are then in turn used for the actual capability matching.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/virnodedeviceobj.c | 50 +-------------------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-)
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index ccad59a4b..5360df805 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -128,55 +128,7 @@ static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap) { - virNodeDevCapsDefPtr caps = obj->def->caps; - const char *fc_host_cap = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_FC_HOST); - const char *vports_cap = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_VPORTS); - const char *mdev_types = - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_MDEV_TYPES); - - while (caps) { - if (STREQ(cap, virNodeDevCapTypeToString(caps->data.type))) { - return true; - } else { - switch (caps->data.type) { - case VIR_NODE_DEV_CAP_PCI_DEV: - if ((STREQ(cap, mdev_types)) && - (caps->data.pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV)) - return true; - break; - - case VIR_NODE_DEV_CAP_SCSI_HOST: - if ((STREQ(cap, fc_host_cap) && - (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST)) || - (STREQ(cap, vports_cap) && - (caps->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS))) - return true; - break; - - case VIR_NODE_DEV_CAP_SYSTEM: - case VIR_NODE_DEV_CAP_USB_DEV: - case VIR_NODE_DEV_CAP_USB_INTERFACE: - case VIR_NODE_DEV_CAP_NET: - case VIR_NODE_DEV_CAP_SCSI_TARGET: - case VIR_NODE_DEV_CAP_SCSI: - case VIR_NODE_DEV_CAP_STORAGE: - case VIR_NODE_DEV_CAP_FC_HOST: - case VIR_NODE_DEV_CAP_VPORTS: - case VIR_NODE_DEV_CAP_SCSI_GENERIC: - case VIR_NODE_DEV_CAP_DRM: - case VIR_NODE_DEV_CAP_MDEV_TYPES: - case VIR_NODE_DEV_CAP_MDEV: - case VIR_NODE_DEV_CAP_CCW_DEV: - case VIR_NODE_DEV_CAP_LAST: - break; - } - } - - caps = caps->next; - } - return false; + return virNodeDeviceObjHasCap(obj, virNodeDevCapTypeFromString(cap));
I wonder if we should check for the TypeFromString() conversion rather than pass it to the other function directly.
Well, since the conversion function returns -1 on unknown types and none of our device cap enum types can ever be equal to -1, since that would make it non-deterministic, but I agree that by adding a check explicitly we can save a few cycles, may I assume this to be an ACK with the following squashed in?
diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index 2f37c4a05..ccea10793 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -124,7 +124,12 @@ static bool virNodeDeviceObjHasCapStr(const virNodeDeviceObj *obj, const char *cap) { - return virNodeDeviceObjHasCap(obj, virNodeDevCapTypeFromString(cap)); + int type; + + if ((type = virNodeDevCapTypeFromString(cap)) < 0) + return false; + + return virNodeDeviceObjHasCap(obj, type); }
Yup, looks good to me. Michal

We can call directly the virNodeDeviceGetSCSIHostCaps helper instead. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/node_device_conf.c | 12 ++++++++++++ src/node_device/node_device_driver.c | 2 +- src/node_device/node_device_hal.c | 4 ++-- src/node_device/node_device_linux_sysfs.c | 12 ------------ src/node_device/node_device_linux_sysfs.h | 1 - src/node_device/node_device_udev.c | 2 +- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index bf84fd2b3..70a753ebf 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -2431,6 +2431,8 @@ virNodeDeviceDeleteVport(virConnectPtr conn, } +#ifdef __linux__ + int virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host) { @@ -2511,3 +2513,13 @@ virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host) VIR_FREE(tmp); return ret; } + +#else + +int +virNodeDeviceGetSCSIHostCaps(virNodeDevCap) +{ + return -1; +} + +#endif /* __linux__ */ diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 6216a6977..a2f687942 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -56,7 +56,7 @@ nodeDeviceUpdateCaps(virNodeDeviceDefPtr def) while (cap) { switch (cap->data.type) { case VIR_NODE_DEV_CAP_SCSI_HOST: - nodeDeviceSysfsGetSCSIHostCaps(&cap->data.scsi_host); + virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host); break; case VIR_NODE_DEV_CAP_SCSI_TARGET: nodeDeviceSysfsGetSCSITargetCaps(def->sysfs_path, diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index c19e327c9..4c50f4613 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -151,7 +151,7 @@ gather_pci_cap(LibHalContext *ctx, const char *udi, ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function)); } - if (nodeDeviceSysfsGetPCIRelatedDevCaps(sysfs_path, &d->pci_dev) < 0) { + if (virNodeDeviceGetPCIDynamicCaps(sysfs_path, &d->pci_dev) < 0) { VIR_FREE(sysfs_path); return -1; } @@ -237,7 +237,7 @@ gather_scsi_host_cap(LibHalContext *ctx, const char *udi, (void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host); - retval = nodeDeviceSysfsGetSCSIHostCaps(&d->scsi_host); + retval = virNodeDeviceGetSCSIHostCaps(&d->scsi_host); if (retval == -1) goto out; diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c index 6f438e5f3..b3f80a555 100644 --- a/src/node_device/node_device_linux_sysfs.c +++ b/src/node_device/node_device_linux_sysfs.c @@ -45,12 +45,6 @@ VIR_LOG_INIT("node_device.node_device_linux_sysfs"); -int -nodeDeviceSysfsGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host) -{ - return virNodeDeviceGetSCSIHostCaps(scsi_host); -} - int nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath, @@ -196,12 +190,6 @@ nodeDeviceSysfsGetPCIRelatedDevCaps(const char *sysfsPath, #else -int -nodeDeviceSysfsGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host ATTRIBUTE_UNUSED) -{ - return -1; -} - int nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath ATTRIBUTE_UNUSED, virNodeDevCapSCSITargetPtr scsi_target ATTRIBUTE_UNUSED) { diff --git a/src/node_device/node_device_linux_sysfs.h b/src/node_device/node_device_linux_sysfs.h index 12cfe6341..9392d6934 100644 --- a/src/node_device/node_device_linux_sysfs.h +++ b/src/node_device/node_device_linux_sysfs.h @@ -25,7 +25,6 @@ # include "node_device_conf.h" -int nodeDeviceSysfsGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host); int nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath, virNodeDevCapSCSITargetPtr scsi_target); int nodeDeviceSysfsGetPCIRelatedDevCaps(const char *sysfsPath, diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index e0fca6159..4cc531d2c 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -781,7 +781,7 @@ udevProcessSCSIHost(struct udev_device *device ATTRIBUTE_UNUSED, return -1; } - nodeDeviceSysfsGetSCSIHostCaps(&def->caps->data.scsi_host); + virNodeDeviceGetSCSIHostCaps(&def->caps->data.scsi_host); if (udevGenerateDeviceName(device, def, NULL) != 0) return -1; -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
We can call directly the virNodeDeviceGetSCSIHostCaps helper instead.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/node_device_conf.c | 12 ++++++++++++ src/node_device/node_device_driver.c | 2 +- src/node_device/node_device_hal.c | 4 ++-- src/node_device/node_device_linux_sysfs.c | 12 ------------ src/node_device/node_device_linux_sysfs.h | 1 - src/node_device/node_device_udev.c | 2 +- 6 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index bf84fd2b3..70a753ebf 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -2431,6 +2431,8 @@ virNodeDeviceDeleteVport(virConnectPtr conn, }
+#ifdef __linux__ + int virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host) { @@ -2511,3 +2513,13 @@ virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host) VIR_FREE(tmp); return ret; } + +#else + +int +virNodeDeviceGetSCSIHostCaps(virNodeDevCap)
The linux version of this function takes virNodeDevCapSCSIHostPtr. This non-linux should do so too. Also, you should give the argument a name and mark it as ATTRIBUTE_UNUSED.
+{ + return -1; +} + +#endif /* __linux__ */ diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 6216a6977..a2f687942 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -56,7 +56,7 @@ nodeDeviceUpdateCaps(virNodeDeviceDefPtr def) while (cap) { switch (cap->data.type) { case VIR_NODE_DEV_CAP_SCSI_HOST: - nodeDeviceSysfsGetSCSIHostCaps(&cap->data.scsi_host); + virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host); break; case VIR_NODE_DEV_CAP_SCSI_TARGET: nodeDeviceSysfsGetSCSITargetCaps(def->sysfs_path, diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index c19e327c9..4c50f4613 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -151,7 +151,7 @@ gather_pci_cap(LibHalContext *ctx, const char *udi, ignore_value(virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function)); }
- if (nodeDeviceSysfsGetPCIRelatedDevCaps(sysfs_path, &d->pci_dev) < 0) { + if (virNodeDeviceGetPCIDynamicCaps(sysfs_path, &d->pci_dev) < 0) { VIR_FREE(sysfs_path); return -1;
This doesn't look right. You're not changing PCI function in this patch. ACK to the rest. Michal

The capabilities are defined/parsed/formatted/queried from this module, no reason for 'update' not being part of the module as well. This also involves some module-specific prefix changes. This patch also drops the node_device_linux_sysfs module from the repo since: a) it only contained the capability handlers we just moved b) it's only linked with the driver (by design) and thus unreachable to other modules c) we touch sysfs across all the src/util modules so the module being deleted hasn't been serving its original intention for some time already. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/Makefile.am | 4 +- src/conf/node_device_conf.c | 154 +++++++++++++++++++++- src/conf/node_device_conf.h | 7 + src/libvirt_private.syms | 2 + src/node_device/node_device_driver.c | 7 +- src/node_device/node_device_hal.c | 1 - src/node_device/node_device_linux_sysfs.c | 206 ------------------------------ src/node_device/node_device_linux_sysfs.h | 33 ----- src/node_device/node_device_udev.c | 5 +- 9 files changed, 168 insertions(+), 251 deletions(-) delete mode 100644 src/node_device/node_device_linux_sysfs.c delete mode 100644 src/node_device/node_device_linux_sysfs.h diff --git a/src/Makefile.am b/src/Makefile.am index 166c9a8e9..b8ecd8df8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1168,9 +1168,7 @@ ACCESS_DRIVER_POLKIT_POLICY = \ NODE_DEVICE_DRIVER_SOURCES = \ node_device/node_device_driver.c \ - node_device/node_device_driver.h \ - node_device/node_device_linux_sysfs.c \ - node_device/node_device_linux_sysfs.h + node_device/node_device_driver.h NODE_DEVICE_DRIVER_HAL_SOURCES = \ node_device/node_device_hal.c \ diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 70a753ebf..5b0af559a 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -33,11 +33,13 @@ #include "virstring.h" #include "node_device_conf.h" #include "device_conf.h" +#include "dirname.h" #include "virxml.h" #include "virbuffer.h" #include "viruuid.h" #include "virrandom.h" #include "virlog.h" +#include "virfcp.h" #define VIR_FROM_THIS VIR_FROM_NODEDEV @@ -2514,10 +2516,160 @@ virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host) return ret; } + +int +virNodeDeviceGetSCSITargetCaps(const char *sysfsPath, + virNodeDevCapSCSITargetPtr scsi_target) +{ + int ret = -1; + char *dir = NULL, *rport = NULL; + + VIR_DEBUG("Checking if '%s' is an FC remote port", scsi_target->name); + + /* /sys/devices/[...]/host0/rport-0:0-0/target0:0:0 -> rport-0:0-0 */ + if (!(dir = mdir_name(sysfsPath))) + return -1; + + if (VIR_STRDUP(rport, last_component(dir)) < 0) + goto cleanup; + + if (!virFCIsCapableRport(rport)) + goto cleanup; + + VIR_FREE(scsi_target->rport); + VIR_STEAL_PTR(scsi_target->rport, rport); + + if (virFCReadRportValue(scsi_target->rport, "port_name", + &scsi_target->wwpn) < 0) { + VIR_WARN("Failed to read port_name for '%s'", scsi_target->rport); + goto cleanup; + } + + scsi_target->flags |= VIR_NODE_DEV_CAP_FLAG_FC_RPORT; + ret = 0; + + cleanup: + if (ret < 0) { + VIR_FREE(scsi_target->rport); + VIR_FREE(scsi_target->wwpn); + scsi_target->flags &= ~VIR_NODE_DEV_CAP_FLAG_FC_RPORT; + } + VIR_FREE(rport); + VIR_FREE(dir); + + return ret; +} + + +static int +virNodeDeviceGetPCISRIOVCaps(const char *sysfsPath, + virNodeDevCapPCIDevPtr pci_dev) +{ + size_t i; + int ret; + + /* this could be a refresh, so clear out the old data */ + for (i = 0; i < pci_dev->num_virtual_functions; i++) + VIR_FREE(pci_dev->virtual_functions[i]); + VIR_FREE(pci_dev->virtual_functions); + pci_dev->num_virtual_functions = 0; + pci_dev->max_virtual_functions = 0; + pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; + pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; + + ret = virPCIGetPhysicalFunction(sysfsPath, + &pci_dev->physical_function); + if (ret < 0) + goto cleanup; + + if (pci_dev->physical_function) + pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; + + ret = virPCIGetVirtualFunctions(sysfsPath, &pci_dev->virtual_functions, + &pci_dev->num_virtual_functions, + &pci_dev->max_virtual_functions); + if (ret < 0) + goto cleanup; + + if (pci_dev->num_virtual_functions > 0 || + pci_dev->max_virtual_functions > 0) + pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; + + cleanup: + return ret; +} + + +static int +virNodeDeviceGetPCIIOMMUGroupCaps(virNodeDevCapPCIDevPtr pci_dev) +{ + size_t i; + int tmpGroup, ret = -1; + virPCIDeviceAddress addr; + + /* this could be a refresh, so clear out the old data */ + for (i = 0; i < pci_dev->nIommuGroupDevices; i++) + VIR_FREE(pci_dev->iommuGroupDevices[i]); + VIR_FREE(pci_dev->iommuGroupDevices); + pci_dev->nIommuGroupDevices = 0; + pci_dev->iommuGroupNumber = 0; + + addr.domain = pci_dev->domain; + addr.bus = pci_dev->bus; + addr.slot = pci_dev->slot; + addr.function = pci_dev->function; + tmpGroup = virPCIDeviceAddressGetIOMMUGroupNum(&addr); + if (tmpGroup == -1) { + /* error was already reported */ + goto cleanup; + } + if (tmpGroup == -2) { + /* -2 return means there is no iommu_group data */ + ret = 0; + goto cleanup; + } + if (tmpGroup >= 0) { + if (virPCIDeviceAddressGetIOMMUGroupAddresses(&addr, &pci_dev->iommuGroupDevices, + &pci_dev->nIommuGroupDevices) < 0) + goto cleanup; + pci_dev->iommuGroupNumber = tmpGroup; + } + + ret = 0; + cleanup: + return ret; +} + + +/* virNodeDeviceGetPCIDynamicCaps() get info that is stored in sysfs + * about devices related to this device, i.e. things that can change + * without this device itself changing. These must be refreshed + * anytime full XML of the device is requested, because they can + * change with no corresponding notification from the kernel/udev. + */ +int +virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, + virNodeDevCapPCIDevPtr pci_dev) +{ + if (virNodeDeviceGetPCISRIOVCaps(sysfsPath, pci_dev) < 0) + return -1; + if (virNodeDeviceGetPCIIOMMUGroupCaps(pci_dev) < 0) + return -1; + return 0; +} + #else int -virNodeDeviceGetSCSIHostCaps(virNodeDevCap) +virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, + virNodeDevCapPCIDevPtr pci_dev) +{ + return -1; +} + + +int virNodeDeviceGetSCSITargetCaps(const char *sysfsPath ATTRIBUTE_UNUSED, + virNodeDevCapSCSITargetPtr scsi_target ATTRIBUTE_UNUSED) { return -1; } diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index cf79773aa..4e3154875 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -393,4 +393,11 @@ virNodeDeviceDeleteVport(virConnectPtr conn, int virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host); +int +virNodeDeviceGetSCSITargetCaps(const char *sysfsPath, + virNodeDevCapSCSITargetPtr scsi_target); + +int +virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, + virNodeDevCapPCIDevPtr pci_dev); #endif /* __VIR_NODE_DEVICE_CONF_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index bc8cc1fba..0cd8086a6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -707,7 +707,9 @@ virNodeDeviceDefParseNode; virNodeDeviceDefParseString; virNodeDeviceDeleteVport; virNodeDeviceGetParentName; +virNodeDeviceGetPCIDynamicCaps; virNodeDeviceGetSCSIHostCaps; +virNodeDeviceGetSCSITargetCaps; virNodeDeviceGetWWNs; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index a2f687942..2e42d3527 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -38,7 +38,6 @@ #include "node_device_event.h" #include "node_device_driver.h" #include "node_device_hal.h" -#include "node_device_linux_sysfs.h" #include "virvhba.h" #include "viraccessapicheck.h" #include "virnetdev.h" @@ -59,7 +58,7 @@ nodeDeviceUpdateCaps(virNodeDeviceDefPtr def) virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host); break; case VIR_NODE_DEV_CAP_SCSI_TARGET: - nodeDeviceSysfsGetSCSITargetCaps(def->sysfs_path, + virNodeDeviceGetSCSITargetCaps(def->sysfs_path, &cap->data.scsi_target); break; case VIR_NODE_DEV_CAP_NET: @@ -70,8 +69,8 @@ nodeDeviceUpdateCaps(virNodeDeviceDefPtr def) return -1; break; case VIR_NODE_DEV_CAP_PCI_DEV: - if (nodeDeviceSysfsGetPCIRelatedDevCaps(def->sysfs_path, - &cap->data.pci_dev) < 0) + if (virNodeDeviceGetPCIDynamicCaps(def->sysfs_path, + &cap->data.pci_dev) < 0) return -1; break; diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 4c50f4613..f98fd0856 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -31,7 +31,6 @@ #include "node_device_conf.h" #include "node_device_driver.h" #include "node_device_hal.h" -#include "node_device_linux_sysfs.h" #include "virerror.h" #include "driver.h" #include "datatypes.h" diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c deleted file mode 100644 index b3f80a555..000000000 --- a/src/node_device/node_device_linux_sysfs.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * node_device_linux_sysfs.c: Linux specific code to gather device data - * that is available from sysfs (but not from UDEV or HAL). - * - * Copyright (C) 2009-2015 Red Hat, Inc. - * - * 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/>. - * - */ - -#include <config.h> - -#include <fcntl.h> -#include <sys/stat.h> -#include <stdlib.h> - -#include "dirname.h" -#include "node_device_driver.h" -#include "node_device_hal.h" -#include "node_device_linux_sysfs.h" -#include "virerror.h" -#include "viralloc.h" -#include "virfcp.h" -#include "virlog.h" -#include "virfile.h" -#include "virscsihost.h" -#include "virstring.h" -#include "virvhba.h" - -#define VIR_FROM_THIS VIR_FROM_NODEDEV - -#ifdef __linux__ - -VIR_LOG_INIT("node_device.node_device_linux_sysfs"); - - -int -nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath, - virNodeDevCapSCSITargetPtr scsi_target) -{ - int ret = -1; - char *dir = NULL, *rport = NULL; - - VIR_DEBUG("Checking if '%s' is an FC remote port", scsi_target->name); - - /* /sys/devices/[...]/host0/rport-0:0-0/target0:0:0 -> rport-0:0-0 */ - if (!(dir = mdir_name(sysfsPath))) - return -1; - - if (VIR_STRDUP(rport, last_component(dir)) < 0) - goto cleanup; - - if (!virFCIsCapableRport(rport)) - goto cleanup; - - VIR_FREE(scsi_target->rport); - VIR_STEAL_PTR(scsi_target->rport, rport); - - if (virFCReadRportValue(scsi_target->rport, "port_name", - &scsi_target->wwpn) < 0) { - VIR_WARN("Failed to read port_name for '%s'", scsi_target->rport); - goto cleanup; - } - - scsi_target->flags |= VIR_NODE_DEV_CAP_FLAG_FC_RPORT; - ret = 0; - - cleanup: - if (ret < 0) { - VIR_FREE(scsi_target->rport); - VIR_FREE(scsi_target->wwpn); - scsi_target->flags &= ~VIR_NODE_DEV_CAP_FLAG_FC_RPORT; - } - VIR_FREE(rport); - VIR_FREE(dir); - - return ret; -} - - -static int -nodeDeviceSysfsGetPCISRIOVCaps(const char *sysfsPath, - virNodeDevCapPCIDevPtr pci_dev) -{ - size_t i; - int ret; - - /* this could be a refresh, so clear out the old data */ - for (i = 0; i < pci_dev->num_virtual_functions; i++) - VIR_FREE(pci_dev->virtual_functions[i]); - VIR_FREE(pci_dev->virtual_functions); - pci_dev->num_virtual_functions = 0; - pci_dev->max_virtual_functions = 0; - pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; - pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; - - ret = virPCIGetPhysicalFunction(sysfsPath, - &pci_dev->physical_function); - if (ret < 0) - goto cleanup; - - if (pci_dev->physical_function) - pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; - - ret = virPCIGetVirtualFunctions(sysfsPath, &pci_dev->virtual_functions, - &pci_dev->num_virtual_functions, - &pci_dev->max_virtual_functions); - if (ret < 0) - goto cleanup; - - if (pci_dev->num_virtual_functions > 0 || - pci_dev->max_virtual_functions > 0) - pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; - - cleanup: - return ret; -} - - -static int -nodeDeviceSysfsGetPCIIOMMUGroupCaps(virNodeDevCapPCIDevPtr pci_dev) -{ - size_t i; - int tmpGroup, ret = -1; - virPCIDeviceAddress addr; - - /* this could be a refresh, so clear out the old data */ - for (i = 0; i < pci_dev->nIommuGroupDevices; i++) - VIR_FREE(pci_dev->iommuGroupDevices[i]); - VIR_FREE(pci_dev->iommuGroupDevices); - pci_dev->nIommuGroupDevices = 0; - pci_dev->iommuGroupNumber = 0; - - addr.domain = pci_dev->domain; - addr.bus = pci_dev->bus; - addr.slot = pci_dev->slot; - addr.function = pci_dev->function; - tmpGroup = virPCIDeviceAddressGetIOMMUGroupNum(&addr); - if (tmpGroup == -1) { - /* error was already reported */ - goto cleanup; - } - if (tmpGroup == -2) { - /* -2 return means there is no iommu_group data */ - ret = 0; - goto cleanup; - } - if (tmpGroup >= 0) { - if (virPCIDeviceAddressGetIOMMUGroupAddresses(&addr, &pci_dev->iommuGroupDevices, - &pci_dev->nIommuGroupDevices) < 0) - goto cleanup; - pci_dev->iommuGroupNumber = tmpGroup; - } - - ret = 0; - cleanup: - return ret; -} - - -/* nodeDeviceSysfsGetPCIRelatedCaps() get info that is stored in sysfs - * about devices related to this device, i.e. things that can change - * without this device itself changing. These must be refreshed - * anytime full XML of the device is requested, because they can - * change with no corresponding notification from the kernel/udev. - */ -int -nodeDeviceSysfsGetPCIRelatedDevCaps(const char *sysfsPath, - virNodeDevCapPCIDevPtr pci_dev) -{ - if (nodeDeviceSysfsGetPCISRIOVCaps(sysfsPath, pci_dev) < 0) - return -1; - if (nodeDeviceSysfsGetPCIIOMMUGroupCaps(pci_dev) < 0) - return -1; - return 0; -} - - -#else - -int nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath ATTRIBUTE_UNUSED, - virNodeDevCapSCSITargetPtr scsi_target ATTRIBUTE_UNUSED) -{ - return -1; -} - -int -nodeDeviceSysfsGetPCIRelatedDevCaps(const char *sysfsPath ATTRIBUTE_UNUSED, - virNodeDevCapPCIDevPtr pci_dev ATTRIBUTE_UNUSED) -{ - return -1; -} - -#endif /* __linux__ */ diff --git a/src/node_device/node_device_linux_sysfs.h b/src/node_device/node_device_linux_sysfs.h deleted file mode 100644 index 9392d6934..000000000 --- a/src/node_device/node_device_linux_sysfs.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * node_device_linux_sysfs.h: Linux specific code to gather device data - * that is available from sysfs (but not from UDEV or HAL). - * - * Copyright (C) 2015 Red Hat, Inc. - * - * 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/>. - * - */ - -#ifndef __VIR_NODE_DEVICE_LINUX_SYSFS_H__ -# define __VIR_NODE_DEVICE_LINUX_SYSFS_H__ - -# include "node_device_conf.h" - -int nodeDeviceSysfsGetSCSITargetCaps(const char *sysfsPath, - virNodeDevCapSCSITargetPtr scsi_target); -int nodeDeviceSysfsGetPCIRelatedDevCaps(const char *sysfsPath, - virNodeDevCapPCIDevPtr pci_dev); - -#endif /* __VIR_NODE_DEVICE_LINUX_SYSFS_H__ */ diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 4cc531d2c..519b0bf6f 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -30,7 +30,6 @@ #include "node_device_conf.h" #include "node_device_event.h" #include "node_device_driver.h" -#include "node_device_linux_sysfs.h" #include "node_device_udev.h" #include "virerror.h" #include "driver.h" @@ -558,7 +557,7 @@ udevProcessPCI(struct udev_device *device, &pci_dev->numa_node, 10) < 0) goto cleanup; - if (nodeDeviceSysfsGetPCIRelatedDevCaps(def->sysfs_path, pci_dev) < 0) + if (virNodeDeviceGetPCIDynamicCaps(def->sysfs_path, pci_dev) < 0) goto cleanup; if (!(pciDev = virPCIDeviceNew(pci_dev->domain, @@ -802,7 +801,7 @@ udevProcessSCSITarget(struct udev_device *device, if (VIR_STRDUP(scsi_target->name, sysname) < 0) return -1; - nodeDeviceSysfsGetSCSITargetCaps(def->sysfs_path, &def->caps->data.scsi_target); + virNodeDeviceGetSCSITargetCaps(def->sysfs_path, &def->caps->data.scsi_target); if (udevGenerateDeviceName(device, def, NULL) != 0) return -1; -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
The capabilities are defined/parsed/formatted/queried from this module, no reason for 'update' not being part of the module as well. This also involves some module-specific prefix changes. This patch also drops the node_device_linux_sysfs module from the repo since: a) it only contained the capability handlers we just moved b) it's only linked with the driver (by design) and thus unreachable to other modules c) we touch sysfs across all the src/util modules so the module being deleted hasn't been serving its original intention for some time already.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/Makefile.am | 4 +- src/conf/node_device_conf.c | 154 +++++++++++++++++++++- src/conf/node_device_conf.h | 7 + src/libvirt_private.syms | 2 + src/node_device/node_device_driver.c | 7 +- src/node_device/node_device_hal.c | 1 - src/node_device/node_device_linux_sysfs.c | 206 ------------------------------ src/node_device/node_device_linux_sysfs.h | 33 ----- src/node_device/node_device_udev.c | 5 +- 9 files changed, 168 insertions(+), 251 deletions(-) delete mode 100644 src/node_device/node_device_linux_sysfs.c delete mode 100644 src/node_device/node_device_linux_sysfs.h
diff --git a/src/Makefile.am b/src/Makefile.am index 166c9a8e9..b8ecd8df8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1168,9 +1168,7 @@ ACCESS_DRIVER_POLKIT_POLICY = \
NODE_DEVICE_DRIVER_SOURCES = \ node_device/node_device_driver.c \ - node_device/node_device_driver.h \ - node_device/node_device_linux_sysfs.c \ - node_device/node_device_linux_sysfs.h + node_device/node_device_driver.h
NODE_DEVICE_DRIVER_HAL_SOURCES = \ node_device/node_device_hal.c \ diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 70a753ebf..5b0af559a 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c
int -virNodeDeviceGetSCSIHostCaps(virNodeDevCap) +virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, + virNodeDevCapPCIDevPtr pci_dev) +{
ATTRIBUTE_UNUSED to both. Also, it seems interesting that for rename of SCSI version of the function you have a separate patch but for PCI you do it in one run. I share your feelings towards PCI, SCSI is so much better bus and thus deserves its own patch :-)
+ return -1; +} + + +int virNodeDeviceGetSCSITargetCaps(const char *sysfsPath ATTRIBUTE_UNUSED, + virNodeDevCapSCSITargetPtr scsi_target ATTRIBUTE_UNUSED) { return -1; } diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index cf79773aa..4e3154875 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -393,4 +393,11 @@ virNodeDeviceDeleteVport(virConnectPtr conn, int virNodeDeviceGetSCSIHostCaps(virNodeDevCapSCSIHostPtr scsi_host);
+int +virNodeDeviceGetSCSITargetCaps(const char *sysfsPath, + virNodeDevCapSCSITargetPtr scsi_target); + +int +virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, + virNodeDevCapPCIDevPtr pci_dev); #endif /* __VIR_NODE_DEVICE_CONF_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index bc8cc1fba..0cd8086a6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -707,7 +707,9 @@ virNodeDeviceDefParseNode; virNodeDeviceDefParseString; virNodeDeviceDeleteVport; virNodeDeviceGetParentName; +virNodeDeviceGetPCIDynamicCaps; virNodeDeviceGetSCSIHostCaps; +virNodeDeviceGetSCSITargetCaps; virNodeDeviceGetWWNs;
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index a2f687942..2e42d3527 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -38,7 +38,6 @@ #include "node_device_event.h" #include "node_device_driver.h" #include "node_device_hal.h" -#include "node_device_linux_sysfs.h" #include "virvhba.h" #include "viraccessapicheck.h" #include "virnetdev.h" @@ -59,7 +58,7 @@ nodeDeviceUpdateCaps(virNodeDeviceDefPtr def) virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host); break; case VIR_NODE_DEV_CAP_SCSI_TARGET: - nodeDeviceSysfsGetSCSITargetCaps(def->sysfs_path, + virNodeDeviceGetSCSITargetCaps(def->sysfs_path, &cap->data.scsi_target); break; case VIR_NODE_DEV_CAP_NET: @@ -70,8 +69,8 @@ nodeDeviceUpdateCaps(virNodeDeviceDefPtr def) return -1; break; case VIR_NODE_DEV_CAP_PCI_DEV: - if (nodeDeviceSysfsGetPCIRelatedDevCaps(def->sysfs_path, - &cap->data.pci_dev) < 0) + if (virNodeDeviceGetPCIDynamicCaps(def->sysfs_path, + &cap->data.pci_dev) < 0) return -1; break;
diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 4c50f4613..f98fd0856 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -31,7 +31,6 @@ #include "node_device_conf.h" #include "node_device_driver.h" #include "node_device_hal.h" -#include "node_device_linux_sysfs.h" #include "virerror.h" #include "driver.h" #include "datatypes.h"
Ah, this is the place for the hunk I'm mentioning in the previous patch. ACK if you fix it. Michal

Since we moved the helpers from nodedev driver to src/conf, the actual 'update' function using those helpers should be moved as well so that we don't need to call back into the driver. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/node_device_conf.c | 54 ++++++++++++++++++++++++++++++++++++ src/conf/node_device_conf.h | 3 ++ src/libvirt_private.syms | 1 + src/node_device/node_device_driver.c | 54 +----------------------------------- 4 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 5b0af559a..217673a56 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -2433,6 +2433,60 @@ virNodeDeviceDeleteVport(virConnectPtr conn, } +int +virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def) +{ + virNodeDevCapsDefPtr cap = def->caps; + + while (cap) { + switch (cap->data.type) { + case VIR_NODE_DEV_CAP_SCSI_HOST: + virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host); + break; + case VIR_NODE_DEV_CAP_SCSI_TARGET: + virNodeDeviceGetSCSITargetCaps(def->sysfs_path, + &cap->data.scsi_target); + break; + case VIR_NODE_DEV_CAP_NET: + if (virNetDevGetLinkInfo(cap->data.net.ifname, + &cap->data.net.lnk) < 0) + return -1; + virBitmapFree(cap->data.net.features); + if (virNetDevGetFeatures(cap->data.net.ifname, + &cap->data.net.features) < 0) + return -1; + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + if (virNodeDeviceGetPCIDynamicCaps(def->sysfs_path, + &cap->data.pci_dev) < 0) + return -1; + break; + + /* all types that (supposedly) don't require any updates + * relative to what's in the cache. + */ + case VIR_NODE_DEV_CAP_DRM: + case VIR_NODE_DEV_CAP_SYSTEM: + case VIR_NODE_DEV_CAP_USB_DEV: + case VIR_NODE_DEV_CAP_USB_INTERFACE: + case VIR_NODE_DEV_CAP_SCSI: + case VIR_NODE_DEV_CAP_STORAGE: + case VIR_NODE_DEV_CAP_FC_HOST: + case VIR_NODE_DEV_CAP_VPORTS: + case VIR_NODE_DEV_CAP_SCSI_GENERIC: + case VIR_NODE_DEV_CAP_MDEV_TYPES: + case VIR_NODE_DEV_CAP_MDEV: + case VIR_NODE_DEV_CAP_CCW_DEV: + case VIR_NODE_DEV_CAP_LAST: + break; + } + cap = cap->next; + } + + return 0; +} + + #ifdef __linux__ int diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 4e3154875..7e32f5c05 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -400,4 +400,7 @@ virNodeDeviceGetSCSITargetCaps(const char *sysfsPath, int virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, virNodeDevCapPCIDevPtr pci_dev); + +int +virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def); #endif /* __VIR_NODE_DEVICE_CONF_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0cd8086a6..6098cf121 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -711,6 +711,7 @@ virNodeDeviceGetPCIDynamicCaps; virNodeDeviceGetSCSIHostCaps; virNodeDeviceGetSCSITargetCaps; virNodeDeviceGetWWNs; +virNodeDeviceUpdateCaps; # conf/node_device_event.h diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 2e42d3527..48f45474c 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -47,58 +47,6 @@ virNodeDeviceDriverStatePtr driver; -static int -nodeDeviceUpdateCaps(virNodeDeviceDefPtr def) -{ - virNodeDevCapsDefPtr cap = def->caps; - - while (cap) { - switch (cap->data.type) { - case VIR_NODE_DEV_CAP_SCSI_HOST: - virNodeDeviceGetSCSIHostCaps(&cap->data.scsi_host); - break; - case VIR_NODE_DEV_CAP_SCSI_TARGET: - virNodeDeviceGetSCSITargetCaps(def->sysfs_path, - &cap->data.scsi_target); - break; - case VIR_NODE_DEV_CAP_NET: - if (virNetDevGetLinkInfo(cap->data.net.ifname, &cap->data.net.lnk) < 0) - return -1; - virBitmapFree(cap->data.net.features); - if (virNetDevGetFeatures(cap->data.net.ifname, &cap->data.net.features) < 0) - return -1; - break; - case VIR_NODE_DEV_CAP_PCI_DEV: - if (virNodeDeviceGetPCIDynamicCaps(def->sysfs_path, - &cap->data.pci_dev) < 0) - return -1; - break; - - /* all types that (supposedly) don't require any updates - * relative to what's in the cache. - */ - case VIR_NODE_DEV_CAP_DRM: - case VIR_NODE_DEV_CAP_SYSTEM: - case VIR_NODE_DEV_CAP_USB_DEV: - case VIR_NODE_DEV_CAP_USB_INTERFACE: - case VIR_NODE_DEV_CAP_SCSI: - case VIR_NODE_DEV_CAP_STORAGE: - case VIR_NODE_DEV_CAP_FC_HOST: - case VIR_NODE_DEV_CAP_VPORTS: - case VIR_NODE_DEV_CAP_SCSI_GENERIC: - case VIR_NODE_DEV_CAP_MDEV_TYPES: - case VIR_NODE_DEV_CAP_MDEV: - case VIR_NODE_DEV_CAP_CCW_DEV: - case VIR_NODE_DEV_CAP_LAST: - break; - } - cap = cap->next; - } - - return 0; -} - - #if defined (__linux__) && ( defined (WITH_HAL) || defined(WITH_UDEV)) /* NB: It was previously believed that changes in driver name were * relayed to libvirt as "change" events by udev, and the udev event @@ -314,7 +262,7 @@ nodeDeviceGetXMLDesc(virNodeDevicePtr device, if (nodeDeviceUpdateDriverName(def) < 0) goto cleanup; - if (nodeDeviceUpdateCaps(def) < 0) + if (virNodeDeviceUpdateCaps(def) < 0) goto cleanup; ret = virNodeDeviceDefFormat(def); -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
Since we moved the helpers from nodedev driver to src/conf, the actual 'update' function using those helpers should be moved as well so that we don't need to call back into the driver.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/node_device_conf.c | 54 ++++++++++++++++++++++++++++++++++++ src/conf/node_device_conf.h | 3 ++ src/libvirt_private.syms | 1 + src/node_device/node_device_driver.c | 54 +----------------------------------- 4 files changed, 59 insertions(+), 53 deletions(-)
ACK Michal

Whether asking for a number of capabilities supported by a device or listing them, it's handled essentially by a copy-paste code, so extract the common stuff into this new helper which also updates all capabilities just before touching them. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/node_device_conf.c | 73 +++++++++++++++++++++++++++++++++++ src/conf/node_device_conf.h | 5 +++ src/libvirt_private.syms | 1 + src/node_device/node_device_driver.c | 75 +++++++++--------------------------- 4 files changed, 97 insertions(+), 57 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 217673a56..9467bb415 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -2487,6 +2487,79 @@ virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def) } +/** + * virNodeDeviceCapsListExport: + * @def: node device definition + * @list: pointer to an array to store all supported capabilities by a device + * + * Takes the definition, scans through all the capabilities that the device + * supports (including the nested caps) and populates a newly allocated list + * with them. Caller is responsible for freeing the list. + * If NULL is passed to @list, only the number of caps will be returned. + * + * Returns the number of capabilities the device supports, -1 on error. + */ +int +virNodeDeviceCapsListExport(virNodeDeviceDefPtr def, + virNodeDevCapType **list) +{ + virNodeDevCapsDefPtr caps = NULL; + virNodeDevCapType *tmp = NULL; + bool want_list = !!list; + int ncaps = 0; + int ret = -1; + +#define MAYBE_ADD_CAP(cap) \ + do { \ + if (want_list) \ + tmp[ncaps] = cap; \ + } while (0) + + if (want_list && VIR_ALLOC_N(tmp, VIR_NODE_DEV_CAP_LAST - 1) < 0) + goto cleanup; + + for (caps = def->caps; caps; caps = caps->next) { + unsigned int flags; + + MAYBE_ADD_CAP(caps->data.type); + ncaps++; + + /* check nested caps for a given type as well */ + if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) { + flags = caps->data.scsi_host.flags; + + if (flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) { + MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_FC_HOST); + ncaps++; + } + + if (flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) { + MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_VPORTS); + ncaps++; + } + } + + if (caps->data.type == VIR_NODE_DEV_CAP_PCI_DEV) { + flags = caps->data.pci_dev.flags; + + if (flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) { + MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_MDEV_TYPES); + ncaps++; + } + } + } + +#undef MAYBE_ADD_CAP + + if (want_list) + VIR_STEAL_PTR(*list, tmp); + ret = ncaps; + cleanup: + VIR_FREE(tmp); + return ret; +} + + #ifdef __linux__ int diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 7e32f5c05..53cdfdb01 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -403,4 +403,9 @@ virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, int virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def); + +int +virNodeDeviceCapsListExport(virNodeDeviceDefPtr def, + virNodeDevCapType **list); + #endif /* __VIR_NODE_DEVICE_CONF_H__ */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6098cf121..1698e6227 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -699,6 +699,7 @@ virNodeDevCapMdevTypeFree; virNodeDevCapsDefFree; virNodeDevCapTypeFromString; virNodeDevCapTypeToString; +virNodeDeviceCapsListExport; virNodeDeviceCreateVport; virNodeDeviceDefFormat; virNodeDeviceDefFree; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 48f45474c..8fb08742b 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -306,8 +306,6 @@ nodeDeviceNumOfCaps(virNodeDevicePtr device) { virNodeDeviceObjPtr obj; virNodeDeviceDefPtr def; - virNodeDevCapsDefPtr caps; - int ncaps = 0; int ret = -1; if (!(obj = nodeDeviceObjFindByName(device->name))) @@ -317,27 +315,7 @@ nodeDeviceNumOfCaps(virNodeDevicePtr device) if (virNodeDeviceNumOfCapsEnsureACL(device->conn, def) < 0) goto cleanup; - for (caps = def->caps; caps; caps = caps->next) { - ++ncaps; - - if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) { - if (caps->data.scsi_host.flags & - VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) - ncaps++; - - if (caps->data.scsi_host.flags & - VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) - ncaps++; - } - if (caps->data.type == VIR_NODE_DEV_CAP_PCI_DEV) { - if (caps->data.pci_dev.flags & - VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) - ncaps++; - } - - } - - ret = ncaps; + ret = virNodeDeviceCapsListExport(def, NULL); cleanup: virNodeDeviceObjEndAPI(&obj); @@ -353,9 +331,10 @@ nodeDeviceListCaps(virNodeDevicePtr device, { virNodeDeviceObjPtr obj; virNodeDeviceDefPtr def; - virNodeDevCapsDefPtr caps; + virNodeDevCapType *list = NULL; int ncaps = 0; int ret = -1; + size_t i; if (!(obj = nodeDeviceObjFindByName(device->name))) return -1; @@ -364,46 +343,28 @@ nodeDeviceListCaps(virNodeDevicePtr device, if (virNodeDeviceListCapsEnsureACL(device->conn, def) < 0) goto cleanup; - for (caps = def->caps; caps && ncaps < maxnames; caps = caps->next) { - if (VIR_STRDUP(names[ncaps++], virNodeDevCapTypeToString(caps->data.type)) < 0) + if ((ncaps = virNodeDeviceCapsListExport(def, &list)) < 0) + goto cleanup; + + if (ncaps > maxnames) + ncaps = maxnames; + + for (i = 0; i < ncaps; i++) { + if (VIR_STRDUP(names[i], virNodeDevCapTypeToString(list[i])) < 0) goto cleanup; - - if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) { - if (ncaps < maxnames && - caps->data.scsi_host.flags & - VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) { - if (VIR_STRDUP(names[ncaps++], - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_FC_HOST)) < 0) - goto cleanup; - } - - if (ncaps < maxnames && - caps->data.scsi_host.flags & - VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) { - if (VIR_STRDUP(names[ncaps++], - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_VPORTS)) < 0) - goto cleanup; - } - } - if (caps->data.type == VIR_NODE_DEV_CAP_PCI_DEV) { - if (ncaps < maxnames && - caps->data.pci_dev.flags & - VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) { - if (VIR_STRDUP(names[ncaps++], - virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_MDEV_TYPES)) < 0) - goto cleanup; - } - } } + ret = ncaps; cleanup: virNodeDeviceObjEndAPI(&obj); - if (ret == -1) { - --ncaps; - while (--ncaps >= 0) - VIR_FREE(names[ncaps]); + if (ret < 0) { + size_t j; + for (j = 0; j < i; j++) + VIR_FREE(names[j]); } + + VIR_FREE(list); return ret; } -- 2.13.6

> -----Original Message----- > From: libvir-list-bounces@redhat.com [mailto:libvir-list- > bounces@redhat.com] On Behalf Of Erik Skultety > Sent: Thursday, January 25, 2018 5:24 PM > To: libvir-list@redhat.com > Cc: Erik Skultety <eskultet@redhat.com> > Subject: [libvirt] [PATCH 07/15] nodedev: Introduce > virNodeDeviceCapsListExport > > Whether asking for a number of capabilities supported by a device or > listing them, it's handled essentially by a copy-paste code, so extract > the common stuff into this new helper which also updates all capabilities > just before touching them. > > Signed-off-by: Erik Skultety <eskultet@redhat.com> > --- > src/conf/node_device_conf.c | 73 > +++++++++++++++++++++++++++++++++++ > src/conf/node_device_conf.h | 5 +++ > src/libvirt_private.syms | 1 + > src/node_device/node_device_driver.c | 75 +++++++++---------------------- > ----- > 4 files changed, 97 insertions(+), 57 deletions(-) > > diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c > index 217673a56..9467bb415 100644 > --- a/src/conf/node_device_conf.c > +++ b/src/conf/node_device_conf.c > @@ -2487,6 +2487,79 @@ virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def) } > > > +/** > + * virNodeDeviceCapsListExport: > + * @def: node device definition > + * @list: pointer to an array to store all supported capabilities by a > +device > + * > + * Takes the definition, scans through all the capabilities that the > +device > + * supports (including the nested caps) and populates a newly allocated > +list > + * with them. Caller is responsible for freeing the list. > + * If NULL is passed to @list, only the number of caps will be returned. > + * > + * Returns the number of capabilities the device supports, -1 on error. > + */ > +int > +virNodeDeviceCapsListExport(virNodeDeviceDefPtr def, > + virNodeDevCapType **list) { > + virNodeDevCapsDefPtr caps = NULL; > + virNodeDevCapType *tmp = NULL; > + bool want_list = !!list; > + int ncaps = 0; > + int ret = -1; > + > +#define MAYBE_ADD_CAP(cap) \ > + do { \ > + if (want_list) \ > + tmp[ncaps] = cap; \ > + } while (0) > + > + if (want_list && VIR_ALLOC_N(tmp, VIR_NODE_DEV_CAP_LAST - 1) < 0) > + goto cleanup; > + > + for (caps = def->caps; caps; caps = caps->next) { > + unsigned int flags; > + > + MAYBE_ADD_CAP(caps->data.type); > + ncaps++; > + > + /* check nested caps for a given type as well */ > + if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) { > + flags = caps->data.scsi_host.flags; > + > + if (flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) { > + MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_FC_HOST); > + ncaps++; > + } > + > + if (flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) { > + MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_VPORTS); > + ncaps++; > + } > + } > + > + if (caps->data.type == VIR_NODE_DEV_CAP_PCI_DEV) { > + flags = caps->data.pci_dev.flags; > + > + if (flags & VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) { > + MAYBE_ADD_CAP(VIR_NODE_DEV_CAP_MDEV_TYPES); > + ncaps++; > + } > + } > + } > + > +#undef MAYBE_ADD_CAP > + > + if (want_list) > + VIR_STEAL_PTR(*list, tmp); > + ret = ncaps; > + cleanup: > + VIR_FREE(tmp); > + return ret; > +} > + > + > #ifdef __linux__ > > int > diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h > index 7e32f5c05..53cdfdb01 100644 > --- a/src/conf/node_device_conf.h > +++ b/src/conf/node_device_conf.h > @@ -403,4 +403,9 @@ virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, > > int > virNodeDeviceUpdateCaps(virNodeDeviceDefPtr def); > + > +int > +virNodeDeviceCapsListExport(virNodeDeviceDefPtr def, > + virNodeDevCapType **list); > + > #endif /* __VIR_NODE_DEVICE_CONF_H__ */ diff --git > a/src/libvirt_private.syms b/src/libvirt_private.syms index > 6098cf121..1698e6227 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -699,6 +699,7 @@ virNodeDevCapMdevTypeFree; virNodeDevCapsDefFree; > virNodeDevCapTypeFromString; virNodeDevCapTypeToString; > +virNodeDeviceCapsListExport; > virNodeDeviceCreateVport; > virNodeDeviceDefFormat; > virNodeDeviceDefFree; > diff --git a/src/node_device/node_device_driver.c > b/src/node_device/node_device_driver.c > index 48f45474c..8fb08742b 100644 > --- a/src/node_device/node_device_driver.c > +++ b/src/node_device/node_device_driver.c > @@ -306,8 +306,6 @@ nodeDeviceNumOfCaps(virNodeDevicePtr device) { > virNodeDeviceObjPtr obj; > virNodeDeviceDefPtr def; > - virNodeDevCapsDefPtr caps; > - int ncaps = 0; > int ret = -1; > > if (!(obj = nodeDeviceObjFindByName(device->name))) > @@ -317,27 +315,7 @@ nodeDeviceNumOfCaps(virNodeDevicePtr device) > if (virNodeDeviceNumOfCapsEnsureACL(device->conn, def) < 0) > goto cleanup; > > - for (caps = def->caps; caps; caps = caps->next) { > - ++ncaps; > - > - if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) { > - if (caps->data.scsi_host.flags & > - VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) > - ncaps++; > - > - if (caps->data.scsi_host.flags & > - VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) > - ncaps++; > - } > - if (caps->data.type == VIR_NODE_DEV_CAP_PCI_DEV) { > - if (caps->data.pci_dev.flags & > - VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) > - ncaps++; > - } > - > - } > - > - ret = ncaps; > + ret = virNodeDeviceCapsListExport(def, NULL); > > cleanup: > virNodeDeviceObjEndAPI(&obj); > @@ -353,9 +331,10 @@ nodeDeviceListCaps(virNodeDevicePtr device, { > virNodeDeviceObjPtr obj; > virNodeDeviceDefPtr def; > - virNodeDevCapsDefPtr caps; > + virNodeDevCapType *list = NULL; > int ncaps = 0; > int ret = -1; > + size_t i; variable i should be initialized. Or the act is uncertain when cleanup. Except this, this series of patches work well for me. > > if (!(obj = nodeDeviceObjFindByName(device->name))) > return -1; > @@ -364,46 +343,28 @@ nodeDeviceListCaps(virNodeDevicePtr device, > if (virNodeDeviceListCapsEnsureACL(device->conn, def) < 0) > goto cleanup; > > - for (caps = def->caps; caps && ncaps < maxnames; caps = caps->next) { > - if (VIR_STRDUP(names[ncaps++], virNodeDevCapTypeToString(caps- > >data.type)) < 0) > + if ((ncaps = virNodeDeviceCapsListExport(def, &list)) < 0) > + goto cleanup; > + > + if (ncaps > maxnames) > + ncaps = maxnames; > + > + for (i = 0; i < ncaps; i++) { > + if (VIR_STRDUP(names[i], virNodeDevCapTypeToString(list[i])) < > + 0) > goto cleanup; > - > - if (caps->data.type == VIR_NODE_DEV_CAP_SCSI_HOST) { > - if (ncaps < maxnames && > - caps->data.scsi_host.flags & > - VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) { > - if (VIR_STRDUP(names[ncaps++], > - > virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_FC_HOST)) < 0) > - goto cleanup; > - } > - > - if (ncaps < maxnames && > - caps->data.scsi_host.flags & > - VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) { > - if (VIR_STRDUP(names[ncaps++], > - > virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_VPORTS)) < 0) > - goto cleanup; > - } > - } > - if (caps->data.type == VIR_NODE_DEV_CAP_PCI_DEV) { > - if (ncaps < maxnames && > - caps->data.pci_dev.flags & > - VIR_NODE_DEV_CAP_FLAG_PCI_MDEV) { > - if (VIR_STRDUP(names[ncaps++], > - > virNodeDevCapTypeToString(VIR_NODE_DEV_CAP_MDEV_TYPES)) < 0) > - goto cleanup; > - } > - } > } > + > ret = ncaps; > > cleanup: > virNodeDeviceObjEndAPI(&obj); > - if (ret == -1) { > - --ncaps; > - while (--ncaps >= 0) > - VIR_FREE(names[ncaps]); > + if (ret < 0) { > + size_t j; > + for (j = 0; j < i; j++) > + VIR_FREE(names[j]); > } > + > + VIR_FREE(list); > return ret; > } > > -- > 2.13.6 > > -- > libvir-list mailing list > libvir-list@redhat.com > https://www.redhat.com/mailman/listinfo/libvir-list

On 01/25/2018 10:23 AM, Erik Skultety wrote:
Whether asking for a number of capabilities supported by a device or listing them, it's handled essentially by a copy-paste code, so extract the common stuff into this new helper which also updates all capabilities just before touching them.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/node_device_conf.c | 73 +++++++++++++++++++++++++++++++++++ src/conf/node_device_conf.h | 5 +++ src/libvirt_private.syms | 1 + src/node_device/node_device_driver.c | 75 +++++++++--------------------------- 4 files changed, 97 insertions(+), 57 deletions(-)
ACK Michal

Most of them are static, however in case of PCI and SCSI_HOST devices, the nested capabilities can change dynamically, e.g. due to a driver change (from host_pci_driver -> vfio_pci). Signed-off-by: Erik Skultety <eskultet@redhat.com> Suggested-by: Wu Zongyong <cordius.wu@huawei.com> --- src/conf/node_device_conf.c | 3 +++ src/conf/virnodedeviceobj.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 9467bb415..3aefc9e5b 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -2515,6 +2515,9 @@ virNodeDeviceCapsListExport(virNodeDeviceDefPtr def, tmp[ncaps] = cap; \ } while (0) + if (virNodeDeviceUpdateCaps(def) < 0) + goto cleanup; + if (want_list && VIR_ALLOC_N(tmp, VIR_NODE_DEV_CAP_LAST - 1) < 0) goto cleanup; diff --git a/src/conf/virnodedeviceobj.c b/src/conf/virnodedeviceobj.c index 5360df805..34f754454 100644 --- a/src/conf/virnodedeviceobj.c +++ b/src/conf/virnodedeviceobj.c @@ -809,6 +809,10 @@ static bool virNodeDeviceMatch(virNodeDeviceObjPtr obj, unsigned int flags) { + /* Refresh the capabilities first, e.g. due to a driver change */ + if (virNodeDeviceUpdateCaps(obj->def) < 0) + return false; + /* filter by cap type */ if (flags & VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP) { if (!(MATCH(SYSTEM) || -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
Most of them are static, however in case of PCI and SCSI_HOST devices, the nested capabilities can change dynamically, e.g. due to a driver change (from host_pci_driver -> vfio_pci).
Signed-off-by: Erik Skultety <eskultet@redhat.com> Suggested-by: Wu Zongyong <cordius.wu@huawei.com> --- src/conf/node_device_conf.c | 3 +++ src/conf/virnodedeviceobj.c | 4 ++++ 2 files changed, 7 insertions(+)
ACK Michal

There were some leftovers from early development which never got used. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/util/virmdev.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/util/virmdev.h b/src/util/virmdev.h index 0b8e830f4..84cbb1f2a 100644 --- a/src/util/virmdev.h +++ b/src/util/virmdev.h @@ -22,7 +22,6 @@ # include "internal.h" # include "virobject.h" # include "virutil.h" -# include "virpci.h" typedef enum { VIR_MDEV_MODEL_TYPE_VFIO_PCI = 0, @@ -35,8 +34,6 @@ VIR_ENUM_DECL(virMediatedDeviceModel) typedef struct _virMediatedDevice virMediatedDevice; typedef virMediatedDevice *virMediatedDevicePtr; -typedef struct _virMediatedDeviceAddress virMediatedDeviceAddress; -typedef virMediatedDeviceAddress *virMediatedDeviceAddressPtr; typedef struct _virMediatedDeviceList virMediatedDeviceList; typedef virMediatedDeviceList *virMediatedDeviceListPtr; -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
There were some leftovers from early development which never got used.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/util/virmdev.h | 3 --- 1 file changed, 3 deletions(-)
ACK, nice. Michal

This is later going to replace the existing virNodeDevCapMdevType, since: 1) it's going to couple related stuff in a single module 2) util is supposed to contain helpers that are widely accessible across the whole repository. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virmdev.c | 13 +++++++++++++ src/util/virmdev.h | 12 ++++++++++++ 3 files changed, 26 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1698e6227..75eaf1d4c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2181,6 +2181,7 @@ virMediatedDeviceModelTypeFromString; virMediatedDeviceModelTypeToString; virMediatedDeviceNew; virMediatedDeviceSetUsedBy; +virMediatedDeviceTypeFree; diff --git a/src/util/virmdev.c b/src/util/virmdev.c index a5f52d10f..db679b8a6 100644 --- a/src/util/virmdev.c +++ b/src/util/virmdev.c @@ -483,3 +483,16 @@ virMediatedDeviceListMarkDevices(virMediatedDeviceListPtr dst, } goto cleanup; } + + +void +virMediatedDeviceTypeFree(virMediatedDeviceTypePtr type) +{ + if (!type) + return; + + VIR_FREE(type->id); + VIR_FREE(type->name); + VIR_FREE(type->device_api); + VIR_FREE(type); +} diff --git a/src/util/virmdev.h b/src/util/virmdev.h index 84cbb1f2a..320610ab9 100644 --- a/src/util/virmdev.h +++ b/src/util/virmdev.h @@ -37,6 +37,15 @@ typedef virMediatedDevice *virMediatedDevicePtr; typedef struct _virMediatedDeviceList virMediatedDeviceList; typedef virMediatedDeviceList *virMediatedDeviceListPtr; +typedef struct _virMediatedDeviceType virMediatedDeviceType; +typedef virMediatedDeviceType *virMediatedDeviceTypePtr; +struct _virMediatedDeviceType { + char *id; + char *name; + char *device_api; + unsigned int available_instances; +}; + typedef int (*virMediatedDeviceCallback)(virMediatedDevicePtr dev, const char *path, void *opaque); @@ -117,4 +126,7 @@ virMediatedDeviceListMarkDevices(virMediatedDeviceListPtr dst, virMediatedDeviceListPtr src, const char *drvname, const char *domname); + +void +virMediatedDeviceTypeFree(virMediatedDeviceTypePtr type); #endif /* __VIR_MDEV_H__ */ -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
This is later going to replace the existing virNodeDevCapMdevType, since: 1) it's going to couple related stuff in a single module 2) util is supposed to contain helpers that are widely accessible across the whole repository.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virmdev.c | 13 +++++++++++++ src/util/virmdev.h | 12 ++++++++++++ 3 files changed, 26 insertions(+)
ACK Michal

This should serve as a replacement for the existing udevFillMdevType which is responsible for fetching the device type's attributes from the sysfs interface. The problem with the existing solution is that it's tied to the udev backend. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/util/virmdev.c | 34 ++++++++++++++++++++++++++++++++++ src/util/virmdev.h | 5 +++++ 2 files changed, 39 insertions(+) diff --git a/src/util/virmdev.c b/src/util/virmdev.c index db679b8a6..b57cc3ed9 100644 --- a/src/util/virmdev.c +++ b/src/util/virmdev.c @@ -496,3 +496,37 @@ virMediatedDeviceTypeFree(virMediatedDeviceTypePtr type) VIR_FREE(type->device_api); VIR_FREE(type); } + + +int +virMediatedDeviceTypeReadAttrs(const char *sysfspath, + virMediatedDeviceTypePtr *type) +{ + int ret = -1; + virMediatedDeviceTypePtr tmp = NULL; + +#define MDEV_GET_SYSFS_ATTR(attr, dst, cb) \ + do { \ + if (cb(dst, "%s/%s", sysfspath, attr) < 0) \ + goto cleanup; \ + } while (0) \ + + if (VIR_ALLOC(tmp) < 0) + goto cleanup; + + if (VIR_STRDUP(tmp->id, last_component(sysfspath)) < 0) + goto cleanup; + + MDEV_GET_SYSFS_ATTR("name", &tmp->name, virFileReadValueString); + MDEV_GET_SYSFS_ATTR("device_api", &tmp->device_api, virFileReadValueString); + MDEV_GET_SYSFS_ATTR("available_instances", &tmp->available_instances, + virFileReadValueUint); + +#undef MDEV_GET_SYSFS_ATTR + + VIR_STEAL_PTR(*type, tmp); + ret = 0; + cleanup: + virMediatedDeviceTypeFree(tmp); + return ret; +} diff --git a/src/util/virmdev.h b/src/util/virmdev.h index 320610ab9..01ab02e75 100644 --- a/src/util/virmdev.h +++ b/src/util/virmdev.h @@ -129,4 +129,9 @@ virMediatedDeviceListMarkDevices(virMediatedDeviceListPtr dst, void virMediatedDeviceTypeFree(virMediatedDeviceTypePtr type); + +int +virMediatedDeviceTypeReadAttrs(const char *sysfspath, + virMediatedDeviceTypePtr *type); + #endif /* __VIR_MDEV_H__ */ -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
This should serve as a replacement for the existing udevFillMdevType which is responsible for fetching the device type's attributes from the sysfs interface. The problem with the existing solution is that it's tied to the udev backend.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/util/virmdev.c | 34 ++++++++++++++++++++++++++++++++++ src/util/virmdev.h | 5 +++++ 2 files changed, 39 insertions(+)
diff --git a/src/util/virmdev.c b/src/util/virmdev.c index db679b8a6..b57cc3ed9 100644 --- a/src/util/virmdev.c +++ b/src/util/virmdev.c @@ -496,3 +496,37 @@ virMediatedDeviceTypeFree(virMediatedDeviceTypePtr type) VIR_FREE(type->device_api); VIR_FREE(type); } + + +int +virMediatedDeviceTypeReadAttrs(const char *sysfspath, + virMediatedDeviceTypePtr *type) +{ + int ret = -1; + virMediatedDeviceTypePtr tmp = NULL; + +#define MDEV_GET_SYSFS_ATTR(attr, dst, cb) \ + do { \ + if (cb(dst, "%s/%s", sysfspath, attr) < 0) \ + goto cleanup; \ + } while (0) \
Drop this backward slash.
+ + if (VIR_ALLOC(tmp) < 0) + goto cleanup; + + if (VIR_STRDUP(tmp->id, last_component(sysfspath)) < 0) + goto cleanup; + + MDEV_GET_SYSFS_ATTR("name", &tmp->name, virFileReadValueString); + MDEV_GET_SYSFS_ATTR("device_api", &tmp->device_api, virFileReadValueString); + MDEV_GET_SYSFS_ATTR("available_instances", &tmp->available_instances, + virFileReadValueUint); + +#undef MDEV_GET_SYSFS_ATTR + + VIR_STEAL_PTR(*type, tmp); + ret = 0; + cleanup: + virMediatedDeviceTypeFree(tmp); + return ret; +} diff --git a/src/util/virmdev.h b/src/util/virmdev.h index 320610ab9..01ab02e75 100644 --- a/src/util/virmdev.h +++ b/src/util/virmdev.h @@ -129,4 +129,9 @@ virMediatedDeviceListMarkDevices(virMediatedDeviceListPtr dst,
void virMediatedDeviceTypeFree(virMediatedDeviceTypePtr type); + +int +virMediatedDeviceTypeReadAttrs(const char *sysfspath, + virMediatedDeviceTypePtr *type);
ACK if you also expose the function in libvirt_private.syms. Michal

This is a replacement for the existing udevPCIGetMdevTypesCap which is static to the udev backend. This simple helper constructs the sysfs path from the device's base path for each mdev type and queries the corresponding attributes of that type. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virpci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virpci.h | 4 ++++ 3 files changed, 63 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 75eaf1d4c..8d4c8dd3f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2456,6 +2456,7 @@ virPCIDeviceWaitForCleanup; virPCIEDeviceInfoFree; virPCIGetDeviceAddressFromSysfsLink; virPCIGetHeaderType; +virPCIGetMdevTypes; virPCIGetNetName; virPCIGetPhysicalFunction; virPCIGetVirtualFunctionIndex; diff --git a/src/util/virpci.c b/src/util/virpci.c index fe57bef32..12d7ef0e4 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -3027,6 +3027,64 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path, return ret; } + +int +virPCIGetMdevTypes(const char *sysfspath, + virMediatedDeviceTypePtr **types) +{ + int ret = -1; + int dirret = -1; + DIR *dir = NULL; + struct dirent *entry; + char *types_path = NULL; + char *tmppath = NULL; + virMediatedDeviceTypePtr mdev_type = NULL; + virMediatedDeviceTypePtr *mdev_types = NULL; + size_t ntypes = 0; + size_t i; + + if (virAsprintf(&types_path, "%s/mdev_supported_types", sysfspath) < 0) + return -1; + + if ((dirret = virDirOpenIfExists(&dir, types_path)) < 0) + goto cleanup; + + if (dirret == 0) { + ret = 0; + goto cleanup; + } + + while ((dirret = virDirRead(dir, &entry, types_path)) > 0) { + /* append the type id to the path and read the attributes from there */ + if (virAsprintf(&tmppath, "%s/%s", types_path, entry->d_name) < 0) + goto cleanup; + + if (virMediatedDeviceTypeReadAttrs(tmppath, &mdev_type) < 0) + goto cleanup; + + if (VIR_APPEND_ELEMENT(mdev_types, ntypes, mdev_type) < 0) + goto cleanup; + + VIR_FREE(tmppath); + } + + if (dirret < 0) + goto cleanup; + + VIR_STEAL_PTR(*types, mdev_types); + ret = ntypes; + ntypes = 0; + cleanup: + virMediatedDeviceTypeFree(mdev_type); + for (i = 0; i < ntypes; i++) + virMediatedDeviceTypeFree(mdev_types[i]); + VIR_FREE(mdev_types); + VIR_FREE(types_path); + VIR_FREE(tmppath); + VIR_DIR_CLOSE(dir); + return ret; +} + #else static const char *unsupported = N_("not supported on non-linux platforms"); diff --git a/src/util/virpci.h b/src/util/virpci.h index f1fbe39e6..a0bc0a474 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -25,6 +25,7 @@ # define __VIR_PCI_H__ # include "internal.h" +# include "virmdev.h" # include "virobject.h" # include "virutil.h" @@ -249,4 +250,7 @@ int virPCIGetHeaderType(virPCIDevicePtr dev, int *hdrType); void virPCIEDeviceInfoFree(virPCIEDeviceInfoPtr dev); +int virPCIGetMdevTypes(const char *sysfspath, + virMediatedDeviceType ***types); + #endif /* __VIR_PCI_H__ */ -- 2.13.6

On 01/25/2018 10:23 AM, Erik Skultety wrote:
This is a replacement for the existing udevPCIGetMdevTypesCap which is static to the udev backend. This simple helper constructs the sysfs path from the device's base path for each mdev type and queries the corresponding attributes of that type.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virpci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virpci.h | 4 ++++ 3 files changed, 63 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 75eaf1d4c..8d4c8dd3f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2456,6 +2456,7 @@ virPCIDeviceWaitForCleanup; virPCIEDeviceInfoFree; virPCIGetDeviceAddressFromSysfsLink; virPCIGetHeaderType; +virPCIGetMdevTypes; virPCIGetNetName; virPCIGetPhysicalFunction; virPCIGetVirtualFunctionIndex; diff --git a/src/util/virpci.c b/src/util/virpci.c index fe57bef32..12d7ef0e4 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -3027,6 +3027,64 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path, return ret; }
+ +int +virPCIGetMdevTypes(const char *sysfspath, + virMediatedDeviceTypePtr **types)
Since this function returns size_t on success, I guess the retval should be type of ssize_t at least. We are not guaranteed that size_t will fit into int (although in this case it will - currently you will have only limited number of MDEVs if any). ACK Michal

On Fri, Jan 26, 2018 at 12:39:00PM +0100, Michal Privoznik wrote:
On 01/25/2018 10:23 AM, Erik Skultety wrote:
This is a replacement for the existing udevPCIGetMdevTypesCap which is static to the udev backend. This simple helper constructs the sysfs path from the device's base path for each mdev type and queries the corresponding attributes of that type.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virpci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virpci.h | 4 ++++ 3 files changed, 63 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 75eaf1d4c..8d4c8dd3f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2456,6 +2456,7 @@ virPCIDeviceWaitForCleanup; virPCIEDeviceInfoFree; virPCIGetDeviceAddressFromSysfsLink; virPCIGetHeaderType; +virPCIGetMdevTypes; virPCIGetNetName; virPCIGetPhysicalFunction; virPCIGetVirtualFunctionIndex; diff --git a/src/util/virpci.c b/src/util/virpci.c index fe57bef32..12d7ef0e4 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -3027,6 +3027,64 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path, return ret; }
+ +int +virPCIGetMdevTypes(const char *sysfspath, + virMediatedDeviceTypePtr **types)
Since this function returns size_t on success, I guess the retval should be type of ssize_t at least. We are not guaranteed that size_t will fit
ssize_t wouldn't really help, since assigning size_t might overflow, so the only safe bet is long long, but I mean, do you really expect there to be more than INT_MAX mdev types for a device? That would be a lot of types to support. Erik
into int (although in this case it will - currently you will have only limited number of MDEVs if any).
ACK
Michal

On 01/29/2018 01:24 PM, Erik Skultety wrote:
On Fri, Jan 26, 2018 at 12:39:00PM +0100, Michal Privoznik wrote:
On 01/25/2018 10:23 AM, Erik Skultety wrote:
This is a replacement for the existing udevPCIGetMdevTypesCap which is static to the udev backend. This simple helper constructs the sysfs path from the device's base path for each mdev type and queries the corresponding attributes of that type.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virpci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virpci.h | 4 ++++ 3 files changed, 63 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 75eaf1d4c..8d4c8dd3f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2456,6 +2456,7 @@ virPCIDeviceWaitForCleanup; virPCIEDeviceInfoFree; virPCIGetDeviceAddressFromSysfsLink; virPCIGetHeaderType; +virPCIGetMdevTypes; virPCIGetNetName; virPCIGetPhysicalFunction; virPCIGetVirtualFunctionIndex; diff --git a/src/util/virpci.c b/src/util/virpci.c index fe57bef32..12d7ef0e4 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -3027,6 +3027,64 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path, return ret; }
+ +int +virPCIGetMdevTypes(const char *sysfspath, + virMediatedDeviceTypePtr **types)
Since this function returns size_t on success, I guess the retval should be type of ssize_t at least. We are not guaranteed that size_t will fit
ssize_t wouldn't really help, since assigning size_t might overflow, so the only safe bet is long long, but I mean, do you really expect there to be more than INT_MAX mdev types for a device? That would be a lot of types to support.
In kernel, they do a lot of size_t -> ssize_t conversion in cases where's it's next to impossible to overflow. And I believe this is one of them. Michal

On Mon, Jan 29, 2018 at 02:02:19PM +0100, Michal Privoznik wrote
On 01/29/2018 01:24 PM, Erik Skultety wrote:
On Fri, Jan 26, 2018 at 12:39:00PM +0100, Michal Privoznik wrote:
On 01/25/2018 10:23 AM, Erik Skultety wrote:
This is a replacement for the existing udevPCIGetMdevTypesCap which is static to the udev backend. This simple helper constructs the sysfs path from the device's base path for each mdev type and queries the corresponding attributes of that type.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virpci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virpci.h | 4 ++++ 3 files changed, 63 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 75eaf1d4c..8d4c8dd3f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2456,6 +2456,7 @@ virPCIDeviceWaitForCleanup; virPCIEDeviceInfoFree; virPCIGetDeviceAddressFromSysfsLink; virPCIGetHeaderType; +virPCIGetMdevTypes; virPCIGetNetName; virPCIGetPhysicalFunction; virPCIGetVirtualFunctionIndex; diff --git a/src/util/virpci.c b/src/util/virpci.c index fe57bef32..12d7ef0e4 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -3027,6 +3027,64 @@ virPCIGetVirtualFunctionInfo(const char *vf_sysfs_device_path, return ret; }
+ +int +virPCIGetMdevTypes(const char *sysfspath, + virMediatedDeviceTypePtr **types)
Since this function returns size_t on success, I guess the retval should be type of ssize_t at least. We are not guaranteed that size_t will fit
ssize_t wouldn't really help, since assigning size_t might overflow, so the only safe bet is long long, but I mean, do you really expect there to be more than INT_MAX mdev types for a device? That would be a lot of types to support.
In kernel, they do a lot of size_t -> ssize_t conversion in cases where's it's next to impossible to overflow. And I believe this is one of them.
Fair enough, consider it changed. Erik

These are not necessary anymore, since these are going to be shadowed by the helpers provided by util/virmdev.c module. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/node_device/node_device_udev.c | 119 ------------------------------------- 1 file changed, 119 deletions(-) diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 519b0bf6f..1ccf1f8b4 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -393,119 +393,6 @@ udevTranslatePCIIds(unsigned int vendor, static int -udevFillMdevType(struct udev_device *device, - const char *dir, - virNodeDevCapMdevTypePtr type) -{ - int ret = -1; - char *attrpath = NULL; - -#define MDEV_GET_SYSFS_ATTR(attr_name, cb, ...) \ - do { \ - if (virAsprintf(&attrpath, "%s/%s", dir, #attr_name) < 0) \ - goto cleanup; \ - \ - if (cb(device, attrpath, __VA_ARGS__) < 0) \ - goto cleanup; \ - \ - VIR_FREE(attrpath); \ - } while (0) \ - - if (VIR_STRDUP(type->id, last_component(dir)) < 0) - goto cleanup; - - /* query udev for the attributes under subdirectories using the relative - * path stored in @dir, i.e. 'mdev_supported_types/<type_id>' - */ - MDEV_GET_SYSFS_ATTR(name, udevGetStringSysfsAttr, &type->name); - MDEV_GET_SYSFS_ATTR(device_api, udevGetStringSysfsAttr, &type->device_api); - MDEV_GET_SYSFS_ATTR(available_instances, udevGetUintSysfsAttr, - &type->available_instances, 10); - -#undef MDEV_GET_SYSFS_ATTR - - ret = 0; - cleanup: - VIR_FREE(attrpath); - return ret; -} - - -static int -udevPCIGetMdevTypesCap(struct udev_device *device, - virNodeDevCapPCIDevPtr pcidata) -{ - int ret = -1; - int dirret = -1; - DIR *dir = NULL; - struct dirent *entry; - char *path = NULL; - char *tmppath = NULL; - virNodeDevCapMdevTypePtr type = NULL; - virNodeDevCapMdevTypePtr *types = NULL; - size_t ntypes = 0; - size_t i; - - if (virAsprintf(&path, "%s/mdev_supported_types", - udev_device_get_syspath(device)) < 0) - return -1; - - if ((dirret = virDirOpenIfExists(&dir, path)) < 0) - goto cleanup; - - if (dirret == 0) { - ret = 0; - goto cleanup; - } - - if (VIR_ALLOC(types) < 0) - goto cleanup; - - /* UDEV doesn't report attributes under subdirectories by default but is - * able to query them if the path to the attribute is relative to the - * device's base path, e.g. /sys/devices/../0000:00:01.0/ is the device's - * base path as udev reports it, but we're interested in attributes under - * /sys/devices/../0000:00:01.0/mdev_supported_types/<type>/. So, we need to - * scan the subdirectories ourselves. - */ - while ((dirret = virDirRead(dir, &entry, path)) > 0) { - if (VIR_ALLOC(type) < 0) - goto cleanup; - - /* construct the relative mdev type path bit for udev */ - if (virAsprintf(&tmppath, "mdev_supported_types/%s", entry->d_name) < 0) - goto cleanup; - - if (udevFillMdevType(device, tmppath, type) < 0) - goto cleanup; - - if (VIR_APPEND_ELEMENT(types, ntypes, type) < 0) - goto cleanup; - - VIR_FREE(tmppath); - } - - if (dirret < 0) - goto cleanup; - - VIR_STEAL_PTR(pcidata->mdev_types, types); - pcidata->nmdev_types = ntypes; - pcidata->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV; - ntypes = 0; - ret = 0; - cleanup: - virNodeDevCapMdevTypeFree(type); - for (i = 0; i < ntypes; i++) - virNodeDevCapMdevTypeFree(types[i]); - VIR_FREE(types); - VIR_FREE(path); - VIR_FREE(tmppath); - VIR_DIR_CLOSE(dir); - return ret; -} - - -static int udevProcessPCI(struct udev_device *device, virNodeDeviceDefPtr def) { @@ -596,12 +483,6 @@ udevProcessPCI(struct udev_device *device, } } - /* check whether the device is mediated devices framework capable, if so, - * process it - */ - if (udevPCIGetMdevTypesCap(device, pci_dev) < 0) - goto cleanup; - ret = 0; cleanup: -- 2.13.6

On 01/25/2018 10:24 AM, Erik Skultety wrote:
These are not necessary anymore, since these are going to be shadowed by the helpers provided by util/virmdev.c module.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/node_device/node_device_udev.c | 119 ------------------------------------- 1 file changed, 119 deletions(-)
ACK Michal

Now that we have all the building blocks in place, switch the nodedev driver to use the "new" virMediatedDeviceType type instead of the "old" virNodeDevCapMdevType one. Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/node_device_conf.c | 21 ++++----------------- src/conf/node_device_conf.h | 14 +------------- src/libvirt_private.syms | 1 - 3 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 3aefc9e5b..5fc5f6708 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -92,19 +92,6 @@ virNodeDevCapsDefParseString(const char *xpath, void -virNodeDevCapMdevTypeFree(virNodeDevCapMdevTypePtr type) -{ - if (!type) - return; - - VIR_FREE(type->id); - VIR_FREE(type->name); - VIR_FREE(type->device_api); - VIR_FREE(type); -} - - -void virNodeDeviceDefFree(virNodeDeviceDefPtr def) { virNodeDevCapsDefPtr caps; @@ -285,7 +272,7 @@ virNodeDeviceCapPCIDefFormat(virBufferPtr buf, virBufferAddLit(buf, "<capability type='mdev_types'>\n"); virBufferAdjustIndent(buf, 2); for (i = 0; i < data->pci_dev.nmdev_types; i++) { - virNodeDevCapMdevTypePtr type = data->pci_dev.mdev_types[i]; + virMediatedDeviceTypePtr type = data->pci_dev.mdev_types[i]; virBufferEscapeString(buf, "<type id='%s'>\n", type->id); virBufferAdjustIndent(buf, 2); if (type->name) @@ -1546,7 +1533,7 @@ virNodeDevPCICapMdevTypesParseXML(xmlXPathContextPtr ctxt, xmlNodePtr orignode = NULL; xmlNodePtr *nodes = NULL; int nmdev_types = -1; - virNodeDevCapMdevTypePtr type = NULL; + virMediatedDeviceTypePtr type = NULL; size_t i; if ((nmdev_types = virXPathNodeSet("./type", ctxt, &nodes)) < 0) @@ -1593,7 +1580,7 @@ virNodeDevPCICapMdevTypesParseXML(xmlXPathContextPtr ctxt, ret = 0; cleanup: VIR_FREE(nodes); - virNodeDevCapMdevTypeFree(type); + virMediatedDeviceTypeFree(type); ctxt->node = orignode; return ret; } @@ -2176,7 +2163,7 @@ virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) VIR_FREE(data->pci_dev.iommuGroupDevices); virPCIEDeviceInfoFree(data->pci_dev.pci_express); for (i = 0; i < data->pci_dev.nmdev_types; i++) - virNodeDevCapMdevTypeFree(data->pci_dev.mdev_types[i]); + virMediatedDeviceTypeFree(data->pci_dev.mdev_types[i]); VIR_FREE(data->pci_dev.mdev_types); break; case VIR_NODE_DEV_CAP_USB_DEV: diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 53cdfdb01..685ae3034 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -139,15 +139,6 @@ struct _virNodeDevCapSystem { virNodeDevCapSystemFirmware firmware; }; -typedef struct _virNodeDevCapMdevType virNodeDevCapMdevType; -typedef virNodeDevCapMdevType *virNodeDevCapMdevTypePtr; -struct _virNodeDevCapMdevType { - char *id; - char *name; - char *device_api; - unsigned int available_instances; -}; - typedef struct _virNodeDevCapMdev virNodeDevCapMdev; typedef virNodeDevCapMdev *virNodeDevCapMdevPtr; struct _virNodeDevCapMdev { @@ -178,7 +169,7 @@ struct _virNodeDevCapPCIDev { int numa_node; virPCIEDeviceInfoPtr pci_express; int hdrType; /* enum virPCIHeaderType or -1 */ - virNodeDevCapMdevTypePtr *mdev_types; + virMediatedDeviceTypePtr *mdev_types; size_t nmdev_types; }; @@ -358,9 +349,6 @@ virNodeDeviceDefFree(virNodeDeviceDefPtr def); void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps); -void -virNodeDevCapMdevTypeFree(virNodeDevCapMdevTypePtr type); - # define VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_CAP \ (VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM | \ VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV | \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8d4c8dd3f..2e20304ad 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -695,7 +695,6 @@ virNetDevIPRouteParseXML; # conf/node_device_conf.h -virNodeDevCapMdevTypeFree; virNodeDevCapsDefFree; virNodeDevCapTypeFromString; virNodeDevCapTypeToString; -- 2.13.6

On 01/25/2018 10:24 AM, Erik Skultety wrote:
Now that we have all the building blocks in place, switch the nodedev driver to use the "new" virMediatedDeviceType type instead of the "old" virNodeDevCapMdevType one.
Signed-off-by: Erik Skultety <eskultet@redhat.com> --- src/conf/node_device_conf.c | 21 ++++----------------- src/conf/node_device_conf.h | 14 +------------- src/libvirt_private.syms | 1 - 3 files changed, 5 insertions(+), 31 deletions(-)
ACK Michal

Just like SRIOV, a PCI device is only capable of the mediated devices framework when it's bound to the vendor native driver, thus if a driver change occurs, e.g. vendor_native->vfio, we need to refresh some of the device's capabilities to reflect the reality, mdev included. Signed-off-by: Erik Skultety <eskultet@redhat.com> Suggested-by: Wu Zongyong <cordius.wu@huawei.com> --- src/conf/node_device_conf.c | 34 +++++++++++++++++++++++++++++++--- src/node_device/node_device_udev.c | 1 - 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 5fc5f6708..9e4273855 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -2758,6 +2758,34 @@ virNodeDeviceGetPCIIOMMUGroupCaps(virNodeDevCapPCIDevPtr pci_dev) } +static int +virNodeDeviceGetPCIMdevTypesCaps(const char *sysfspath, + virNodeDevCapPCIDevPtr pci_dev) +{ + virMediatedDeviceTypePtr *types = NULL; + int rc = 0; + size_t i; + + /* this could be a refresh, so clear out the old data */ + for (i = 0; i < pci_dev->nmdev_types; i++) + virMediatedDeviceTypeFree(pci_dev->mdev_types[i]); + VIR_FREE(pci_dev->mdev_types); + pci_dev->nmdev_types = 0; + pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_MDEV; + + rc = virPCIGetMdevTypes(sysfspath, &types); + + if (rc <= 0) + return rc; + + VIR_STEAL_PTR(pci_dev->mdev_types, types); + pci_dev->nmdev_types = rc; + pci_dev->flags |= VIR_NODE_DEV_CAP_FLAG_PCI_MDEV; + + return 0; +} + + /* virNodeDeviceGetPCIDynamicCaps() get info that is stored in sysfs * about devices related to this device, i.e. things that can change * without this device itself changing. These must be refreshed @@ -2768,9 +2796,9 @@ int virNodeDeviceGetPCIDynamicCaps(const char *sysfsPath, virNodeDevCapPCIDevPtr pci_dev) { - if (virNodeDeviceGetPCISRIOVCaps(sysfsPath, pci_dev) < 0) - return -1; - if (virNodeDeviceGetPCIIOMMUGroupCaps(pci_dev) < 0) + if (virNodeDeviceGetPCISRIOVCaps(sysfsPath, pci_dev) < 0 || + virNodeDeviceGetPCIIOMMUGroupCaps(pci_dev) < 0 || + virNodeDeviceGetPCIMdevTypesCaps(sysfsPath, pci_dev) < 0) return -1; return 0; } diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 1ccf1f8b4..e10660ba0 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -484,7 +484,6 @@ udevProcessPCI(struct udev_device *device, } ret = 0; - cleanup: virPCIDeviceFree(pciDev); virPCIEDeviceInfoFree(pci_express); -- 2.13.6

On 01/25/2018 10:24 AM, Erik Skultety wrote:
Just like SRIOV, a PCI device is only capable of the mediated devices framework when it's bound to the vendor native driver, thus if a driver change occurs, e.g. vendor_native->vfio, we need to refresh some of the device's capabilities to reflect the reality, mdev included.
Signed-off-by: Erik Skultety <eskultet@redhat.com> Suggested-by: Wu Zongyong <cordius.wu@huawei.com> --- src/conf/node_device_conf.c | 34 +++++++++++++++++++++++++++++++--- src/node_device/node_device_udev.c | 1 - 2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 1ccf1f8b4..e10660ba0 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -484,7 +484,6 @@ udevProcessPCI(struct udev_device *device, }
ret = 0; - cleanup: virPCIDeviceFree(pciDev); virPCIEDeviceInfoFree(pci_express);
Unrelated change. ACK to the rest. Michal

On Thu, Jan 25, 2018 at 10:23:47AM +0100, Erik Skultety wrote:
TL;DR: nodedev: - contained a decent amount of redundant code handling the same thing, now it doesn't. - only updated dynamic capabilities during dumpXML, now it does every time it touches them mdev: - didn't update mdev capabilities at all, now it does
This series combines some long-needed refactor changes to the nodedev driver with some necessary mdev fixes based on Wu Zongyong's patch series [1]. There's a lot of simple code movement due to the fact that update of the device capabilities is strictly bound to the nodedev driver. The problem with the existing approach is that in order to properly update all capabilities, especially mdev, we would have to violate the logical code flow we have and call back into the driver to have access to sysfs, i.e. driver->(conf|obj) handling->util_helpers->DRIVER. Therefore to resolve it, along with all the compilation dependencies, I moved most of the capability handling out of the driver into src/conf/node_device_conf.c which already contained more than just parsing and formatting of the capabilities. I also had to move the existing virNodeDevCapMdevType into src/util so that the util helpers would know the type they're working with.
[1] https://www.redhat.com/archives/libvir-list/2018-January/msg00315.html
Fixed all the issues raised by reviewers and pushed, thanks. Erik
participants (3)
-
Erik Skultety
-
Michal Privoznik
-
Wuzongyong (Euler Dept)