mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
util: Move scsi_host specific functions from virutil
Create a virscsihost.c and place the functions there. That removes the last #ifdef __linux__ from virutil.c. Take the opporunity to also change the function names and in one case the parameters slightly
This commit is contained in:
parent
d2d74a986d
commit
03346def06
@ -242,6 +242,7 @@ src/util/virqemu.c
|
||||
src/util/virrandom.c
|
||||
src/util/virrotatingfile.c
|
||||
src/util/virscsi.c
|
||||
src/util/virscsihost.c
|
||||
src/util/virscsivhost.c
|
||||
src/util/virsecret.c
|
||||
src/util/virsexpr.c
|
||||
|
@ -164,6 +164,7 @@ UTIL_SOURCES = \
|
||||
util/virrandom.h util/virrandom.c \
|
||||
util/virrotatingfile.h util/virrotatingfile.c \
|
||||
util/virscsi.c util/virscsi.h \
|
||||
util/virscsihost.c util/virscsihost.h \
|
||||
util/virscsivhost.c util/virscsivhost.h \
|
||||
util/virseclabel.c util/virseclabel.h \
|
||||
util/virsecret.c util/virsecret.h \
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "virbuffer.h"
|
||||
#include "viralloc.h"
|
||||
#include "virfile.h"
|
||||
#include "virscsihost.h"
|
||||
#include "virstring.h"
|
||||
#include "virlog.h"
|
||||
#include "virvhba.h"
|
||||
@ -2289,16 +2290,16 @@ getSCSIHostNumber(virStoragePoolSourceAdapter adapter,
|
||||
virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr;
|
||||
unsigned int unique_id = adapter.data.scsi_host.unique_id;
|
||||
|
||||
if (!(name = virGetSCSIHostNameByParentaddr(addr.domain,
|
||||
if (!(name = virSCSIHostGetNameByParentaddr(addr.domain,
|
||||
addr.bus,
|
||||
addr.slot,
|
||||
addr.function,
|
||||
unique_id)))
|
||||
goto cleanup;
|
||||
if (virGetSCSIHostNumber(name, &num) < 0)
|
||||
if (virSCSIHostGetNumber(name, &num) < 0)
|
||||
goto cleanup;
|
||||
} else {
|
||||
if (virGetSCSIHostNumber(adapter.data.scsi_host.name, &num) < 0)
|
||||
if (virSCSIHostGetNumber(adapter.data.scsi_host.name, &num) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -2310,6 +2311,21 @@ getSCSIHostNumber(virStoragePoolSourceAdapter adapter,
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
virStorageIsSameHostnum(const char *name,
|
||||
unsigned int scsi_hostnum)
|
||||
{
|
||||
unsigned int fc_hostnum;
|
||||
|
||||
if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 &&
|
||||
scsi_hostnum == fc_hostnum)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* matchFCHostToSCSIHost:
|
||||
*
|
||||
@ -2328,14 +2344,12 @@ matchFCHostToSCSIHost(virConnectPtr conn,
|
||||
char *name = NULL;
|
||||
char *scsi_host_name = NULL;
|
||||
char *parent_name = NULL;
|
||||
unsigned int fc_hostnum;
|
||||
|
||||
/* If we have a parent defined, get its hostnum, and compare to the
|
||||
* scsi_hostnum. If they are the same, then we have a match
|
||||
*/
|
||||
if (fc_adapter.data.fchost.parent &&
|
||||
virGetSCSIHostNumber(fc_adapter.data.fchost.parent, &fc_hostnum) == 0 &&
|
||||
scsi_hostnum == fc_hostnum)
|
||||
virStorageIsSameHostnum(fc_adapter.data.fchost.parent, scsi_hostnum))
|
||||
return true;
|
||||
|
||||
/* If we find an fc_adapter name, then either libvirt created a vHBA
|
||||
@ -2347,11 +2361,11 @@ matchFCHostToSCSIHost(virConnectPtr conn,
|
||||
/* Get the scsi_hostN for the vHBA in order to see if it
|
||||
* matches our scsi_hostnum
|
||||
*/
|
||||
if (virGetSCSIHostNumber(name, &fc_hostnum) == 0 &&
|
||||
scsi_hostnum == fc_hostnum) {
|
||||
if (virStorageIsSameHostnum(name, scsi_hostnum)) {
|
||||
VIR_FREE(name);
|
||||
return true;
|
||||
}
|
||||
VIR_FREE(name);
|
||||
|
||||
/* We weren't provided a parent, so we have to query the node
|
||||
* device driver in order to ascertain the parent of the vHBA.
|
||||
@ -2366,10 +2380,8 @@ matchFCHostToSCSIHost(virConnectPtr conn,
|
||||
if ((parent_name = virNodeDeviceGetParentName(conn,
|
||||
scsi_host_name))) {
|
||||
VIR_FREE(scsi_host_name);
|
||||
if (virGetSCSIHostNumber(parent_name, &fc_hostnum) == 0 &&
|
||||
scsi_hostnum == fc_hostnum) {
|
||||
if (virStorageIsSameHostnum(parent_name, scsi_hostnum)) {
|
||||
VIR_FREE(parent_name);
|
||||
VIR_FREE(name);
|
||||
return true;
|
||||
}
|
||||
VIR_FREE(parent_name);
|
||||
@ -2380,7 +2392,6 @@ matchFCHostToSCSIHost(virConnectPtr conn,
|
||||
VIR_FREE(scsi_host_name);
|
||||
}
|
||||
}
|
||||
VIR_FREE(name);
|
||||
}
|
||||
|
||||
/* NB: Lack of a name means that this vHBA hasn't yet been created,
|
||||
|
@ -2354,6 +2354,12 @@ virSCSIDeviceNew;
|
||||
virSCSIDeviceSetUsedBy;
|
||||
|
||||
|
||||
# util/virscsihost.h
|
||||
virSCSIHostFindByPCI;
|
||||
virSCSIHostGetNameByParentaddr;
|
||||
virSCSIHostGetNumber;
|
||||
virSCSIHostGetUniqueId;
|
||||
|
||||
# util/virscsivhost.h
|
||||
virSCSIVHostDeviceFileIterate;
|
||||
virSCSIVHostDeviceFree;
|
||||
@ -2679,7 +2685,6 @@ virUSBDeviceSetUsedBy;
|
||||
virDoubleToStr;
|
||||
virEnumFromString;
|
||||
virEnumToString;
|
||||
virFindSCSIHostByPCI;
|
||||
virFormatIntDecimal;
|
||||
virGetDeviceID;
|
||||
virGetDeviceUnprivSGIO;
|
||||
@ -2691,8 +2696,6 @@ virGetGroupName;
|
||||
virGetHostname;
|
||||
virGetHostnameQuiet;
|
||||
virGetListenFDs;
|
||||
virGetSCSIHostNameByParentaddr;
|
||||
virGetSCSIHostNumber;
|
||||
virGetSelfLastChanged;
|
||||
virGetSystemPageSize;
|
||||
virGetSystemPageSizeKB;
|
||||
@ -2716,7 +2719,6 @@ virParseNumber;
|
||||
virParseOwnershipIds;
|
||||
virParseVersionString;
|
||||
virPipeReadUntilEOF;
|
||||
virReadSCSIUniqueId;
|
||||
virScaleInteger;
|
||||
virSetBlocking;
|
||||
virSetCloseExec;
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "viralloc.h"
|
||||
#include "virlog.h"
|
||||
#include "virfile.h"
|
||||
#include "virscsihost.h"
|
||||
#include "virstring.h"
|
||||
#include "virvhba.h"
|
||||
|
||||
@ -48,8 +49,8 @@ nodeDeviceSysfsGetSCSIHostCaps(virNodeDevCapDataPtr d)
|
||||
char *tmp = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (virReadSCSIUniqueId(NULL, d->scsi_host.host,
|
||||
&d->scsi_host.unique_id) < 0) {
|
||||
if ((d->scsi_host.unique_id =
|
||||
virSCSIHostGetUniqueId(NULL, d->scsi_host.host)) < 0) {
|
||||
VIR_DEBUG("Failed to read unique_id for host%d", d->scsi_host.host);
|
||||
d->scsi_host.unique_id = -1;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "virlog.h"
|
||||
#include "virfile.h"
|
||||
#include "vircommand.h"
|
||||
#include "virscsihost.h"
|
||||
#include "virstring.h"
|
||||
#include "virvhba.h"
|
||||
#include "storage_util.h"
|
||||
@ -160,7 +161,7 @@ virStoragePoolFCRefreshThread(void *opaque)
|
||||
pool->def->allocation = pool->def->capacity = pool->def->available = 0;
|
||||
|
||||
if (virStoragePoolObjIsActive(pool) &&
|
||||
virGetSCSIHostNumber(fchost_name, &host) == 0 &&
|
||||
virSCSIHostGetNumber(fchost_name, &host) == 0 &&
|
||||
virStorageBackendSCSITriggerRescan(host) == 0) {
|
||||
virStoragePoolObjClearVols(pool);
|
||||
found = virStorageBackendSCSIFindLUs(pool, host);
|
||||
@ -185,7 +186,7 @@ getAdapterName(virStoragePoolSourceAdapter adapter)
|
||||
virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr;
|
||||
unsigned int unique_id = adapter.data.scsi_host.unique_id;
|
||||
|
||||
if (!(name = virGetSCSIHostNameByParentaddr(addr.domain,
|
||||
if (!(name = virSCSIHostGetNameByParentaddr(addr.domain,
|
||||
addr.bus,
|
||||
addr.slot,
|
||||
addr.function,
|
||||
@ -318,7 +319,7 @@ createVport(virConnectPtr conn,
|
||||
skip_capable_check = true;
|
||||
}
|
||||
|
||||
if (virGetSCSIHostNumber(parent_hoststr, &parent_host) < 0)
|
||||
if (virSCSIHostGetNumber(parent_hoststr, &parent_host) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* NOTE:
|
||||
@ -420,7 +421,7 @@ deleteVport(virConnectPtr conn,
|
||||
* the parent scsi_host which we did not save at startup time
|
||||
*/
|
||||
if (adapter.data.fchost.parent) {
|
||||
if (virGetSCSIHostNumber(adapter.data.fchost.parent, &parent_host) < 0)
|
||||
if (virSCSIHostGetNumber(adapter.data.fchost.parent, &parent_host) < 0)
|
||||
goto cleanup;
|
||||
} else {
|
||||
if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
|
||||
@ -429,7 +430,7 @@ deleteVport(virConnectPtr conn,
|
||||
if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name)))
|
||||
goto cleanup;
|
||||
|
||||
if (virGetSCSIHostNumber(vhba_parent, &parent_host) < 0)
|
||||
if (virSCSIHostGetNumber(vhba_parent, &parent_host) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -471,7 +472,7 @@ virStorageBackendSCSICheckPool(virStoragePoolObjPtr pool,
|
||||
}
|
||||
}
|
||||
|
||||
if (virGetSCSIHostNumber(name, &host) < 0)
|
||||
if (virSCSIHostGetNumber(name, &host) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virAsprintf(&path, "%s/host%d",
|
||||
@ -500,7 +501,7 @@ virStorageBackendSCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
if (!(name = getAdapterName(pool->def->source.adapter)))
|
||||
return -1;
|
||||
|
||||
if (virGetSCSIHostNumber(name, &host) < 0)
|
||||
if (virSCSIHostGetNumber(name, &host) < 0)
|
||||
goto out;
|
||||
|
||||
VIR_DEBUG("Scanning host%u", host);
|
||||
|
297
src/util/virscsihost.c
Normal file
297
src/util/virscsihost.c
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* virscsihost.c: Generic scsi_host management utility functions
|
||||
*
|
||||
* 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 <dirent.h>
|
||||
|
||||
#include "viralloc.h"
|
||||
#include "virerror.h"
|
||||
#include "virfile.h"
|
||||
#include "virlog.h"
|
||||
#include "virscsihost.h"
|
||||
#include "virstring.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||
|
||||
VIR_LOG_INIT("util.scsi_host");
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
# define SYSFS_SCSI_HOST_PATH "/sys/class/scsi_host"
|
||||
|
||||
/* virSCSIHostGetUniqueId:
|
||||
* @sysfs_prefix: "scsi_host" sysfs path, defaults to SYSFS_SCSI_HOST_PATH
|
||||
* @host: Host number, E.g. 5 of "scsi_host/host5"
|
||||
*
|
||||
* Read the value of the "scsi_host" unique_id file.
|
||||
*
|
||||
* Returns the value on success or -1 on failure.
|
||||
*/
|
||||
int
|
||||
virSCSIHostGetUniqueId(const char *sysfs_prefix,
|
||||
int host)
|
||||
{
|
||||
char *sysfs_path = NULL;
|
||||
char *p = NULL;
|
||||
int ret = -1;
|
||||
char *buf = NULL;
|
||||
int unique_id;
|
||||
|
||||
if (virAsprintf(&sysfs_path, "%s/host%d/unique_id",
|
||||
sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_HOST_PATH,
|
||||
host) < 0)
|
||||
return -1;
|
||||
|
||||
if (virFileReadAll(sysfs_path, 1024, &buf) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((p = strchr(buf, '\n')))
|
||||
*p = '\0';
|
||||
|
||||
if (virStrToLong_i(buf, NULL, 10, &unique_id) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unable to parse unique_id: %s"), buf);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = unique_id;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(sysfs_path);
|
||||
VIR_FREE(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* virSCSIHostFindByPCI:
|
||||
* @sysfs_prefix: "scsi_host" sysfs path, defaults to SYSFS_SCSI_HOST_PATH
|
||||
* @parentaddr: string of the PCI address "scsi_host" device to be found
|
||||
* @unique_id: unique_id value of the to be found "scsi_host" device
|
||||
* @result: Return the host# of the matching "scsi_host" device
|
||||
*
|
||||
* Iterate over the SYSFS_SCSI_HOST_PATH entries looking for a matching
|
||||
* PCI Address in the expected format (dddd:bb:ss.f, where 'dddd' is the
|
||||
* 'domain' value, 'bb' is the 'bus' value, 'ss' is the 'slot' value, and
|
||||
* 'f' is the 'function' value from the PCI address) with a unique_id file
|
||||
* entry having the value expected. Unlike virReadSCSIUniqueId() we don't
|
||||
* have a host number yet and that's what we're looking for.
|
||||
*
|
||||
* Returns the host name of the "scsi_host" which must be freed by the caller,
|
||||
* or NULL on failure
|
||||
*/
|
||||
char *
|
||||
virSCSIHostFindByPCI(const char *sysfs_prefix,
|
||||
const char *parentaddr,
|
||||
unsigned int unique_id)
|
||||
{
|
||||
const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_HOST_PATH;
|
||||
struct dirent *entry = NULL;
|
||||
DIR *dir = NULL;
|
||||
char *host_link = NULL;
|
||||
char *host_path = NULL;
|
||||
char *p = NULL;
|
||||
char *ret = NULL;
|
||||
char *buf = NULL;
|
||||
char *unique_path = NULL;
|
||||
unsigned int read_unique_id;
|
||||
|
||||
if (virDirOpen(&dir, prefix) < 0)
|
||||
return NULL;
|
||||
|
||||
while (virDirRead(dir, &entry, prefix) > 0) {
|
||||
if (!virFileIsLink(entry->d_name))
|
||||
continue;
|
||||
|
||||
if (virAsprintf(&host_link, "%s/%s", prefix, entry->d_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virFileResolveLink(host_link, &host_path) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!strstr(host_path, parentaddr)) {
|
||||
VIR_FREE(host_link);
|
||||
VIR_FREE(host_path);
|
||||
continue;
|
||||
}
|
||||
VIR_FREE(host_link);
|
||||
VIR_FREE(host_path);
|
||||
|
||||
if (virAsprintf(&unique_path, "%s/%s/unique_id", prefix,
|
||||
entry->d_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!virFileExists(unique_path)) {
|
||||
VIR_FREE(unique_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (virFileReadAll(unique_path, 1024, &buf) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((p = strchr(buf, '\n')))
|
||||
*p = '\0';
|
||||
|
||||
if (virStrToLong_ui(buf, NULL, 10, &read_unique_id) < 0)
|
||||
goto cleanup;
|
||||
|
||||
VIR_FREE(buf);
|
||||
|
||||
if (read_unique_id != unique_id) {
|
||||
VIR_FREE(unique_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
ignore_value(VIR_STRDUP(ret, entry->d_name));
|
||||
break;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_DIR_CLOSE(dir);
|
||||
VIR_FREE(unique_path);
|
||||
VIR_FREE(host_link);
|
||||
VIR_FREE(host_path);
|
||||
VIR_FREE(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* virSCSIHostGetNumber:
|
||||
* @adapter_name: Name of the host adapter
|
||||
* @result: Return the entry value as unsigned int
|
||||
*
|
||||
* Convert the various forms of scsi_host names into the numeric
|
||||
* host# value that can be used in order to scan sysfs looking for
|
||||
* the specific host.
|
||||
*
|
||||
* Names can be either "scsi_host#" or just "host#", where
|
||||
* "host#" is the back-compat format, but both equate to
|
||||
* the same source adapter. First check if both pool and def
|
||||
* are using same format (easier) - if so, then compare
|
||||
*
|
||||
* Returns 0 on success, and @result has the host number.
|
||||
* Otherwise returns -1.
|
||||
*/
|
||||
int
|
||||
virSCSIHostGetNumber(const char *adapter_name,
|
||||
unsigned int *result)
|
||||
{
|
||||
/* Specifying adapter like 'host5' is still supported for
|
||||
* back-compat reason.
|
||||
*/
|
||||
if (STRPREFIX(adapter_name, "scsi_host")) {
|
||||
adapter_name += strlen("scsi_host");
|
||||
} else if (STRPREFIX(adapter_name, "fc_host")) {
|
||||
adapter_name += strlen("fc_host");
|
||||
} else if (STRPREFIX(adapter_name, "host")) {
|
||||
adapter_name += strlen("host");
|
||||
} else {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Invalid adapter name '%s' for SCSI pool"),
|
||||
adapter_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virStrToLong_ui(adapter_name, NULL, 10, result) == -1) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Invalid adapter name '%s' for SCSI pool"),
|
||||
adapter_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* virSCSIHostGetNameByParentaddr:
|
||||
* @domain: The domain from the scsi_host parentaddr
|
||||
* @bus: The bus from the scsi_host parentaddr
|
||||
* @slot: The slot from the scsi_host parentaddr
|
||||
* @function: The function from the scsi_host parentaddr
|
||||
* @unique_id: The unique id value for parentaddr
|
||||
*
|
||||
* Generate a parentaddr and find the scsi_host host# for
|
||||
* the provided parentaddr PCI address fields.
|
||||
*
|
||||
* Returns the "host#" string which must be free'd by
|
||||
* the caller or NULL on error
|
||||
*/
|
||||
char *
|
||||
virSCSIHostGetNameByParentaddr(unsigned int domain,
|
||||
unsigned int bus,
|
||||
unsigned int slot,
|
||||
unsigned int function,
|
||||
unsigned int unique_id)
|
||||
{
|
||||
char *name = NULL;
|
||||
char *parentaddr = NULL;
|
||||
|
||||
if (virAsprintf(&parentaddr, "%04x:%02x:%02x.%01x",
|
||||
domain, bus, slot, function) < 0)
|
||||
goto cleanup;
|
||||
if (!(name = virSCSIHostFindByPCI(NULL, parentaddr, unique_id))) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("Failed to find scsi_host using PCI '%s' "
|
||||
"and unique_id='%u'"),
|
||||
parentaddr, unique_id);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(parentaddr);
|
||||
return name;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
virSCSIHostGetUniqueId(const char *sysfs_prefix ATTRIBUTE_UNUSED,
|
||||
int host ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *
|
||||
virSCSIHostFindByPCI(const char *sysfs_prefix ATTRIBUTE_UNUSED,
|
||||
const char *parentaddr ATTRIBUTE_UNUSED,
|
||||
unsigned int unique_id ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
virSCSIHostGetNumber(const char *adapter_name ATTRIBUTE_UNUSED,
|
||||
unsigned int *result ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *
|
||||
virSCSIHostGetNameByParentaddr(unsigned int domain ATTRIBUTE_UNUSED,
|
||||
unsigned int bus ATTRIBUTE_UNUSED,
|
||||
unsigned int slot ATTRIBUTE_UNUSED,
|
||||
unsigned int function ATTRIBUTE_UNUSED,
|
||||
unsigned int unique_id ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
40
src/util/virscsihost.h
Normal file
40
src/util/virscsihost.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* virscsihost.h: Generic scsi_host management utility functions
|
||||
*
|
||||
* 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_SCSI_HOST_H__
|
||||
# define __VIR_SCSI_HOST_H__
|
||||
|
||||
# include "internal.h"
|
||||
|
||||
int virSCSIHostGetUniqueId(const char *sysfs_prefix, int host);
|
||||
|
||||
char *virSCSIHostFindByPCI(const char *sysfs_prefix,
|
||||
const char *parentaddr,
|
||||
unsigned int unique_id);
|
||||
|
||||
int virSCSIHostGetNumber(const char *adapter_name,
|
||||
unsigned int *result)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
char *virSCSIHostGetNameByParentaddr(unsigned int domain,
|
||||
unsigned int bus,
|
||||
unsigned int slot,
|
||||
unsigned int function,
|
||||
unsigned int unique_id);
|
||||
|
||||
#endif /* __VIR_SCSI_HOST_H__ */
|
@ -27,7 +27,6 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
@ -1776,274 +1775,6 @@ virGetDeviceUnprivSGIO(const char *path,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
# define SYSFS_SCSI_HOST_PATH "/sys/class/scsi_host"
|
||||
|
||||
/* virReadSCSIUniqueId:
|
||||
* @sysfs_prefix: "scsi_host" sysfs path, defaults to SYSFS_SCSI_HOST_PATH
|
||||
* @host: Host number, E.g. 5 of "scsi_host/host5"
|
||||
* @result: Return the entry value as an unsigned int
|
||||
*
|
||||
* Read the value of the "scsi_host" unique_id file.
|
||||
*
|
||||
* Returns 0 on success, and @result is filled with the unique_id value
|
||||
* Otherwise returns -1
|
||||
*/
|
||||
int
|
||||
virReadSCSIUniqueId(const char *sysfs_prefix,
|
||||
int host,
|
||||
int *result)
|
||||
{
|
||||
char *sysfs_path = NULL;
|
||||
char *p = NULL;
|
||||
int ret = -1;
|
||||
char *buf = NULL;
|
||||
int unique_id;
|
||||
|
||||
if (virAsprintf(&sysfs_path, "%s/host%d/unique_id",
|
||||
sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_HOST_PATH,
|
||||
host) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virFileReadAll(sysfs_path, 1024, &buf) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((p = strchr(buf, '\n')))
|
||||
*p = '\0';
|
||||
|
||||
if (virStrToLong_i(buf, NULL, 10, &unique_id) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("unable to parse unique_id: %s"), buf);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*result = unique_id;
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(sysfs_path);
|
||||
VIR_FREE(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* virFindSCSIHostByPCI:
|
||||
* @sysfs_prefix: "scsi_host" sysfs path, defaults to SYSFS_SCSI_HOST_PATH
|
||||
* @parentaddr: string of the PCI address "scsi_host" device to be found
|
||||
* @unique_id: unique_id value of the to be found "scsi_host" device
|
||||
* @result: Return the host# of the matching "scsi_host" device
|
||||
*
|
||||
* Iterate over the SYSFS_SCSI_HOST_PATH entries looking for a matching
|
||||
* PCI Address in the expected format (dddd:bb:ss.f, where 'dddd' is the
|
||||
* 'domain' value, 'bb' is the 'bus' value, 'ss' is the 'slot' value, and
|
||||
* 'f' is the 'function' value from the PCI address) with a unique_id file
|
||||
* entry having the value expected. Unlike virReadSCSIUniqueId() we don't
|
||||
* have a host number yet and that's what we're looking for.
|
||||
*
|
||||
* Returns the host name of the "scsi_host" which must be freed by the caller,
|
||||
* or NULL on failure
|
||||
*/
|
||||
char *
|
||||
virFindSCSIHostByPCI(const char *sysfs_prefix,
|
||||
const char *parentaddr,
|
||||
unsigned int unique_id)
|
||||
{
|
||||
const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_HOST_PATH;
|
||||
struct dirent *entry = NULL;
|
||||
DIR *dir = NULL;
|
||||
char *host_link = NULL;
|
||||
char *host_path = NULL;
|
||||
char *p = NULL;
|
||||
char *ret = NULL;
|
||||
char *buf = NULL;
|
||||
char *unique_path = NULL;
|
||||
unsigned int read_unique_id;
|
||||
|
||||
if (virDirOpen(&dir, prefix) < 0)
|
||||
return NULL;
|
||||
|
||||
while (virDirRead(dir, &entry, prefix) > 0) {
|
||||
if (!virFileIsLink(entry->d_name))
|
||||
continue;
|
||||
|
||||
if (virAsprintf(&host_link, "%s/%s", prefix, entry->d_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virFileResolveLink(host_link, &host_path) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!strstr(host_path, parentaddr)) {
|
||||
VIR_FREE(host_link);
|
||||
VIR_FREE(host_path);
|
||||
continue;
|
||||
}
|
||||
VIR_FREE(host_link);
|
||||
VIR_FREE(host_path);
|
||||
|
||||
if (virAsprintf(&unique_path, "%s/%s/unique_id", prefix,
|
||||
entry->d_name) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!virFileExists(unique_path)) {
|
||||
VIR_FREE(unique_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (virFileReadAll(unique_path, 1024, &buf) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((p = strchr(buf, '\n')))
|
||||
*p = '\0';
|
||||
|
||||
if (virStrToLong_ui(buf, NULL, 10, &read_unique_id) < 0)
|
||||
goto cleanup;
|
||||
|
||||
VIR_FREE(buf);
|
||||
|
||||
if (read_unique_id != unique_id) {
|
||||
VIR_FREE(unique_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
ignore_value(VIR_STRDUP(ret, entry->d_name));
|
||||
break;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_DIR_CLOSE(dir);
|
||||
VIR_FREE(unique_path);
|
||||
VIR_FREE(host_link);
|
||||
VIR_FREE(host_path);
|
||||
VIR_FREE(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* virGetSCSIHostNumber:
|
||||
* @adapter_name: Name of the host adapter
|
||||
* @result: Return the entry value as unsigned int
|
||||
*
|
||||
* Convert the various forms of scsi_host names into the numeric
|
||||
* host# value that can be used in order to scan sysfs looking for
|
||||
* the specific host.
|
||||
*
|
||||
* Names can be either "scsi_host#" or just "host#", where
|
||||
* "host#" is the back-compat format, but both equate to
|
||||
* the same source adapter. First check if both pool and def
|
||||
* are using same format (easier) - if so, then compare
|
||||
*
|
||||
* Returns 0 on success, and @result has the host number.
|
||||
* Otherwise returns -1.
|
||||
*/
|
||||
int
|
||||
virGetSCSIHostNumber(const char *adapter_name,
|
||||
unsigned int *result)
|
||||
{
|
||||
/* Specifying adapter like 'host5' is still supported for
|
||||
* back-compat reason.
|
||||
*/
|
||||
if (STRPREFIX(adapter_name, "scsi_host")) {
|
||||
adapter_name += strlen("scsi_host");
|
||||
} else if (STRPREFIX(adapter_name, "fc_host")) {
|
||||
adapter_name += strlen("fc_host");
|
||||
} else if (STRPREFIX(adapter_name, "host")) {
|
||||
adapter_name += strlen("host");
|
||||
} else {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Invalid adapter name '%s' for SCSI pool"),
|
||||
adapter_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virStrToLong_ui(adapter_name, NULL, 10, result) == -1) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Invalid adapter name '%s' for SCSI pool"),
|
||||
adapter_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* virGetSCSIHostNameByParentaddr:
|
||||
* @domain: The domain from the scsi_host parentaddr
|
||||
* @bus: The bus from the scsi_host parentaddr
|
||||
* @slot: The slot from the scsi_host parentaddr
|
||||
* @function: The function from the scsi_host parentaddr
|
||||
* @unique_id: The unique id value for parentaddr
|
||||
*
|
||||
* Generate a parentaddr and find the scsi_host host# for
|
||||
* the provided parentaddr PCI address fields.
|
||||
*
|
||||
* Returns the "host#" string which must be free'd by
|
||||
* the caller or NULL on error
|
||||
*/
|
||||
char *
|
||||
virGetSCSIHostNameByParentaddr(unsigned int domain,
|
||||
unsigned int bus,
|
||||
unsigned int slot,
|
||||
unsigned int function,
|
||||
unsigned int unique_id)
|
||||
{
|
||||
char *name = NULL;
|
||||
char *parentaddr = NULL;
|
||||
|
||||
if (virAsprintf(&parentaddr, "%04x:%02x:%02x.%01x",
|
||||
domain, bus, slot, function) < 0)
|
||||
goto cleanup;
|
||||
if (!(name = virFindSCSIHostByPCI(NULL, parentaddr, unique_id))) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("Failed to find scsi_host using PCI '%s' "
|
||||
"and unique_id='%u'"),
|
||||
parentaddr, unique_id);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(parentaddr);
|
||||
return name;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
virReadSCSIUniqueId(const char *sysfs_prefix ATTRIBUTE_UNUSED,
|
||||
int host ATTRIBUTE_UNUSED,
|
||||
int *result ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *
|
||||
virFindSCSIHostByPCI(const char *sysfs_prefix ATTRIBUTE_UNUSED,
|
||||
const char *parentaddr ATTRIBUTE_UNUSED,
|
||||
unsigned int unique_id ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
virGetSCSIHostNumber(const char *adapter_name ATTRIBUTE_UNUSED,
|
||||
unsigned int *result ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *
|
||||
virGetSCSIHostNameByParentaddr(unsigned int domain ATTRIBUTE_UNUSED,
|
||||
unsigned int bus ATTRIBUTE_UNUSED,
|
||||
unsigned int slot ATTRIBUTE_UNUSED,
|
||||
unsigned int function ATTRIBUTE_UNUSED,
|
||||
unsigned int unique_id ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
/**
|
||||
* virParseOwnershipIds:
|
||||
|
@ -164,26 +164,6 @@ int virGetDeviceUnprivSGIO(const char *path,
|
||||
int *unpriv_sgio);
|
||||
char *virGetUnprivSGIOSysfsPath(const char *path,
|
||||
const char *sysfs_dir);
|
||||
int virReadSCSIUniqueId(const char *sysfs_prefix,
|
||||
int host,
|
||||
int *result)
|
||||
ATTRIBUTE_NONNULL(3);
|
||||
char *
|
||||
virFindSCSIHostByPCI(const char *sysfs_prefix,
|
||||
const char *parentaddr,
|
||||
unsigned int unique_id);
|
||||
int
|
||||
virGetSCSIHostNumber(const char *adapter_name,
|
||||
unsigned int *result)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
char *
|
||||
virGetSCSIHostNameByParentaddr(unsigned int domain,
|
||||
unsigned int bus,
|
||||
unsigned int slot,
|
||||
unsigned int function,
|
||||
unsigned int unique_id);
|
||||
|
||||
|
||||
|
||||
int virParseOwnershipIds(const char *label, uid_t *uidPtr, gid_t *gidPtr);
|
||||
|
||||
|
@ -26,9 +26,9 @@
|
||||
# include <fcntl.h>
|
||||
# include <sys/stat.h>
|
||||
# include "virstring.h"
|
||||
# include "virutil.h"
|
||||
# include "virerror.h"
|
||||
# include "virlog.h"
|
||||
# include "virscsihost.h"
|
||||
|
||||
# define VIR_FROM_THIS VIR_FROM_NONE
|
||||
|
||||
@ -173,8 +173,8 @@ testVirReadSCSIUniqueId(const void *data ATTRIBUTE_UNUSED)
|
||||
int hostnum, unique_id;
|
||||
|
||||
for (hostnum = 0; hostnum < 4; hostnum++) {
|
||||
if (virReadSCSIUniqueId(TEST_SCSIHOST_CLASS_PATH,
|
||||
hostnum, &unique_id) < 0) {
|
||||
if ((unique_id = virSCSIHostGetUniqueId(TEST_SCSIHOST_CLASS_PATH,
|
||||
hostnum)) < 0) {
|
||||
fprintf(stderr, "Failed to read hostnum=%d unique_id\n", hostnum);
|
||||
return -1;
|
||||
}
|
||||
@ -196,7 +196,7 @@ testVirReadSCSIUniqueId(const void *data ATTRIBUTE_UNUSED)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test virFindSCSIHostByPCI */
|
||||
/* Test virSCSIHostFindByPCI */
|
||||
static int
|
||||
testVirFindSCSIHostByPCI(const void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
@ -212,25 +212,25 @@ testVirFindSCSIHostByPCI(const void *data ATTRIBUTE_UNUSED)
|
||||
"sysfs/class/scsi_host") < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH,
|
||||
if (!(ret_host = virSCSIHostFindByPCI(TEST_SCSIHOST_CLASS_PATH,
|
||||
pci_addr1, unique_id1)) ||
|
||||
STRNEQ(ret_host, "host0"))
|
||||
goto cleanup;
|
||||
VIR_FREE(ret_host);
|
||||
|
||||
if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH,
|
||||
if (!(ret_host = virSCSIHostFindByPCI(TEST_SCSIHOST_CLASS_PATH,
|
||||
pci_addr1, unique_id2)) ||
|
||||
STRNEQ(ret_host, "host1"))
|
||||
goto cleanup;
|
||||
VIR_FREE(ret_host);
|
||||
|
||||
if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH,
|
||||
if (!(ret_host = virSCSIHostFindByPCI(TEST_SCSIHOST_CLASS_PATH,
|
||||
pci_addr2, unique_id1)) ||
|
||||
STRNEQ(ret_host, "host2"))
|
||||
goto cleanup;
|
||||
VIR_FREE(ret_host);
|
||||
|
||||
if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH,
|
||||
if (!(ret_host = virSCSIHostFindByPCI(TEST_SCSIHOST_CLASS_PATH,
|
||||
pci_addr2, unique_id2)) ||
|
||||
STRNEQ(ret_host, "host3"))
|
||||
goto cleanup;
|
||||
|
Loading…
Reference in New Issue
Block a user