[libvirt] [PATCH 00/12] Miscs of nodedev

Basicly, this set is created on the road to implement the supports for NPIV migration [1]. Some of them are preparations (such as the various new util functions), some of them are fixes, and others are improvements. Another set to support the persistent vHBA via scsi storage pool will come soon. Osier Yang (12): Introduce new public API virNodeDeviceFindByWWN remote: Wire up the remote protocol nodedev: Implement virNodeDeviceFindByWWN virsh: Use virNodeDeviceLookupByWWN nodedev: Remove the unused enum nodedev: Introduce two new flags for listAll API util: Add one helper virReadFCHost to read the value of fc_host entry nodedev: Use access instead of stat nodedev: Refactor the helpers nodedev: Dump max vports and vports in use for HBA's XML nodedev: Fix the improper logic when enumerating SRIOV VF nodedev: Abstract nodeDeviceVportCreateDelete as util function docs/formatnode.html.in | 10 +- docs/schemas/nodedev.rng | 6 + include/libvirt/libvirt.h.in | 25 ++- src/conf/node_device_conf.c | 41 ++++- src/conf/node_device_conf.h | 16 +- src/driver.h | 6 + src/libvirt.c | 47 ++++++ src/libvirt_private.syms | 4 + src/libvirt_public.syms | 1 + src/node_device/node_device_driver.c | 119 ++------------ src/node_device/node_device_driver.h | 23 +-- src/node_device/node_device_hal.c | 16 ++- src/node_device/node_device_linux_sysfs.c | 245 +++++++++------------------- src/node_device/node_device_udev.c | 15 ++- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 13 ++- src/remote_protocol-structs | 9 + src/rpc/gendispatch.pl | 4 +- src/util/virpci.c | 36 +++-- src/util/virutil.c | 224 ++++++++++++++++++++++++++ src/util/virutil.h | 19 +++ tools/virsh-nodedev.c | 97 +++++++++--- tools/virsh.pod | 22 ++- 23 files changed, 626 insertions(+), 373 deletions(-) https://www.redhat.com/archives/libvir-list/2012-November/msg00826.html Regards, Osier

Since the name (like scsi_host10) is not stable for vHBA, (it can be changed either after recreating or system rebooting), current API virNodeDeviceFindByName is not nice to use for management app in this case. (E.g. one wants to destroy the vHBA whose name has been changed after system rebooting, he has to find out current name first). Later patches will support the persistent vHBA via storage pool, with which one can identify the vHBA stably by the wwnn && wwpn pair. So this new API comes. --- include/libvirt/libvirt.h.in | 5 ++++ src/driver.h | 6 +++++ src/libvirt.c | 45 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 57 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 09c89c5..b4e1ead 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -3156,6 +3156,11 @@ int virConnectListAllNodeDevices (virConnectPtr conn, virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, const char *name); +virNodeDevicePtr virNodeDeviceLookupByWWN (virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags); + const char * virNodeDeviceGetName (virNodeDevicePtr dev); const char * virNodeDeviceGetParent (virNodeDevicePtr dev); diff --git a/src/driver.h b/src/driver.h index 01c95cf..a4a6573 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1547,6 +1547,11 @@ typedef int (*virDevMonListAllNodeDevices)(virConnectPtr conn, typedef virNodeDevicePtr (*virDevMonDeviceLookupByName)(virConnectPtr conn, const char *name); +typedef virNodeDevicePtr (*virDevMonDeviceLookupByWWN)(virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags); + typedef char * (*virDevMonDeviceGetXMLDesc)(virNodeDevicePtr dev, unsigned int flags); @@ -1578,6 +1583,7 @@ struct _virDeviceMonitor { virDevMonListDevices listDevices; virDevMonListAllNodeDevices listAllNodeDevices; virDevMonDeviceLookupByName deviceLookupByName; + virDevMonDeviceLookupByWWN deviceLookupByWWN; virDevMonDeviceGetXMLDesc deviceGetXMLDesc; virDevMonDeviceGetParent deviceGetParent; virDevMonDeviceNumOfCaps deviceNumOfCaps; diff --git a/src/libvirt.c b/src/libvirt.c index 6d1da12..3ca7e9c 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -14303,6 +14303,51 @@ error: return NULL; } +/** + * virNodeDeviceLookupByWWN: + * @conn: pointer to the hypervisor connection + * @wwnn: WWNN of the HBA. + * @wwpn: WWPN of the HBA. + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Lookup a node device (specially for HBA) by its WWNN and + * WWPN. + * + * Returns a virNodeDevicePtr if found, NULL otherwise. + */ +virNodeDevicePtr +virNodeDeviceLookupByWWN(virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, wwnn=%p, wwpn=%p, flags=%x", conn, wwnn, wwpn, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return NULL; + } + + virCheckNonNullArgGoto(wwnn, error); + virCheckNonNullArgGoto(wwpn, error); + + if (conn->deviceMonitor && conn->deviceMonitor->deviceLookupByWWN) { + virNodeDevicePtr ret; + ret = conn->deviceMonitor->deviceLookupByWWN(conn, wwnn, wwpn, flags); + if (!ret) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return NULL; +} /** * virNodeDeviceGetXMLDesc: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 2107519..13f67ca 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -583,6 +583,7 @@ LIBVIRT_1.0.1 { LIBVIRT_1.0.2 { global: virDomainOpenChannel; + virNodeDeviceLookupByWWN; } LIBVIRT_1.0.1; # .... define new API here using predicted next version number .... -- 1.7.7.6

On Tue, Jan 08, 2013 at 01:05:23AM +0800, Osier Yang wrote:
Since the name (like scsi_host10) is not stable for vHBA, (it can be changed either after recreating or system rebooting), current API virNodeDeviceFindByName is not nice to use for management app in this case. (E.g. one wants to destroy the vHBA whose name has been changed after system rebooting, he has to find out current name first).
Later patches will support the persistent vHBA via storage pool, with which one can identify the vHBA stably by the wwnn && wwpn pair.
So this new API comes. --- include/libvirt/libvirt.h.in | 5 ++++ src/driver.h | 6 +++++ src/libvirt.c | 45 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 09c89c5..b4e1ead 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -3156,6 +3156,11 @@ int virConnectListAllNodeDevices (virConnectPtr conn, virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, const char *name);
+virNodeDevicePtr virNodeDeviceLookupByWWN (virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags);
Since this API doesn't work for all types of node dev, its name should really reflect that. eg virNodeDeviceLookupSCSIHostByWWN() Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 2013年01月08日 01:27, Daniel P. Berrange wrote:
On Tue, Jan 08, 2013 at 01:05:23AM +0800, Osier Yang wrote:
Since the name (like scsi_host10) is not stable for vHBA, (it can be changed either after recreating or system rebooting), current API virNodeDeviceFindByName is not nice to use for management app in this case. (E.g. one wants to destroy the vHBA whose name has been changed after system rebooting, he has to find out current name first).
Later patches will support the persistent vHBA via storage pool, with which one can identify the vHBA stably by the wwnn&& wwpn pair.
So this new API comes. --- include/libvirt/libvirt.h.in | 5 ++++ src/driver.h | 6 +++++ src/libvirt.c | 45 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 09c89c5..b4e1ead 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -3156,6 +3156,11 @@ int virConnectListAllNodeDevices (virConnectPtr conn, virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, const char *name);
+virNodeDevicePtr virNodeDeviceLookupByWWN (virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags);
Since this API doesn't work for all types of node dev, its name should really reflect that. eg
virNodeDeviceLookupSCSIHostByWWN()
Agreed, and v2 posted.

Since the name (like scsi_host10) is not stable for vHBA, (it can be changed either after recreating or system rebooting), current API virNodeDeviceLookupByName is not nice to use for management app in this case. (E.g. one wants to destroy the vHBA whose name has been changed after system rebooting, he has to find out current name first). Later patches will support the persistent vHBA via storage pool, with which one can identify the vHBA stably by the wwnn && wwpn pair. So this new API comes. --- include/libvirt/libvirt.h.in | 5 ++++ src/driver.h | 6 +++++ src/libvirt.c | 46 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + 4 files changed, 58 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 09c89c5..05e9659 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -3156,6 +3156,11 @@ int virConnectListAllNodeDevices (virConnectPtr conn, virNodeDevicePtr virNodeDeviceLookupByName (virConnectPtr conn, const char *name); +virNodeDevicePtr virNodeDeviceLookupSCSIHostByWWN (virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags); + const char * virNodeDeviceGetName (virNodeDevicePtr dev); const char * virNodeDeviceGetParent (virNodeDevicePtr dev); diff --git a/src/driver.h b/src/driver.h index 01c95cf..bdac101 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1547,6 +1547,11 @@ typedef int (*virDevMonListAllNodeDevices)(virConnectPtr conn, typedef virNodeDevicePtr (*virDevMonDeviceLookupByName)(virConnectPtr conn, const char *name); +typedef virNodeDevicePtr (*virDevMonDeviceLookupSCSIHostByWWN)(virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags); + typedef char * (*virDevMonDeviceGetXMLDesc)(virNodeDevicePtr dev, unsigned int flags); @@ -1578,6 +1583,7 @@ struct _virDeviceMonitor { virDevMonListDevices listDevices; virDevMonListAllNodeDevices listAllNodeDevices; virDevMonDeviceLookupByName deviceLookupByName; + virDevMonDeviceLookupSCSIHostByWWN deviceLookupSCSIHostByWWN; virDevMonDeviceGetXMLDesc deviceGetXMLDesc; virDevMonDeviceGetParent deviceGetParent; virDevMonDeviceNumOfCaps deviceNumOfCaps; diff --git a/src/libvirt.c b/src/libvirt.c index 6d1da12..a6db670 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -14303,6 +14303,52 @@ error: return NULL; } +/** + * virNodeDeviceLookupSCSIHostByWWN: + * @conn: pointer to the hypervisor connection + * @wwnn: WWNN of the SCSI Host. + * @wwpn: WWPN of the SCSI Host. + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Lookup SCSI Host which is capable with 'fc_host' by its WWNN and WWPN. + * + * Returns a virNodeDevicePtr if found, NULL otherwise. + */ +virNodeDevicePtr +virNodeDeviceLookupSCSIHostByWWN(virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, wwnn=%p, wwpn=%p, flags=%x", conn, wwnn, wwpn, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return NULL; + } + + virCheckNonNullArgGoto(wwnn, error); + virCheckNonNullArgGoto(wwpn, error); + + if (conn->deviceMonitor && + conn->deviceMonitor->deviceLookupSCSIHostByWWN) { + virNodeDevicePtr ret; + ret = conn->deviceMonitor->deviceLookupSCSIHostByWWN(conn, wwnn, + wwpn, flags); + if (!ret) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return NULL; +} /** * virNodeDeviceGetXMLDesc: diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 2107519..abd5d4a 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -583,6 +583,7 @@ LIBVIRT_1.0.1 { LIBVIRT_1.0.2 { global: virDomainOpenChannel; + virNodeDeviceLookupSCSIHostByWWN; } LIBVIRT_1.0.1; # .... define new API here using predicted next version number .... -- 1.7.7.6

Like virNodeDeviceFindByName, virNodeDeviceFindByWWN has to be treated specially when generating the RPC codes. Also new rule is added in fixup_name to keep the name FindByWWN. --- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 13 ++++++++++++- src/remote_protocol-structs | 9 +++++++++ src/rpc/gendispatch.pl | 4 +++- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index c078cb5..3c0aeaf 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6274,6 +6274,7 @@ static virDeviceMonitor dev_monitor = { .listDevices = remoteNodeListDevices, /* 0.5.0 */ .listAllNodeDevices = remoteConnectListAllNodeDevices, /* 0.10.2 */ .deviceLookupByName = remoteNodeDeviceLookupByName, /* 0.5.0 */ + .deviceLookupByWWN = remoteNodeDeviceLookupByWWN, /* 1.0.2 */ .deviceGetXMLDesc = remoteNodeDeviceGetXMLDesc, /* 0.5.0 */ .deviceGetParent = remoteNodeDeviceGetParent, /* 0.5.0 */ .deviceNumOfCaps = remoteNodeDeviceNumOfCaps, /* 0.5.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 9035776..ccdaea2 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1852,6 +1852,16 @@ struct remote_node_device_lookup_by_name_ret { remote_nonnull_node_device dev; }; +struct remote_node_device_lookup_by_wwn_args { + remote_nonnull_string wwnn; + remote_nonnull_string wwpn; + unsigned int flags; +}; + +struct remote_node_device_lookup_by_wwn_ret { + remote_nonnull_node_device dev; +}; + struct remote_node_device_get_xml_desc_args { remote_nonnull_string name; unsigned int flags; @@ -3049,7 +3059,8 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_CPU_MAP = 293, /* skipgen skipgen */ REMOTE_PROC_DOMAIN_FSTRIM = 294, /* autogen autogen */ REMOTE_PROC_DOMAIN_SEND_PROCESS_SIGNAL = 295, /* autogen autogen */ - REMOTE_PROC_DOMAIN_OPEN_CHANNEL = 296 /* autogen autogen | readstream@2 */ + REMOTE_PROC_DOMAIN_OPEN_CHANNEL = 296, /* autogen autogen | readstream@2 */ + REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_WWN = 297 /* autogen autogen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 91414d4..368833a 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1400,6 +1400,14 @@ struct remote_node_device_lookup_by_name_args { struct remote_node_device_lookup_by_name_ret { remote_nonnull_node_device dev; }; +struct remote_node_device_lookup_by_wwn_args { + remote_nonull_string wwnn; + remote_nonull_string wwpn; + unsigned int flags; +}; +struct remote_node_device_lookup_by_wwn_ret { + remote_nonnull_node_device dev; +}; struct remote_node_device_get_xml_desc_args { remote_nonnull_string name; u_int flags; @@ -2453,4 +2461,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_FSTRIM = 294, REMOTE_PROC_DOMAIN_SEND_PROCESS_SIGNAL = 295, REMOTE_PROC_DOMAIN_OPEN_CHANNEL = 296, + REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_WWN = 297, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 899f4bc..1f895ba 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -45,6 +45,7 @@ sub fixup_name { $name =~ s/Nmi$/NMI/; $name =~ s/Pm/PM/; $name =~ s/Fstrim$/FSTrim/; + $name =~ s/Wwn$/WWN/; return $name; } @@ -402,7 +403,8 @@ elsif ($opt_b) { # node device is special, as it's identified by name if ($argtype =~ m/^remote_node_device_/ and !($argtype =~ m/^remote_node_device_lookup_by_name_/) and - !($argtype =~ m/^remote_node_device_create_xml_/)) { + !($argtype =~ m/^remote_node_device_create_xml_/) and + !($argtype =~ m/^remote_node_device_lookup_by_wwn_/)) { $has_node_device = 1; push(@vars_list, "virNodeDevicePtr dev = NULL"); push(@getters_list, -- 1.7.7.6

Like virNodeDeviceCreateXML, virNodeDeviceLookupSCSIHostByWWN has to be treated specially when generating the RPC codes. Also new rules are added in fixup_name to keep the name. --- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 13 ++++++++++++- src/remote_protocol-structs | 9 +++++++++ src/rpc/gendispatch.pl | 5 ++++- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index c078cb5..8700fa6 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6274,6 +6274,7 @@ static virDeviceMonitor dev_monitor = { .listDevices = remoteNodeListDevices, /* 0.5.0 */ .listAllNodeDevices = remoteConnectListAllNodeDevices, /* 0.10.2 */ .deviceLookupByName = remoteNodeDeviceLookupByName, /* 0.5.0 */ + .deviceLookupSCSIHostByWWN = remoteNodeDeviceLookupSCSIHostByWWN, /* 1.0.2 */ .deviceGetXMLDesc = remoteNodeDeviceGetXMLDesc, /* 0.5.0 */ .deviceGetParent = remoteNodeDeviceGetParent, /* 0.5.0 */ .deviceNumOfCaps = remoteNodeDeviceNumOfCaps, /* 0.5.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 9035776..5ace31f 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1852,6 +1852,16 @@ struct remote_node_device_lookup_by_name_ret { remote_nonnull_node_device dev; }; +struct remote_node_device_lookup_scsi_host_by_wwn_args { + remote_nonnull_string wwnn; + remote_nonnull_string wwpn; + unsigned int flags; +}; + +struct remote_node_device_lookup_scsi_host_by_wwn_ret { + remote_nonnull_node_device dev; +}; + struct remote_node_device_get_xml_desc_args { remote_nonnull_string name; unsigned int flags; @@ -3049,7 +3059,8 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_CPU_MAP = 293, /* skipgen skipgen */ REMOTE_PROC_DOMAIN_FSTRIM = 294, /* autogen autogen */ REMOTE_PROC_DOMAIN_SEND_PROCESS_SIGNAL = 295, /* autogen autogen */ - REMOTE_PROC_DOMAIN_OPEN_CHANNEL = 296 /* autogen autogen | readstream@2 */ + REMOTE_PROC_DOMAIN_OPEN_CHANNEL = 296, /* autogen autogen | readstream@2 */ + REMOTE_PROC_NODE_DEVICE_LOOKUP_SCSI_HOST_BY_WWN = 297 /* autogen autogen priority:high */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 91414d4..b8ca88b 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -1400,6 +1400,14 @@ struct remote_node_device_lookup_by_name_args { struct remote_node_device_lookup_by_name_ret { remote_nonnull_node_device dev; }; +struct remote_node_device_lookup_scsi_host_by_wwn_args { + remote_nonull_string wwnn; + remote_nonull_string wwpn; + unsigned int flags; +}; +struct remote_node_device_lookup_scsi_host_by_wwn_ret { + remote_nonnull_node_device dev; +}; struct remote_node_device_get_xml_desc_args { remote_nonnull_string name; u_int flags; @@ -2453,4 +2461,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_FSTRIM = 294, REMOTE_PROC_DOMAIN_SEND_PROCESS_SIGNAL = 295, REMOTE_PROC_DOMAIN_OPEN_CHANNEL = 296, + REMOTE_PROC_NODE_DEVICE_LOOKUP_SCSI_HOST_BY_WWN = 297, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 899f4bc..c29133a 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -45,6 +45,8 @@ sub fixup_name { $name =~ s/Nmi$/NMI/; $name =~ s/Pm/PM/; $name =~ s/Fstrim$/FSTrim/; + $name =~ s/Scsi/SCSI/; + $name =~ s/Wwn$/WWN/; return $name; } @@ -402,7 +404,8 @@ elsif ($opt_b) { # node device is special, as it's identified by name if ($argtype =~ m/^remote_node_device_/ and !($argtype =~ m/^remote_node_device_lookup_by_name_/) and - !($argtype =~ m/^remote_node_device_create_xml_/)) { + !($argtype =~ m/^remote_node_device_create_xml_/) and + !($argtype =~ m/^remote_node_device_lookup_scsi_host_by_wwn_/)) { $has_node_device = 1; push(@vars_list, "virNodeDevicePtr dev = NULL"); push(@getters_list, -- 1.7.7.6

This just simply changes nodeDeviceFindByWWN to be not static, and use that for udev and HAL backends. --- src/node_device/node_device_driver.c | 9 ++++++--- src/node_device/node_device_driver.h | 4 ++++ src/node_device/node_device_hal.c | 1 + src/node_device/node_device_udev.c | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 522af99..6134507 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -224,10 +224,11 @@ cleanup: } -static virNodeDevicePtr +virNodeDevicePtr nodeDeviceLookupByWWN(virConnectPtr conn, const char *wwnn, - const char *wwpn) + const char *wwpn, + unsigned int flags) { unsigned int i; virDeviceMonitorStatePtr driver = conn->devMonPrivateData; @@ -236,6 +237,8 @@ nodeDeviceLookupByWWN(virConnectPtr conn, virNodeDeviceObjPtr obj = NULL; virNodeDevicePtr dev = NULL; + virCheckFlags(0, NULL); + nodeDeviceLock(driver); for (i = 0; i < devs->count; i++) { @@ -546,7 +549,7 @@ find_new_device(virConnectPtr conn, const char *wwnn, const char *wwpn) virFileWaitForDevices(); - dev = nodeDeviceLookupByWWN(conn, wwnn, wwpn); + dev = nodeDeviceLookupByWWN(conn, wwnn, wwpn, 0); if (dev != NULL) { break; diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index 4cec07c..26f0550 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -77,6 +77,10 @@ int nodeListAllNodeDevices(virConnectPtr conn, virNodeDevicePtr **devices, unsigned int flags); virNodeDevicePtr nodeDeviceLookupByName(virConnectPtr conn, const char *name); +virNodeDevicePtr nodeDeviceLookupByWWN(virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags); char *nodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags); char *nodeDeviceGetParent(virNodeDevicePtr dev); int nodeDeviceNumOfCaps(virNodeDevicePtr dev); diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 610df8d..33e0170 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -765,6 +765,7 @@ static virDeviceMonitor halDeviceMonitor = { .listDevices = nodeListDevices, /* 0.5.0 */ .listAllNodeDevices = nodeListAllNodeDevices, /* 0.10.2 */ .deviceLookupByName = nodeDeviceLookupByName, /* 0.5.0 */ + .deviceLookupByWWN = nodeDeviceLookupByWWN, /* 1.0.2 */ .deviceGetXMLDesc = nodeDeviceGetXMLDesc, /* 0.5.0 */ .deviceGetParent = nodeDeviceGetParent, /* 0.5.0 */ .deviceNumOfCaps = nodeDeviceNumOfCaps, /* 0.5.0 */ diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index a9b30b2..4137488 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1754,6 +1754,7 @@ static virDeviceMonitor udevDeviceMonitor = { .listDevices = nodeListDevices, /* 0.7.3 */ .listAllNodeDevices = nodeListAllNodeDevices, /* 0.10.2 */ .deviceLookupByName = nodeDeviceLookupByName, /* 0.7.3 */ + .deviceLookupByWWN = nodeDeviceLookupByWWN, /* 1.0.2 */ .deviceGetXMLDesc = nodeDeviceGetXMLDesc, /* 0.7.3 */ .deviceGetParent = nodeDeviceGetParent, /* 0.7.3 */ .deviceNumOfCaps = nodeDeviceNumOfCaps, /* 0.7.3 */ -- 1.7.7.6

This just simply changes nodeDeviceLookupByWWN to be not static, and its name into nodeDeviceLookupSCSIHostByWWN. And use that for udev and HAL backends. --- src/node_device/node_device_driver.c | 13 ++++++++----- src/node_device/node_device_driver.h | 4 ++++ src/node_device/node_device_hal.c | 1 + src/node_device/node_device_udev.c | 1 + 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 522af99..73b824f 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -224,10 +224,11 @@ cleanup: } -static virNodeDevicePtr -nodeDeviceLookupByWWN(virConnectPtr conn, - const char *wwnn, - const char *wwpn) +virNodeDevicePtr +nodeDeviceLookupSCSIHostByWWN(virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags) { unsigned int i; virDeviceMonitorStatePtr driver = conn->devMonPrivateData; @@ -236,6 +237,8 @@ nodeDeviceLookupByWWN(virConnectPtr conn, virNodeDeviceObjPtr obj = NULL; virNodeDevicePtr dev = NULL; + virCheckFlags(0, NULL); + nodeDeviceLock(driver); for (i = 0; i < devs->count; i++) { @@ -546,7 +549,7 @@ find_new_device(virConnectPtr conn, const char *wwnn, const char *wwpn) virFileWaitForDevices(); - dev = nodeDeviceLookupByWWN(conn, wwnn, wwpn); + dev = nodeDeviceLookupSCSIHostByWWN(conn, wwnn, wwpn, 0); if (dev != NULL) { break; diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index 4cec07c..718e444 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -77,6 +77,10 @@ int nodeListAllNodeDevices(virConnectPtr conn, virNodeDevicePtr **devices, unsigned int flags); virNodeDevicePtr nodeDeviceLookupByName(virConnectPtr conn, const char *name); +virNodeDevicePtr nodeDeviceLookupSCSIHostByWWN(virConnectPtr conn, + const char *wwnn, + const char *wwpn, + unsigned int flags); char *nodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags); char *nodeDeviceGetParent(virNodeDevicePtr dev); int nodeDeviceNumOfCaps(virNodeDevicePtr dev); diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 610df8d..20714d3 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -765,6 +765,7 @@ static virDeviceMonitor halDeviceMonitor = { .listDevices = nodeListDevices, /* 0.5.0 */ .listAllNodeDevices = nodeListAllNodeDevices, /* 0.10.2 */ .deviceLookupByName = nodeDeviceLookupByName, /* 0.5.0 */ + .deviceLookupSCSIHostByWWN = nodeDeviceLookupSCSIHostByWWN, /* 1.0.2 */ .deviceGetXMLDesc = nodeDeviceGetXMLDesc, /* 0.5.0 */ .deviceGetParent = nodeDeviceGetParent, /* 0.5.0 */ .deviceNumOfCaps = nodeDeviceNumOfCaps, /* 0.5.0 */ diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index a9b30b2..1be8526 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -1754,6 +1754,7 @@ static virDeviceMonitor udevDeviceMonitor = { .listDevices = nodeListDevices, /* 0.7.3 */ .listAllNodeDevices = nodeListAllNodeDevices, /* 0.10.2 */ .deviceLookupByName = nodeDeviceLookupByName, /* 0.7.3 */ + .deviceLookupSCSIHostByWWN = nodeDeviceLookupSCSIHostByWWN, /* 1.0.2 */ .deviceGetXMLDesc = nodeDeviceGetXMLDesc, /* 0.7.3 */ .deviceGetParent = nodeDeviceGetParent, /* 0.7.3 */ .deviceNumOfCaps = nodeDeviceNumOfCaps, /* 0.7.3 */ -- 1.7.7.6

Only nodedev-destroy and nodedev-dumpxml can benifit from the new API, other commands like nodedev-detach only works for PCI devices, WWN makes no sense for them. --- tools/virsh-nodedev.c | 91 ++++++++++++++++++++++++++++++++++++------------ tools/virsh.pod | 15 +++++--- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index f9517cc..70e05fab 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -97,8 +97,9 @@ static const vshCmdInfo info_node_device_destroy[] = { }; static const vshCmdOptDef opts_node_device_destroy[] = { - {"name", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("name of the device to be destroyed")}, + {"name", VSH_OT_ALIAS, 0, "device"}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("device name or wwn pair in 'wwnn,wwpn' format")}, {NULL, 0, 0, NULL} }; @@ -106,21 +107,44 @@ static bool cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) { virNodeDevicePtr dev = NULL; - bool ret = true; - const char *name = NULL; + bool ret = false; + const char *device_value = NULL; + char **arr = NULL; + int narr; - if (vshCommandOptString(cmd, "name", &name) <= 0) + if (vshCommandOptString(cmd, "device", &device_value) <= 0) return false; - dev = virNodeDeviceLookupByName(ctl->conn, name); + if (strchr(device_value, ',')) { + narr = vshStringToArray(device_value, &arr); + if (narr != 2) { + vshError(ctl, _("Malformed device value '%s'"), device_value); + goto cleanup; + } + + dev = virNodeDeviceLookupByWWN(ctl->conn, arr[0], arr[1], 0); + } else { + dev = virNodeDeviceLookupByName(ctl->conn, device_value); + } + + if (!dev) { + vshError(ctl, "%s '%s'", _("Could not find matching device"), device_value); + goto cleanup; + } if (virNodeDeviceDestroy(dev) == 0) { - vshPrint(ctl, _("Destroyed node device '%s'\n"), name); + vshPrint(ctl, _("Destroyed node device '%s'\n"), device_value); } else { - vshError(ctl, _("Failed to destroy node device '%s'"), name); - ret = false; + vshError(ctl, _("Failed to destroy node device '%s'"), device_value); + goto cleanup; } + ret = true; +cleanup: + if (arr) { + VIR_FREE(*arr); + VIR_FREE(arr); + } virNodeDeviceFree(dev); return ret; } @@ -459,34 +483,55 @@ static const vshCmdInfo info_node_device_dumpxml[] = { static const vshCmdOptDef opts_node_device_dumpxml[] = { - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("device name or wwn pair in 'wwnn,wwpn' format")}, {NULL, 0, 0, NULL} }; static bool cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) { - const char *name = NULL; - virNodeDevicePtr device; - char *xml; - - if (vshCommandOptString(cmd, "device", &name) <= 0) - return false; - if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { - vshError(ctl, "%s '%s'", _("Could not find matching device"), name); + virNodeDevicePtr device = NULL; + char *xml = NULL; + const char *device_value = NULL; + char **arr = NULL; + int narr; + bool ret = false; + + if (vshCommandOptString(cmd, "device", &device_value) <= 0) return false; + + if (strchr(device_value, ',')) { + narr = vshStringToArray(device_value, &arr); + if (narr != 2) { + vshError(ctl, _("Malformed device value '%s'"), device_value); + goto cleanup; + } + + device = virNodeDeviceLookupByWWN(ctl->conn, arr[0], arr[1], 0); + } else { + device = virNodeDeviceLookupByName(ctl->conn, device_value); } - xml = virNodeDeviceGetXMLDesc(device, 0); - if (!xml) { - virNodeDeviceFree(device); - return false; + if (!device) { + vshError(ctl, "%s '%s'", _("Could not find matching device"), device_value); + goto cleanup; } + if (!(xml = virNodeDeviceGetXMLDesc(device, 0))) + goto cleanup; + vshPrint(ctl, "%s\n", xml); + ret = true; + +cleanup: + if (arr) { + VIR_FREE(*arr); + VIR_FREE(arr); + } VIR_FREE(xml); virNodeDeviceFree(device); - return true; + return ret; } /* diff --git a/tools/virsh.pod b/tools/virsh.pod index 3687a4d..a2da9ef 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1950,11 +1950,12 @@ host nodes are available for use, but this allows registration of host hardware that libvirt did not automatically detect. I<file> contains xml for a top-level <device> description of a node device. -=item B<nodedev-destroy> I<nodedev> +=item B<nodedev-destroy> I<device> -Destroy (stop) a device on the host. Note that this makes libvirt -quit managing a host device, and may even make that device unusable -by the rest of the physical host until a reboot. +Destroy (stop) a device on the host. I<device> can be either device +name or wwn pair in "wwnn,wwpn" format (only works for HBA). Note +that this makes libvirt quit managing a host device, and may even make +that device unusable by the rest of the physical host until a reboot. =item B<nodedev-detach> I<nodedev> @@ -1964,12 +1965,14 @@ B<nodedev-reattach>, and is done automatically for managed devices. For compatibility purposes, this command can also be spelled B<nodedev-dettach>. -=item B<nodedev-dumpxml> I<nodedev> +=item B<nodedev-dumpxml> I<device> Dump a <device> XML representation for the given node device, including such information as the device name, which bus owns the device, the vendor and product id, and any capabilities of the device usable by -libvirt (such as whether device reset is supported). +libvirt (such as whether device reset is supported). I<device> can +be either device name or wwn pair in "wwnn,wwpn" format (only works +for HBA). =item B<nodedev-list> I<cap> I<--tree> -- 1.7.7.6

Only nodedev-destroy and nodedev-dumpxml can benifit from the new API, other commands like nodedev-detach only works for PCI devices, WWN makes no sense for them. --- tools/virsh-nodedev.c | 91 ++++++++++++++++++++++++++++++++++++------------ tools/virsh.pod | 15 +++++--- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index f9517cc..0090261 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -97,8 +97,9 @@ static const vshCmdInfo info_node_device_destroy[] = { }; static const vshCmdOptDef opts_node_device_destroy[] = { - {"name", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("name of the device to be destroyed")}, + {"name", VSH_OT_ALIAS, 0, "device"}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("device name or wwn pair in 'wwnn,wwpn' format")}, {NULL, 0, 0, NULL} }; @@ -106,21 +107,44 @@ static bool cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) { virNodeDevicePtr dev = NULL; - bool ret = true; - const char *name = NULL; + bool ret = false; + const char *device_value = NULL; + char **arr = NULL; + int narr; - if (vshCommandOptString(cmd, "name", &name) <= 0) + if (vshCommandOptString(cmd, "device", &device_value) <= 0) return false; - dev = virNodeDeviceLookupByName(ctl->conn, name); + if (strchr(device_value, ',')) { + narr = vshStringToArray(device_value, &arr); + if (narr != 2) { + vshError(ctl, _("Malformed device value '%s'"), device_value); + goto cleanup; + } + + dev = virNodeDeviceLookupSCSIHostByWWN(ctl->conn, arr[0], arr[1], 0); + } else { + dev = virNodeDeviceLookupByName(ctl->conn, device_value); + } + + if (!dev) { + vshError(ctl, "%s '%s'", _("Could not find matching device"), device_value); + goto cleanup; + } if (virNodeDeviceDestroy(dev) == 0) { - vshPrint(ctl, _("Destroyed node device '%s'\n"), name); + vshPrint(ctl, _("Destroyed node device '%s'\n"), device_value); } else { - vshError(ctl, _("Failed to destroy node device '%s'"), name); - ret = false; + vshError(ctl, _("Failed to destroy node device '%s'"), device_value); + goto cleanup; } + ret = true; +cleanup: + if (arr) { + VIR_FREE(*arr); + VIR_FREE(arr); + } virNodeDeviceFree(dev); return ret; } @@ -459,34 +483,55 @@ static const vshCmdInfo info_node_device_dumpxml[] = { static const vshCmdOptDef opts_node_device_dumpxml[] = { - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("device name or wwn pair in 'wwnn,wwpn' format")}, {NULL, 0, 0, NULL} }; static bool cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) { - const char *name = NULL; - virNodeDevicePtr device; - char *xml; - - if (vshCommandOptString(cmd, "device", &name) <= 0) - return false; - if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { - vshError(ctl, "%s '%s'", _("Could not find matching device"), name); + virNodeDevicePtr device = NULL; + char *xml = NULL; + const char *device_value = NULL; + char **arr = NULL; + int narr; + bool ret = false; + + if (vshCommandOptString(cmd, "device", &device_value) <= 0) return false; + + if (strchr(device_value, ',')) { + narr = vshStringToArray(device_value, &arr); + if (narr != 2) { + vshError(ctl, _("Malformed device value '%s'"), device_value); + goto cleanup; + } + + device = virNodeDeviceLookupSCSIHostByWWN(ctl->conn, arr[0], arr[1], 0); + } else { + device = virNodeDeviceLookupByName(ctl->conn, device_value); } - xml = virNodeDeviceGetXMLDesc(device, 0); - if (!xml) { - virNodeDeviceFree(device); - return false; + if (!device) { + vshError(ctl, "%s '%s'", _("Could not find matching device"), device_value); + goto cleanup; } + if (!(xml = virNodeDeviceGetXMLDesc(device, 0))) + goto cleanup; + vshPrint(ctl, "%s\n", xml); + ret = true; + +cleanup: + if (arr) { + VIR_FREE(*arr); + VIR_FREE(arr); + } VIR_FREE(xml); virNodeDeviceFree(device); - return true; + return ret; } /* diff --git a/tools/virsh.pod b/tools/virsh.pod index 3687a4d..a2da9ef 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1950,11 +1950,12 @@ host nodes are available for use, but this allows registration of host hardware that libvirt did not automatically detect. I<file> contains xml for a top-level <device> description of a node device. -=item B<nodedev-destroy> I<nodedev> +=item B<nodedev-destroy> I<device> -Destroy (stop) a device on the host. Note that this makes libvirt -quit managing a host device, and may even make that device unusable -by the rest of the physical host until a reboot. +Destroy (stop) a device on the host. I<device> can be either device +name or wwn pair in "wwnn,wwpn" format (only works for HBA). Note +that this makes libvirt quit managing a host device, and may even make +that device unusable by the rest of the physical host until a reboot. =item B<nodedev-detach> I<nodedev> @@ -1964,12 +1965,14 @@ B<nodedev-reattach>, and is done automatically for managed devices. For compatibility purposes, this command can also be spelled B<nodedev-dettach>. -=item B<nodedev-dumpxml> I<nodedev> +=item B<nodedev-dumpxml> I<device> Dump a <device> XML representation for the given node device, including such information as the device name, which bus owns the device, the vendor and product id, and any capabilities of the device usable by -libvirt (such as whether device reset is supported). +libvirt (such as whether device reset is supported). I<device> can +be either device name or wwn pair in "wwnn,wwpn" format (only works +for HBA). =item B<nodedev-list> I<cap> I<--tree> -- 1.7.7.6

Guess it was created for the fc_host and vports_ops capabilities purpose, but there is enum virNodeDevScsiHostCapFlags for them, and enum virNodeDevHBACapType is unused, and actually both VIR_ENUM_DECL and VIR_ENUM_IMPL use the wrong enum name "virNodeDevHBACap". --- src/conf/node_device_conf.c | 5 ----- src/conf/node_device_conf.h | 8 -------- 2 files changed, 0 insertions(+), 13 deletions(-) diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 53b6af2..48e8190 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -56,11 +56,6 @@ VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST, "80203", "80211") -VIR_ENUM_IMPL(virNodeDevHBACap, VIR_NODE_DEV_CAP_HBA_LAST, - "fc_host", - "vport_ops") - - static int virNodeDevCapsDefParseString(const char *xpath, xmlXPathContextPtr ctxt, diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 12c36d8..36bf5ac 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -55,16 +55,8 @@ enum virNodeDevNetCapType { VIR_NODE_DEV_CAP_NET_LAST }; -enum virNodeDevHBACapType { - /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */ - VIR_NODE_DEV_CAP_HBA_FC_HOST, /* fibre channel HBA */ - VIR_NODE_DEV_CAP_HBA_VPORT_OPS, /* capable of vport operations */ - VIR_NODE_DEV_CAP_HBA_LAST -}; - VIR_ENUM_DECL(virNodeDevCap) VIR_ENUM_DECL(virNodeDevNetCap) -VIR_ENUM_DECL(virNodeDevHBACap) enum virNodeDevStorageCapFlags { VIR_NODE_DEV_CAP_STORAGE_REMOVABLE = (1 << 0), -- 1.7.7.6

VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST to filter the FC HBA, and VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS to filter the FC HBA which supports vport. --- include/libvirt/libvirt.h.in | 20 +++++++++++--------- src/conf/node_device_conf.c | 29 ++++++++++++++++++++++++++--- src/conf/node_device_conf.h | 6 +++++- src/libvirt.c | 2 ++ tools/virsh-nodedev.c | 6 ++++++ tools/virsh.pod | 7 ++++--- 6 files changed, 54 insertions(+), 16 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index b4e1ead..019801a 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -3138,15 +3138,17 @@ int virNodeListDevices (virConnectPtr conn, * type. */ typedef enum { - VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM = 1 << 0, /* System capability */ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV = 1 << 1, /* PCI device */ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV = 1 << 2, /* USB device */ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE = 1 << 3, /* USB interface */ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET = 1 << 4, /* Network device */ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST = 1 << 5, /* SCSI Host Bus Adapter */ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET = 1 << 6, /* SCSI Target */ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI = 1 << 7, /* SCSI device */ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE = 1 << 8, /* Storage device */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM = 1 << 0, /* System capability */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV = 1 << 1, /* PCI device */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV = 1 << 2, /* USB device */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE = 1 << 3, /* USB interface */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET = 1 << 4, /* Network device */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST = 1 << 5, /* SCSI Host Bus Adapter */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET = 1 << 6, /* SCSI Target */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI = 1 << 7, /* SCSI device */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE = 1 << 8, /* Storage device */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST = 1 << 9, /* FC Host Bus Adapter */ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS = 1 << 10, /* Capable of vport */ } virConnectListAllNodeDeviceFlags; int virConnectListAllNodeDevices (virConnectPtr conn, diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 48e8190..819e6af 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -50,7 +50,9 @@ VIR_ENUM_IMPL(virNodeDevCap, VIR_NODE_DEV_CAP_LAST, "scsi_host", "scsi_target", "scsi", - "storage") + "storage", + "fc_host", + "vports") VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST, "80203", @@ -467,8 +469,10 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDefPtr def) virBufferAddLit(&buf, " <capability type='hotpluggable' />\n"); break; + case VIR_NODE_DEV_CAP_FC_HOST: + case VIR_NODE_DEV_CAP_VPORTS: case VIR_NODE_DEV_CAP_LAST: - /* ignore special LAST value */ + default: break; } @@ -1409,7 +1413,10 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) VIR_FREE(data->storage.serial); VIR_FREE(data->storage.media_label); break; + case VIR_NODE_DEV_CAP_FC_HOST: + case VIR_NODE_DEV_CAP_VPORTS: case VIR_NODE_DEV_CAP_LAST: + default: /* This case is here to shutup the compiler */ break; } @@ -1437,6 +1444,18 @@ virNodeDeviceCapMatch(virNodeDeviceObjPtr devobj, for (cap = devobj->def->caps; cap; cap = cap->next) { if (type == cap->type) return true; + + if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) { + if (type == VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST && + (cap->data.scsi_host.flags & + VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST)) + return true; + + if (type == VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS && + (cap->data.scsi_host.flags & + VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS)) + return true; + } } return false; @@ -1466,7 +1485,11 @@ virNodeDeviceMatch(virNodeDeviceObjPtr devobj, (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI) && virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_SCSI)) || (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE) && - virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_STORAGE)))) + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_STORAGE)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_FC_HOST)) || + (MATCH(VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS) && + virNodeDeviceCapMatch(devobj, VIR_NODE_DEV_CAP_VPORTS)))) return false; } diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 36bf5ac..145d699 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -45,6 +45,8 @@ enum virNodeDevCapType { VIR_NODE_DEV_CAP_SCSI_TARGET, /* SCSI Target */ VIR_NODE_DEV_CAP_SCSI, /* SCSI device */ VIR_NODE_DEV_CAP_STORAGE, /* Storage device */ + VIR_NODE_DEV_CAP_FC_HOST, /* FC Host Bus Adapter */ + VIR_NODE_DEV_CAP_VPORTS, /* HBA which is capable of vports */ VIR_NODE_DEV_CAP_LAST }; @@ -262,7 +264,9 @@ void virNodeDeviceObjUnlock(virNodeDeviceObjPtr obj); VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST | \ VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET | \ VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI | \ - VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE) + VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST | \ + VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS) int virNodeDeviceList(virConnectPtr conn, virNodeDeviceObjList devobjs, diff --git a/src/libvirt.c b/src/libvirt.c index 3ca7e9c..04fea4e 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -14171,6 +14171,8 @@ error: * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET * VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI * VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST + * VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS * * Returns the number of node devices found or -1 and sets @devices to NULL in * case of error. On success, the array stored into @devices is guaranteed to diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index 70e05fab..9b7f962 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -417,6 +417,12 @@ cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) case VIR_NODE_DEV_CAP_STORAGE: flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE; break; + case VIR_NODE_DEV_CAP_FC_HOST: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST; + break; + case VIR_NODE_DEV_CAP_VPORTS: + flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS; + break; default: break; } diff --git a/tools/virsh.pod b/tools/virsh.pod index a2da9ef..368618c 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1980,9 +1980,10 @@ List all of the devices available on the node that are known by libvirt. I<cap> is used to filter the list by capability types, the types must be separated by comma, e.g. --cap pci,scsi, valid capability types include 'system', 'pci', 'usb_device', 'usb', 'net', 'scsi_host', 'scsi_target', -'scsi', 'storage'. If I<--tree> is used, the output is formatted in a tree -representing parents of each node. I<cap> and I<--tree> are mutually -exclusive. +'scsi', 'storage', 'fc_host', 'vports'. If I<--tree> is used, the output +is formatted in a tree representing parents of each node. I<cap> and +I<--tree> are mutually exclusive. + =item B<nodedev-reattach> I<nodedev> Declare that I<nodedev> is no longer in use by any guests, and that -- 1.7.7.6

"open_wwn_file" in node_device_linux_sysfs.c is redundant, on one hand it duplicates work of virFileReadAll, on the other hand, it's waste to use a function for it, as there is no other users of it. So I don't see why the file opening work cannot be done in "read_wwn_linux". "read_wwn_linux" can be abstracted as an util function. As what all it does is to read the sysfs entry. So this patch removes "open_wwn_file", and abstract "read_wwn_linux" as an util function "virReadFCHost" (a more general name, because after changes, it can read each of the fc_host entry now). * src/util/virutil.h: (Declare virReadFCHost) * src/util/virutil.c: (Implement virReadFCHost) * src/node_device/node_device_linux_sysfs.c: (Remove open_wwn_file, and read_wwn_linux) src/node_device/node_device_driver.h: (Remove the declaration of read_wwn_linux, and the related macros) src/libvirt_private.syms: (Export virReadFCHost) --- src/libvirt_private.syms | 1 + src/node_device/node_device_driver.h | 4 - src/node_device/node_device_linux_sysfs.c | 92 ++++------------------------- src/util/virutil.c | 67 +++++++++++++++++++++ src/util/virutil.h | 5 ++ 5 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d9b7c1d..2e83747 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1297,6 +1297,7 @@ virIsDevMapperDevice; virParseNumber; virParseVersionString; virPipeReadUntilEOF; +virReadFCHost; virScaleInteger; virSetBlocking; virSetCloseExec; diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index 26f0550..edd2915 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -59,14 +59,10 @@ int check_fc_host_linux(union _virNodeDevCapData *d); # define check_vport_capable(d) check_vport_capable_linux(d) int check_vport_capable_linux(union _virNodeDevCapData *d); -# define read_wwn(host, file, wwn) read_wwn_linux(host, file, wwn) -int read_wwn_linux(int host, const char *file, char **wwn); - # else /* __linux__ */ # define check_fc_host(d) (-1) # define check_vport_capable(d) (-1) -# define read_wwn(host, file, wwn) # endif /* __linux__ */ diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c index 9c305d3..742a0bc 100644 --- a/src/node_device/node_device_linux_sysfs.c +++ b/src/node_device/node_device_linux_sysfs.c @@ -37,77 +37,6 @@ #ifdef __linux__ -static int open_wwn_file(const char *prefix, - int host, - const char *file, - int *fd) -{ - int retval = 0; - char *wwn_path = NULL; - - if (virAsprintf(&wwn_path, "%s/host%d/%s", prefix, host, file) < 0) { - virReportOOMError(); - retval = -1; - goto out; - } - - /* fd will be closed by caller */ - if ((*fd = open(wwn_path, O_RDONLY)) != -1) { - VIR_DEBUG("Opened WWN path '%s' for reading", - wwn_path); - } else { - VIR_ERROR(_("Failed to open WWN path '%s' for reading"), - wwn_path); - } - -out: - VIR_FREE(wwn_path); - return retval; -} - - -int read_wwn_linux(int host, const char *file, char **wwn) -{ - char *p = NULL; - int fd = -1, retval = 0; - char buf[65] = ""; - - if (open_wwn_file(LINUX_SYSFS_FC_HOST_PREFIX, host, file, &fd) < 0) { - goto out; - } - - if (saferead(fd, buf, sizeof(buf) - 1) < 0) { - retval = -1; - VIR_DEBUG("Failed to read WWN for host%d '%s'", - host, file); - goto out; - } - - p = strstr(buf, "0x"); - if (p != NULL) { - p += strlen("0x"); - } else { - p = buf; - } - - *wwn = strndup(p, sizeof(buf)); - if (*wwn == NULL) { - virReportOOMError(); - retval = -1; - goto out; - } - - p = strchr(*wwn, '\n'); - if (p != NULL) { - *p = '\0'; - } - -out: - VIR_FORCE_CLOSE(fd); - return retval; -} - - int check_fc_host_linux(union _virNodeDevCapData *d) { char *sysfs_path = NULL; @@ -131,26 +60,29 @@ int check_fc_host_linux(union _virNodeDevCapData *d) d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST; - if (read_wwn(d->scsi_host.host, - "port_name", - &d->scsi_host.wwpn) == -1) { + if (virReadFCHost(NULL, + d->scsi_host.host, + "port_name", + &d->scsi_host.wwpn) == -1) { VIR_ERROR(_("Failed to read WWPN for host%d"), d->scsi_host.host); retval = -1; goto out; } - if (read_wwn(d->scsi_host.host, - "node_name", - &d->scsi_host.wwnn) == -1) { + if (virReadFCHost(NULL, + d->scsi_host.host, + "node_name", + &d->scsi_host.wwnn) == -1) { VIR_ERROR(_("Failed to read WWNN for host%d"), d->scsi_host.host); retval = -1; } - if (read_wwn(d->scsi_host.host, - "fabric_name", - &d->scsi_host.fabric_wwn) == -1) { + if (virReadFCHost(NULL, + d->scsi_host.host, + "fabric_name", + &d->scsi_host.fabric_wwn) == -1) { VIR_ERROR(_("Failed to read fabric WWN for host%d"), d->scsi_host.host); retval = -1; diff --git a/src/util/virutil.c b/src/util/virutil.c index 47ab17f..0f2cb4f 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -3269,3 +3269,70 @@ cleanup: VIR_FREE(buf); return ret; } + +#ifdef __linux__ +# define SYSFS_FC_HOST_PATH "/sys/class/fc_host/" + +/* virReadFCHost: + * @sysfs_prefix: "fc_host" sysfs path, defaults to SYSFS_FC_HOST_PATH + * @host: Host number, E.g. 5 of "fc_host/host5" + * @entry: Name of the sysfs entry to read + * @result: Return the entry value as string + * + * Read the value of sysfs "fc_host" entry. + * + * Returns 0 on success, and @result is filled with the entry value. + * as string, Otherwise returns -1. Caller must free @result after + * use. + */ +int +virReadFCHost(const char *sysfs_prefix, + int host, + const char *entry, + char **result) +{ + char *sysfs_path = NULL; + char *p = NULL; + int ret = -1; + char *buf = NULL; + + if (virAsprintf(&sysfs_path, "%s/host%d/%s", + sysfs_prefix ? sysfs_prefix : SYSFS_FC_HOST_PATH, + host, entry) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(sysfs_path, 1024, &buf) < 0) + goto cleanup; + + if ((p = strchr(buf, '\n'))) + *p = '\0'; + + if ((p = strstr(buf, "0x"))) + p += strlen("0x"); + else + p = buf; + + if (!(*result = strndup(p, sizeof(buf)))) { + virReportOOMError(); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(sysfs_path); + VIR_FREE(buf); + return ret; +} +#else +int +virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, + int host ATTRIBUTE_UNUSED, + const char *entry ATTRIBUTE_UNUSED, + char **result ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return -1; +} +#endif /* __linux__ */ diff --git a/src/util/virutil.h b/src/util/virutil.h index 5a08c81..373c48c 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -293,5 +293,10 @@ int virGetDeviceUnprivSGIO(const char *path, int *unpriv_sgio); char * virGetUnprivSGIOSysfsPath(const char *path, const char *sysfs_dir); +int virReadFCHost(const char *sysfs_prefix, + int host, + const char *entry, + char **result) + ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); #endif /* __VIR_UTIL_H__ */ -- 1.7.7.6

The use of 'stat' in nodeDeviceVportCreateDelete is only to check if the file exists or not, it's a bit overkill, and safe to replace with the wrapper of access(2) (virFileExists). --- src/node_device/node_device_driver.c | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 6134507..ef85af5 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -28,7 +28,6 @@ #include <errno.h> #include <fcntl.h> #include <time.h> -#include <sys/stat.h> #include "virerror.h" #include "datatypes.h" @@ -422,7 +421,6 @@ nodeDeviceVportCreateDelete(const int parent_host, int retval = 0; char *operation_path = NULL, *vport_name = NULL; const char *operation_file = NULL; - struct stat st; switch (operation) { case VPORT_CREATE: @@ -450,7 +448,7 @@ nodeDeviceVportCreateDelete(const int parent_host, goto cleanup; } - if (stat(operation_path, &st) != 0) { + if (!virFileExists(operation_path)) { VIR_FREE(operation_path); if (virAsprintf(&operation_path, "%shost%d%s", @@ -462,7 +460,7 @@ nodeDeviceVportCreateDelete(const int parent_host, goto cleanup; } - if (stat(operation_path, &st) != 0) { + if (!virFileExists(operation_path)) { VIR_ERROR(_("No vport operation path found for host%d"), parent_host); retval = -1; -- 1.7.7.6

This adds two util functions (virIsCapableFCHost and virIsCapableVport), and rename helper check_fc_host_linux as detect_scsi_host_caps, check_capable_vport_linux is removed, as it's abstracted to the util function virIsCapableVport. detect_scsi_host_caps nows detect both the fc_host and vport_ops capabilities. "stat(2)" is replaced with "access(2)" for saving. * src/util/virutil.h: - Declare virIsCapableFCHost and virIsCapableVport * src/util/virutil.c: - Implement virIsCapableFCHost and virIsCapableVport * src/node_device/node_device_linux_sysfs.c: - Remove check_capable_vport_linux - Rename check_fc_host_linux as detect_scsi_host_caps, and refactor it a bit to detect both fc_host and vport_os capabilities * src/node_device/node_device_driver.h: - Change/remove the related declarations * src/node_device/node_device_udev.c: (Use detect_scsi_host_caps) * src/node_device/node_device_hal.c: (Likewise) * src/node_device/node_device_driver.c (Likewise) --- src/libvirt_private.syms | 2 + src/node_device/node_device_driver.c | 7 +- src/node_device/node_device_driver.h | 10 +-- src/node_device/node_device_hal.c | 4 +- src/node_device/node_device_linux_sysfs.c | 135 ++++++++--------------------- src/node_device/node_device_udev.c | 3 +- src/util/virutil.c | 73 ++++++++++++++++ src/util/virutil.h | 3 + 8 files changed, 123 insertions(+), 114 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 2e83747..41c0d84 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1293,6 +1293,8 @@ virGetUserName; virGetUserRuntimeDirectory; virHexToBin; virIndexToDiskName; +virIsCapableFCHost; +virIsCapableVport; virIsDevMapperDevice; virParseNumber; virParseVersionString; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index ef85af5..db2f922 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -48,7 +48,7 @@ static int update_caps(virNodeDeviceObjPtr dev) while (cap) { /* The only caps that currently need updating are FC related. */ if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) { - check_fc_host(&dev->def->caps->data); + detect_scsi_host_caps(&dev->def->caps->data); } cap = cap->next; } @@ -241,18 +241,15 @@ nodeDeviceLookupByWWN(virConnectPtr conn, nodeDeviceLock(driver); for (i = 0; i < devs->count; i++) { - obj = devs->objs[i]; virNodeDeviceObjLock(obj); cap = obj->def->caps; while (cap) { - if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) { - check_fc_host(&cap->data); + detect_scsi_host_caps(&cap->data); if (cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) { - if (STREQ(cap->data.scsi_host.wwnn, wwnn) && STREQ(cap->data.scsi_host.wwpn, wwpn)) { dev = virGetNodeDevice(conn, obj->def->name); diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index edd2915..17bd020 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -53,16 +53,12 @@ int nodedevRegister(void); # ifdef __linux__ -# define check_fc_host(d) check_fc_host_linux(d) -int check_fc_host_linux(union _virNodeDevCapData *d); - -# define check_vport_capable(d) check_vport_capable_linux(d) -int check_vport_capable_linux(union _virNodeDevCapData *d); +# define detect_scsi_host_caps(d) detect_scsi_host_caps_linux(d) +int detect_scsi_host_caps_linux(union _virNodeDevCapData *d); # else /* __linux__ */ -# define check_fc_host(d) (-1) -# define check_vport_capable(d) (-1) +# define detect_scsi_host_caps(d) (-1) # endif /* __linux__ */ diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 33e0170..18cdab8 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -234,14 +234,12 @@ static int gather_scsi_host_cap(LibHalContext *ctx, const char *udi, (void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host); - retval = check_fc_host(d); + retval = detect_scsi_host_caps(d); if (retval == -1) { goto out; } - retval = check_vport_capable(d); - out: return retval; } diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c index 742a0bc..054afea 100644 --- a/src/node_device/node_device_linux_sysfs.c +++ b/src/node_device/node_device_linux_sysfs.c @@ -1,8 +1,8 @@ /* - * node_device_hal_linuc.c: Linux specific code to gather device data + * node_device_linux_sysfs.c: Linux specific code to gather device data * not available through HAL. * - * Copyright (C) 2009-2011 Red Hat, Inc. + * Copyright (C) 2009-2013 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 @@ -37,112 +37,53 @@ #ifdef __linux__ -int check_fc_host_linux(union _virNodeDevCapData *d) +int +detect_scsi_host_caps_linux(union _virNodeDevCapData *d) { - char *sysfs_path = NULL; - int retval = 0; - struct stat st; + int ret = -1; VIR_DEBUG("Checking if host%d is an FC HBA", d->scsi_host.host); - if (virAsprintf(&sysfs_path, "%shost%d", - LINUX_SYSFS_FC_HOST_PREFIX, - d->scsi_host.host) < 0) { - virReportOOMError(); - retval = -1; - goto out; + if (virIsCapableFCHost(NULL, d->scsi_host.host)) { + d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST; + + if (virReadFCHost(NULL, + d->scsi_host.host, + "port_name", + &d->scsi_host.wwpn) == -1) { + VIR_ERROR(_("Failed to read WWPN for host%d"), d->scsi_host.host); + goto cleanup; + } + + if (virReadFCHost(NULL, + d->scsi_host.host, + "node_name", + &d->scsi_host.wwnn) == -1) { + VIR_ERROR(_("Failed to read WWNN for host%d"), d->scsi_host.host); + goto cleanup; + } + + if (virReadFCHost(NULL, + d->scsi_host.host, + "fabric_name", + &d->scsi_host.fabric_wwn) == -1) { + VIR_ERROR(_("Failed to read fabric WWN for host%d"), + d->scsi_host.host); + goto cleanup; + } } - if (stat(sysfs_path, &st) != 0) { - /* Not an FC HBA; not an error, either. */ - goto out; - } - - d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST; - - if (virReadFCHost(NULL, - d->scsi_host.host, - "port_name", - &d->scsi_host.wwpn) == -1) { - VIR_ERROR(_("Failed to read WWPN for host%d"), - d->scsi_host.host); - retval = -1; - goto out; - } - - if (virReadFCHost(NULL, - d->scsi_host.host, - "node_name", - &d->scsi_host.wwnn) == -1) { - VIR_ERROR(_("Failed to read WWNN for host%d"), - d->scsi_host.host); - retval = -1; - } - - if (virReadFCHost(NULL, - d->scsi_host.host, - "fabric_name", - &d->scsi_host.fabric_wwn) == -1) { - VIR_ERROR(_("Failed to read fabric WWN for host%d"), - d->scsi_host.host); - retval = -1; - goto out; - } + if (virIsCapableVport(NULL, d->scsi_host.host) == 0) + d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS; -out: - if (retval == -1) { + ret = 0; +cleanup: + if (ret == -1) { VIR_FREE(d->scsi_host.wwnn); VIR_FREE(d->scsi_host.wwpn); VIR_FREE(d->scsi_host.fabric_wwn); } - VIR_FREE(sysfs_path); - return retval; -} - - -int check_vport_capable_linux(union _virNodeDevCapData *d) -{ - char *sysfs_path = NULL; - struct stat st; - int retval = 0; - - if (virAsprintf(&sysfs_path, - "%shost%d%s", - LINUX_SYSFS_FC_HOST_PREFIX, - d->scsi_host.host, - LINUX_SYSFS_VPORT_CREATE_POSTFIX) < 0) { - virReportOOMError(); - retval = -1; - goto out; - } - - if (stat(sysfs_path, &st) == 0) { - d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS; - goto out; - } - - VIR_FREE(sysfs_path); - if (virAsprintf(&sysfs_path, - "%shost%d%s", - LINUX_SYSFS_SCSI_HOST_PREFIX, - d->scsi_host.host, - LINUX_SYSFS_VPORT_CREATE_POSTFIX) < 0) { - virReportOOMError(); - retval = -1; - goto out; - } - - if (stat(sysfs_path, &st) == 0) { - d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS; - } else { - /* Not a vport capable HBA; not an error, either. */ - VIR_DEBUG("No vport operation path found for host%d", - d->scsi_host.host); - } - -out: - VIR_FREE(sysfs_path); - return retval; + return ret; } #endif /* __linux__ */ diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 4137488..87a2f61 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -663,8 +663,7 @@ static int udevProcessSCSIHost(struct udev_device *device ATTRIBUTE_UNUSED, goto out; } - check_fc_host(&def->caps->data); - check_vport_capable(&def->caps->data); + detect_scsi_host_caps(&def->caps->data); if (udevGenerateDeviceName(device, def, NULL) != 0) { goto out; diff --git a/src/util/virutil.c b/src/util/virutil.c index 0f2cb4f..95c5b81 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -3272,6 +3272,7 @@ cleanup: #ifdef __linux__ # define SYSFS_FC_HOST_PATH "/sys/class/fc_host/" +# define SYSFS_SCSI_HOST_PATH "/sys/class/scsi_host/" /* virReadFCHost: * @sysfs_prefix: "fc_host" sysfs path, defaults to SYSFS_FC_HOST_PATH @@ -3325,6 +3326,63 @@ cleanup: VIR_FREE(buf); return ret; } + +int +virIsCapableFCHost(const char *sysfs_prefix, + int host) +{ + char *sysfs_path = NULL; + int ret = -1; + + if (virAsprintf(&sysfs_path, "%shost%d", + sysfs_prefix ? sysfs_prefix : SYSFS_FC_HOST_PATH, + host) < 0) { + virReportOOMError(); + return -1; + } + + if (access(sysfs_path, F_OK) == 0) + ret = 0; + + VIR_FREE(sysfs_path); + return ret; +} + +int +virIsCapableVport(const char *sysfs_prefix, + int host) +{ + char *scsi_host_path = NULL; + char *fc_host_path = NULL; + int ret = -1; + + if (virAsprintf(&fc_host_path, + "%shost%d%s", + sysfs_prefix ? sysfs_prefix : SYSFS_FC_HOST_PATH, + host, + "vport_create") < 0) { + virReportOOMError(); + return -1; + } + + if (virAsprintf(&scsi_host_path, + "%shost%d%s", + sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_HOST_PATH, + host, + "vport_create") < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((access(fc_host_path, F_OK) == 0) || + (access(scsi_host_path, F_OK) == 0)) + ret = 0; + +cleanup: + VIR_FREE(fc_host_path); + VIR_FREE(scsi_host_path); + return ret; +} #else int virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, @@ -3335,4 +3393,19 @@ virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); return -1; } + +int +virIsCapableFCHost(int host ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return -1; +} + +int +virIsCapbleVport(const char *sysfs_prefix ATTRIBUTE_UNUSED, + int host ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return -1; +} #endif /* __linux__ */ diff --git a/src/util/virutil.h b/src/util/virutil.h index 373c48c..d87aa92 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -299,4 +299,7 @@ int virReadFCHost(const char *sysfs_prefix, char **result) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); +int virIsCapableFCHost(const char *sysfs_prefix, int host); +int virIsCapableVport(const char *sysfs_prefix, int host); + #endif /* __VIR_UTIL_H__ */ -- 1.7.7.6

This enrichs HBA's xml by dumping the number of max vports and vports in use. Format is like: <capability type='vport_ops'> <max_vports>164</max_vports> <vports>5</vports> </capability> * docs/formatnode.html.in: (Document the new XML) * docs/schemas/nodedev.rng: (Add the schema) * src/conf/node_device_conf.h: (New member for data.scsi_host) * src/node_device/node_device_linux_sysfs.c: (Collect the value of max_vports and vports) --- docs/formatnode.html.in | 10 ++++-- docs/schemas/nodedev.rng | 6 +++ src/conf/node_device_conf.c | 7 +++- src/conf/node_device_conf.h | 2 + src/node_device/node_device_linux_sysfs.c | 48 ++++++++++++++++++++++++++-- 5 files changed, 65 insertions(+), 8 deletions(-) diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in index fcaaaaf..5712bcf 100644 --- a/docs/formatnode.html.in +++ b/docs/formatnode.html.in @@ -136,9 +136,13 @@ <dd>The SCSI host number.</dd> <dt><code>capability</code></dt> <dd>Current capabilities include "vports_ops" (indicates - vport operations are supported) and "fc_host", the later - implies following sub-elements: <code>wwnn</code>, - <code>wwpn</code>, <code>fabric_wwn</code>. + vport operations are supported) and "fc_host". "vport_ops" + could contain two optional sub-elements: <code>vports</code>, + and <code>max_vports</code>. <code>vports</code> shows the + number of vport in use. <code>max_vports</code> shows the + maximum vports the HBA supports. "fc_host" implies following + sub-elements: <code>wwnn</code>, <code>wwpn</code>, and + <code>fabric_wwn</code>. </dd> </dl> </dd> diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng index 7c85815..b94cce6 100644 --- a/docs/schemas/nodedev.rng +++ b/docs/schemas/nodedev.rng @@ -267,6 +267,12 @@ <attribute name='type'> <value>vports_ops</value> </attribute> + <element name='max_vports'> + <ref name='unsignedInt'/> + </element> + <element name='vports'> + <ref name='unsignedInt'/> + </element> </define> <define name='capscsihost'> diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 819e6af..5962d58 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -392,7 +392,12 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDefPtr def) virBufferAddLit(&buf, " </capability>\n"); } if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) { - virBufferAddLit(&buf, " <capability type='vport_ops' />\n"); + virBufferAddLit(&buf, " <capability type='vport_ops'>\n"); + virBufferAsprintf(&buf, " <max_vports>%d</max_vports>\n", + data->scsi_host.max_vports); + virBufferAsprintf(&buf, " <vports>%d</vports>\n", + data->scsi_host.vports); + virBufferAddLit(&buf, " </capability>\n"); } break; diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 145d699..4e584a3 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -137,6 +137,8 @@ struct _virNodeDevCapsDef { char *wwpn; char *fabric_wwn; unsigned int flags; + int max_vports; + int vports; } scsi_host; struct { char *name; diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c index 054afea..b498726 100644 --- a/src/node_device/node_device_linux_sysfs.c +++ b/src/node_device/node_device_linux_sysfs.c @@ -40,6 +40,8 @@ int detect_scsi_host_caps_linux(union _virNodeDevCapData *d) { + char *max_vports = NULL; + char *vports = NULL; int ret = -1; VIR_DEBUG("Checking if host%d is an FC HBA", d->scsi_host.host); @@ -50,7 +52,7 @@ detect_scsi_host_caps_linux(union _virNodeDevCapData *d) if (virReadFCHost(NULL, d->scsi_host.host, "port_name", - &d->scsi_host.wwpn) == -1) { + &d->scsi_host.wwpn) < 0) { VIR_ERROR(_("Failed to read WWPN for host%d"), d->scsi_host.host); goto cleanup; } @@ -58,7 +60,7 @@ detect_scsi_host_caps_linux(union _virNodeDevCapData *d) if (virReadFCHost(NULL, d->scsi_host.host, "node_name", - &d->scsi_host.wwnn) == -1) { + &d->scsi_host.wwnn) < 0) { VIR_ERROR(_("Failed to read WWNN for host%d"), d->scsi_host.host); goto cleanup; } @@ -66,23 +68,61 @@ detect_scsi_host_caps_linux(union _virNodeDevCapData *d) if (virReadFCHost(NULL, d->scsi_host.host, "fabric_name", - &d->scsi_host.fabric_wwn) == -1) { + &d->scsi_host.fabric_wwn) < 0) { VIR_ERROR(_("Failed to read fabric WWN for host%d"), d->scsi_host.host); goto cleanup; } } - if (virIsCapableVport(NULL, d->scsi_host.host) == 0) + if (virIsCapableVport(NULL, d->scsi_host.host) == 0) { d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS; + if (virReadFCHost(NULL, + d->scsi_host.max_vports, + "max_npiv_vports", + &max_vports) < 0) { + VIR_ERROR(_("Failed to read max_npiv_vports for host%d"), + d->scsi_host.host); + goto cleanup; + } + + if (virReadFCHost(NULL, + d->scsi_host.max_vports, + "npiv_vports_inuse", + &vports) < 0) { + VIR_ERROR(_("Failed to read npiv_vports_inuse for host%d"), + d->scsi_host.host); + goto cleanup; + } + + if (virStrToLong_i(max_vports, NULL, 10, + &d->scsi_host.max_vports) < 0) { + VIR_ERROR(_("Failed to parse value of max_npiv_vports '%s'"), + max_vports); + goto cleanup; + } + + if (virStrToLong_i(vports, NULL, 10, + &d->scsi_host.vports) < 0) { + VIR_ERROR(_("Failed to parse value of npiv_vports_inuse '%s'"), + vports); + goto cleanup; + } + } + ret = 0; cleanup: if (ret == -1) { + /* Clear the flags in case of producing confusing XML output */ + d->scsi_host.flags = 0; + VIR_FREE(d->scsi_host.wwnn); VIR_FREE(d->scsi_host.wwpn); VIR_FREE(d->scsi_host.fabric_wwn); } + VIR_FREE(max_vports); + VIR_FREE(vports); return ret; } -- 1.7.7.6

pciGetVirtualFunctions returns 0 even if there is no "virtfn" entry under the device sysfs path. And pciGetVirtualFunctions returns -1 when it fails to get the PCI config space of one VF, however, with keeping the the VFs already detected. That's why udevProcessPCI and gather_pci_cap use logic like: if (!pciGetVirtualFunctions(syspath, &data->pci_dev.virtual_functions, &data->pci_dev.num_virtual_functions) || data->pci_dev.num_virtual_functions > 0) data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; to tag the PCI device with "virtual_function" cap. However, this results in a VF will aslo get "virtual_function" cap. This patch fixes it by: * Ignoring the VF which has failure of getting PCI config space (given that the successfully detected VFs are kept , it makes sense to not give up on the failure of one VF too) with a warning, so pciGetVirtualFunctions will not return -1 except out of memory. * Free the allocated *virtual_functions when out of memory And thus the logic can be changed to: /* Out of memory */ int rc = pciGetVirtualFunctions(syspath, &data->pci_dev.virtual_functions, &data->pci_dev.num_virtual_functions); if (ret < 0 ) goto out; else if (!ret && (data->pci_dev.num_virtual_functions > 0)) data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; --- src/node_device/node_device_hal.c | 11 ++++++++--- src/node_device/node_device_udev.c | 11 ++++++++--- src/util/virpci.c | 36 +++++++++++++++++++++++------------- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 18cdab8..b7f2d02 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -151,10 +151,15 @@ static int gather_pci_cap(LibHalContext *ctx, const char *udi, if (!pciGetPhysicalFunction(sysfs_path, &d->pci_dev.physical_function)) d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; - if (!pciGetVirtualFunctions(sysfs_path, &d->pci_dev.virtual_functions, - &d->pci_dev.num_virtual_functions) || - d->pci_dev.num_virtual_functions > 0) + int ret = pciGetVirtualFunctions(sysfs_path, + &d->pci_dev.virtual_functions, + &d->pci_dev.num_virtual_functions); + if (ret < 0) { + VIR_FREE(sysfs_path); + return -1; + } else if (!ret && (d->pci_dev.num_virtual_functions > 0)) { d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; + } VIR_FREE(sysfs_path); } diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 87a2f61..73d0cf5 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -416,6 +416,7 @@ static int udevProcessPCI(struct udev_device *device, union _virNodeDevCapData *data = &def->caps->data; int ret = -1; char *p; + int rc; syspath = udev_device_get_syspath(device); @@ -484,9 +485,13 @@ static int udevProcessPCI(struct udev_device *device, if (!pciGetPhysicalFunction(syspath, &data->pci_dev.physical_function)) data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION; - if (!pciGetVirtualFunctions(syspath, &data->pci_dev.virtual_functions, - &data->pci_dev.num_virtual_functions) || - data->pci_dev.num_virtual_functions > 0) + rc = pciGetVirtualFunctions(syspath, + &data->pci_dev.virtual_functions, + &data->pci_dev.num_virtual_functions); + /* Out of memory */ + if (rc < 0) + goto out; + else if (!rc && (data->pci_dev.num_virtual_functions > 0)) data->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION; ret = 0; diff --git a/src/util/virpci.c b/src/util/virpci.c index 4b26452..1e087e7 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -1990,6 +1990,7 @@ pciGetVirtualFunctions(const char *sysfs_path, unsigned int *num_virtual_functions) { int ret = -1; + int i; DIR *dir = NULL; struct dirent *entry = NULL; char *device_link = NULL; @@ -2011,6 +2012,7 @@ pciGetVirtualFunctions(const char *sysfs_path, *num_virtual_functions = 0; while ((entry = readdir(dir))) { if (STRPREFIX(entry->d_name, "virtfn")) { + struct pci_config_address *config_addr = NULL; if (virBuildPath(&device_link, sysfs_path, entry->d_name) == -1) { virReportOOMError(); @@ -2019,24 +2021,23 @@ pciGetVirtualFunctions(const char *sysfs_path, VIR_DEBUG("Number of virtual functions: %d", *num_virtual_functions); - if (VIR_REALLOC_N(*virtual_functions, - (*num_virtual_functions) + 1) != 0) { - virReportOOMError(); - VIR_FREE(device_link); - goto out; - } if (pciGetPciConfigAddressFromSysfsDeviceLink(device_link, - &((*virtual_functions)[*num_virtual_functions])) != + &config_addr) != SRIOV_FOUND) { - /* We should not get back SRIOV_NOT_FOUND in this - * case, so if we do, it's an error. */ - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to get SR IOV function from device " - "link '%s'"), device_link); + VIR_WARN("Failed to get SRIOV function from device " + "link '%s'", device_link); VIR_FREE(device_link); - goto out; + continue; } else { + if (VIR_ALLOC_N(*virtual_functions, + *num_virtual_functions + 1) < 0) { + virReportOOMError(); + VIR_FREE(config_addr); + goto out; + } + + (*virtual_functions)[*num_virtual_functions] = config_addr; (*num_virtual_functions)++; } VIR_FREE(device_link); @@ -2044,8 +2045,17 @@ pciGetVirtualFunctions(const char *sysfs_path, } ret = 0; + goto cleanup; out: + if (*virtual_functions) { + for (i = 0; i < *num_virtual_functions; i++) + VIR_FREE((*virtual_functions)[i]); + VIR_FREE(*virtual_functions); + } + +cleanup: + VIR_FREE(device_link); if (dir) closedir(dir); -- 1.7.7.6

This abstracts nodeDeviceVportCreateDelete as an util function virManageVport, which can be further used by later storage patches (to support persistent vHBA, I don't want to create the vHBA using the public API, that's awkful). --- src/libvirt_private.syms | 1 + src/node_device/node_device_driver.c | 101 +++------------------------------- src/node_device/node_device_driver.h | 5 -- src/util/virutil.c | 84 ++++++++++++++++++++++++++++ src/util/virutil.h | 11 ++++ 5 files changed, 104 insertions(+), 98 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 41c0d84..90e16f3 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1296,6 +1296,7 @@ virIndexToDiskName; virIsCapableFCHost; virIsCapableVport; virIsDevMapperDevice; +virManageVport; virParseNumber; virParseVersionString; virPipeReadUntilEOF; diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index db2f922..75b07c5 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -408,91 +408,6 @@ cleanup: return ret; } - -static int -nodeDeviceVportCreateDelete(const int parent_host, - const char *wwpn, - const char *wwnn, - int operation) -{ - int retval = 0; - char *operation_path = NULL, *vport_name = NULL; - const char *operation_file = NULL; - - switch (operation) { - case VPORT_CREATE: - operation_file = LINUX_SYSFS_VPORT_CREATE_POSTFIX; - break; - case VPORT_DELETE: - operation_file = LINUX_SYSFS_VPORT_DELETE_POSTFIX; - break; - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Invalid vport operation (%d)"), operation); - retval = -1; - goto cleanup; - break; - } - - if (virAsprintf(&operation_path, - "%shost%d%s", - LINUX_SYSFS_FC_HOST_PREFIX, - parent_host, - operation_file) < 0) { - - virReportOOMError(); - retval = -1; - goto cleanup; - } - - if (!virFileExists(operation_path)) { - VIR_FREE(operation_path); - if (virAsprintf(&operation_path, - "%shost%d%s", - LINUX_SYSFS_SCSI_HOST_PREFIX, - parent_host, - operation_file) < 0) { - virReportOOMError(); - retval = -1; - goto cleanup; - } - - if (!virFileExists(operation_path)) { - VIR_ERROR(_("No vport operation path found for host%d"), - parent_host); - retval = -1; - goto cleanup; - } - } - - VIR_DEBUG("Vport operation path is '%s'", operation_path); - - if (virAsprintf(&vport_name, - "%s:%s", - wwpn, - wwnn) < 0) { - - virReportOOMError(); - retval = -1; - goto cleanup; - } - - if (virFileWriteStr(operation_path, vport_name, 0) == -1) { - virReportSystemError(errno, - _("Write of '%s' to '%s' during " - "vport create/delete failed"), - vport_name, operation_path); - retval = -1; - } - -cleanup: - VIR_FREE(vport_name); - VIR_FREE(operation_path); - VIR_DEBUG("%s", _("Vport operation complete")); - return retval; -} - - static int get_time(time_t *t) { @@ -594,10 +509,10 @@ nodeDeviceCreateXML(virConnectPtr conn, goto cleanup; } - if (nodeDeviceVportCreateDelete(parent_host, - wwpn, - wwnn, - VPORT_CREATE) == -1) { + if (virManageVport(parent_host, + wwpn, + wwnn, + VPORT_CREATE) == -1) { goto cleanup; } @@ -661,10 +576,10 @@ nodeDeviceDestroy(virNodeDevicePtr dev) goto out; } - if (nodeDeviceVportCreateDelete(parent_host, - wwpn, - wwnn, - VPORT_DELETE) == -1) { + if (virManageVport(parent_host, + wwpn, + wwnn, + VPORT_DELETE) == -1) { goto out; } diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h index 17bd020..d5f5ded 100644 --- a/src/node_device/node_device_driver.h +++ b/src/node_device/node_device_driver.h @@ -32,11 +32,6 @@ # define LINUX_SYSFS_SCSI_HOST_POSTFIX "device" # define LINUX_SYSFS_FC_HOST_PREFIX "/sys/class/fc_host/" -# define VPORT_CREATE 0 -# define VPORT_DELETE 1 -# define LINUX_SYSFS_VPORT_CREATE_POSTFIX "/vport_create" -# define LINUX_SYSFS_VPORT_DELETE_POSTFIX "/vport_delete" - # define LINUX_NEW_DEVICE_WAIT_TIME 60 # ifdef HAVE_HAL diff --git a/src/util/virutil.c b/src/util/virutil.c index 95c5b81..f804521 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -3383,6 +3383,79 @@ cleanup: VIR_FREE(scsi_host_path); return ret; } + +int +virManageVport(const int parent_host, + const char *wwpn, + const char *wwnn, + int operation) +{ + int ret = -1; + char *operation_path = NULL, *vport_name = NULL; + const char *operation_file = NULL; + + switch (operation) { + case VPORT_CREATE: + operation_file = "vport_create"; + break; + case VPORT_DELETE: + operation_file = "vport_delete"; + break; + default: + virReportError(VIR_ERR_OPERATION_INVALID, + _("Invalid vport operation (%d)"), operation); + goto cleanup; + } + + if (virAsprintf(&operation_path, + "%shost%d%s", + SYSFS_FC_HOST_PATH, + parent_host, + operation_file) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (!virFileExists(operation_path)) { + VIR_FREE(operation_path); + if (virAsprintf(&operation_path, + "%shost%d%s", + SYSFS_SCSI_HOST_PATH, + parent_host, + operation_file) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (!virFileExists(operation_path)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("vport operation '%s' is not supported for host%d"), + operation_file, parent_host); + goto cleanup; + } + } + + if (virAsprintf(&vport_name, + "%s:%s", + wwpn, + wwnn) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileWriteStr(operation_path, vport_name, 0) == 0) + ret = 0; + else + virReportSystemError(errno, + _("Write of '%s' to '%s' during " + "vport create/delete failed"), + vport_name, operation_path); + +cleanup: + VIR_FREE(vport_name); + VIR_FREE(operation_path); + return ret; +} #else int virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, @@ -3408,4 +3481,15 @@ virIsCapbleVport(const char *sysfs_prefix ATTRIBUTE_UNUSED, virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); return -1; } + +int +virManageVport(const int parent_host ATTRIBUTE_UNUSED, + const char *wwpn ATTRIBUTE_UNUSED, + const char *wwnn ATTRIBUTE_UNUSED, + int operation ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return -1; +} + #endif /* __linux__ */ diff --git a/src/util/virutil.h b/src/util/virutil.h index d87aa92..c07417c 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -302,4 +302,15 @@ int virReadFCHost(const char *sysfs_prefix, int virIsCapableFCHost(const char *sysfs_prefix, int host); int virIsCapableVport(const char *sysfs_prefix, int host); +enum { + VPORT_CREATE, + VPORT_DELETE, +}; + +int virManageVport(const int parent_host, + const char *wwpn, + const char *wwnn, + int operation) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + #endif /* __VIR_UTIL_H__ */ -- 1.7.7.6
participants (2)
-
Daniel P. Berrange
-
Osier Yang