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:
John Ferlan 2017-01-23 14:48:12 -05:00
parent d2d74a986d
commit 03346def06
11 changed files with 387 additions and 322 deletions

View File

@ -242,6 +242,7 @@ src/util/virqemu.c
src/util/virrandom.c src/util/virrandom.c
src/util/virrotatingfile.c src/util/virrotatingfile.c
src/util/virscsi.c src/util/virscsi.c
src/util/virscsihost.c
src/util/virscsivhost.c src/util/virscsivhost.c
src/util/virsecret.c src/util/virsecret.c
src/util/virsexpr.c src/util/virsexpr.c

View File

@ -164,6 +164,7 @@ UTIL_SOURCES = \
util/virrandom.h util/virrandom.c \ util/virrandom.h util/virrandom.c \
util/virrotatingfile.h util/virrotatingfile.c \ util/virrotatingfile.h util/virrotatingfile.c \
util/virscsi.c util/virscsi.h \ util/virscsi.c util/virscsi.h \
util/virscsihost.c util/virscsihost.h \
util/virscsivhost.c util/virscsivhost.h \ util/virscsivhost.c util/virscsivhost.h \
util/virseclabel.c util/virseclabel.h \ util/virseclabel.c util/virseclabel.h \
util/virsecret.c util/virsecret.h \ util/virsecret.c util/virsecret.h \

View File

@ -44,6 +44,7 @@
#include "virbuffer.h" #include "virbuffer.h"
#include "viralloc.h" #include "viralloc.h"
#include "virfile.h" #include "virfile.h"
#include "virscsihost.h"
#include "virstring.h" #include "virstring.h"
#include "virlog.h" #include "virlog.h"
#include "virvhba.h" #include "virvhba.h"
@ -2289,16 +2290,16 @@ getSCSIHostNumber(virStoragePoolSourceAdapter adapter,
virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr; virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr;
unsigned int unique_id = adapter.data.scsi_host.unique_id; unsigned int unique_id = adapter.data.scsi_host.unique_id;
if (!(name = virGetSCSIHostNameByParentaddr(addr.domain, if (!(name = virSCSIHostGetNameByParentaddr(addr.domain,
addr.bus, addr.bus,
addr.slot, addr.slot,
addr.function, addr.function,
unique_id))) unique_id)))
goto cleanup; goto cleanup;
if (virGetSCSIHostNumber(name, &num) < 0) if (virSCSIHostGetNumber(name, &num) < 0)
goto cleanup; goto cleanup;
} else { } else {
if (virGetSCSIHostNumber(adapter.data.scsi_host.name, &num) < 0) if (virSCSIHostGetNumber(adapter.data.scsi_host.name, &num) < 0)
goto cleanup; goto cleanup;
} }
@ -2310,6 +2311,21 @@ getSCSIHostNumber(virStoragePoolSourceAdapter adapter,
return ret; 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: * matchFCHostToSCSIHost:
* *
@ -2328,14 +2344,12 @@ matchFCHostToSCSIHost(virConnectPtr conn,
char *name = NULL; char *name = NULL;
char *scsi_host_name = NULL; char *scsi_host_name = NULL;
char *parent_name = NULL; char *parent_name = NULL;
unsigned int fc_hostnum;
/* If we have a parent defined, get its hostnum, and compare to the /* 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 * scsi_hostnum. If they are the same, then we have a match
*/ */
if (fc_adapter.data.fchost.parent && if (fc_adapter.data.fchost.parent &&
virGetSCSIHostNumber(fc_adapter.data.fchost.parent, &fc_hostnum) == 0 && virStorageIsSameHostnum(fc_adapter.data.fchost.parent, scsi_hostnum))
scsi_hostnum == fc_hostnum)
return true; return true;
/* If we find an fc_adapter name, then either libvirt created a vHBA /* 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 /* Get the scsi_hostN for the vHBA in order to see if it
* matches our scsi_hostnum * matches our scsi_hostnum
*/ */
if (virGetSCSIHostNumber(name, &fc_hostnum) == 0 && if (virStorageIsSameHostnum(name, scsi_hostnum)) {
scsi_hostnum == fc_hostnum) {
VIR_FREE(name); VIR_FREE(name);
return true; return true;
} }
VIR_FREE(name);
/* We weren't provided a parent, so we have to query the node /* We weren't provided a parent, so we have to query the node
* device driver in order to ascertain the parent of the vHBA. * device driver in order to ascertain the parent of the vHBA.
@ -2366,10 +2380,8 @@ matchFCHostToSCSIHost(virConnectPtr conn,
if ((parent_name = virNodeDeviceGetParentName(conn, if ((parent_name = virNodeDeviceGetParentName(conn,
scsi_host_name))) { scsi_host_name))) {
VIR_FREE(scsi_host_name); VIR_FREE(scsi_host_name);
if (virGetSCSIHostNumber(parent_name, &fc_hostnum) == 0 && if (virStorageIsSameHostnum(parent_name, scsi_hostnum)) {
scsi_hostnum == fc_hostnum) {
VIR_FREE(parent_name); VIR_FREE(parent_name);
VIR_FREE(name);
return true; return true;
} }
VIR_FREE(parent_name); VIR_FREE(parent_name);
@ -2380,7 +2392,6 @@ matchFCHostToSCSIHost(virConnectPtr conn,
VIR_FREE(scsi_host_name); VIR_FREE(scsi_host_name);
} }
} }
VIR_FREE(name);
} }
/* NB: Lack of a name means that this vHBA hasn't yet been created, /* NB: Lack of a name means that this vHBA hasn't yet been created,

View File

@ -2354,6 +2354,12 @@ virSCSIDeviceNew;
virSCSIDeviceSetUsedBy; virSCSIDeviceSetUsedBy;
# util/virscsihost.h
virSCSIHostFindByPCI;
virSCSIHostGetNameByParentaddr;
virSCSIHostGetNumber;
virSCSIHostGetUniqueId;
# util/virscsivhost.h # util/virscsivhost.h
virSCSIVHostDeviceFileIterate; virSCSIVHostDeviceFileIterate;
virSCSIVHostDeviceFree; virSCSIVHostDeviceFree;
@ -2679,7 +2685,6 @@ virUSBDeviceSetUsedBy;
virDoubleToStr; virDoubleToStr;
virEnumFromString; virEnumFromString;
virEnumToString; virEnumToString;
virFindSCSIHostByPCI;
virFormatIntDecimal; virFormatIntDecimal;
virGetDeviceID; virGetDeviceID;
virGetDeviceUnprivSGIO; virGetDeviceUnprivSGIO;
@ -2691,8 +2696,6 @@ virGetGroupName;
virGetHostname; virGetHostname;
virGetHostnameQuiet; virGetHostnameQuiet;
virGetListenFDs; virGetListenFDs;
virGetSCSIHostNameByParentaddr;
virGetSCSIHostNumber;
virGetSelfLastChanged; virGetSelfLastChanged;
virGetSystemPageSize; virGetSystemPageSize;
virGetSystemPageSizeKB; virGetSystemPageSizeKB;
@ -2716,7 +2719,6 @@ virParseNumber;
virParseOwnershipIds; virParseOwnershipIds;
virParseVersionString; virParseVersionString;
virPipeReadUntilEOF; virPipeReadUntilEOF;
virReadSCSIUniqueId;
virScaleInteger; virScaleInteger;
virSetBlocking; virSetBlocking;
virSetCloseExec; virSetCloseExec;

View File

@ -33,6 +33,7 @@
#include "viralloc.h" #include "viralloc.h"
#include "virlog.h" #include "virlog.h"
#include "virfile.h" #include "virfile.h"
#include "virscsihost.h"
#include "virstring.h" #include "virstring.h"
#include "virvhba.h" #include "virvhba.h"
@ -48,8 +49,8 @@ nodeDeviceSysfsGetSCSIHostCaps(virNodeDevCapDataPtr d)
char *tmp = NULL; char *tmp = NULL;
int ret = -1; int ret = -1;
if (virReadSCSIUniqueId(NULL, d->scsi_host.host, if ((d->scsi_host.unique_id =
&d->scsi_host.unique_id) < 0) { virSCSIHostGetUniqueId(NULL, d->scsi_host.host)) < 0) {
VIR_DEBUG("Failed to read unique_id for host%d", d->scsi_host.host); VIR_DEBUG("Failed to read unique_id for host%d", d->scsi_host.host);
d->scsi_host.unique_id = -1; d->scsi_host.unique_id = -1;
} }

View File

@ -33,6 +33,7 @@
#include "virlog.h" #include "virlog.h"
#include "virfile.h" #include "virfile.h"
#include "vircommand.h" #include "vircommand.h"
#include "virscsihost.h"
#include "virstring.h" #include "virstring.h"
#include "virvhba.h" #include "virvhba.h"
#include "storage_util.h" #include "storage_util.h"
@ -160,7 +161,7 @@ virStoragePoolFCRefreshThread(void *opaque)
pool->def->allocation = pool->def->capacity = pool->def->available = 0; pool->def->allocation = pool->def->capacity = pool->def->available = 0;
if (virStoragePoolObjIsActive(pool) && if (virStoragePoolObjIsActive(pool) &&
virGetSCSIHostNumber(fchost_name, &host) == 0 && virSCSIHostGetNumber(fchost_name, &host) == 0 &&
virStorageBackendSCSITriggerRescan(host) == 0) { virStorageBackendSCSITriggerRescan(host) == 0) {
virStoragePoolObjClearVols(pool); virStoragePoolObjClearVols(pool);
found = virStorageBackendSCSIFindLUs(pool, host); found = virStorageBackendSCSIFindLUs(pool, host);
@ -185,7 +186,7 @@ getAdapterName(virStoragePoolSourceAdapter adapter)
virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr; virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr;
unsigned int unique_id = adapter.data.scsi_host.unique_id; unsigned int unique_id = adapter.data.scsi_host.unique_id;
if (!(name = virGetSCSIHostNameByParentaddr(addr.domain, if (!(name = virSCSIHostGetNameByParentaddr(addr.domain,
addr.bus, addr.bus,
addr.slot, addr.slot,
addr.function, addr.function,
@ -318,7 +319,7 @@ createVport(virConnectPtr conn,
skip_capable_check = true; skip_capable_check = true;
} }
if (virGetSCSIHostNumber(parent_hoststr, &parent_host) < 0) if (virSCSIHostGetNumber(parent_hoststr, &parent_host) < 0)
goto cleanup; goto cleanup;
/* NOTE: /* NOTE:
@ -420,7 +421,7 @@ deleteVport(virConnectPtr conn,
* the parent scsi_host which we did not save at startup time * the parent scsi_host which we did not save at startup time
*/ */
if (adapter.data.fchost.parent) { 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; goto cleanup;
} else { } else {
if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0) if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
@ -429,7 +430,7 @@ deleteVport(virConnectPtr conn,
if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name))) if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name)))
goto cleanup; goto cleanup;
if (virGetSCSIHostNumber(vhba_parent, &parent_host) < 0) if (virSCSIHostGetNumber(vhba_parent, &parent_host) < 0)
goto cleanup; goto cleanup;
} }
@ -471,7 +472,7 @@ virStorageBackendSCSICheckPool(virStoragePoolObjPtr pool,
} }
} }
if (virGetSCSIHostNumber(name, &host) < 0) if (virSCSIHostGetNumber(name, &host) < 0)
goto cleanup; goto cleanup;
if (virAsprintf(&path, "%s/host%d", if (virAsprintf(&path, "%s/host%d",
@ -500,7 +501,7 @@ virStorageBackendSCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
if (!(name = getAdapterName(pool->def->source.adapter))) if (!(name = getAdapterName(pool->def->source.adapter)))
return -1; return -1;
if (virGetSCSIHostNumber(name, &host) < 0) if (virSCSIHostGetNumber(name, &host) < 0)
goto out; goto out;
VIR_DEBUG("Scanning host%u", host); VIR_DEBUG("Scanning host%u", host);

297
src/util/virscsihost.c Normal file
View 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
View 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__ */

View File

@ -27,7 +27,6 @@
#include <config.h> #include <config.h>
#include <stdlib.h> #include <stdlib.h>
#include <dirent.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <unistd.h> #include <unistd.h>
@ -1776,274 +1775,6 @@ virGetDeviceUnprivSGIO(const char *path,
return ret; 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: * virParseOwnershipIds:

View File

@ -164,26 +164,6 @@ int virGetDeviceUnprivSGIO(const char *path,
int *unpriv_sgio); int *unpriv_sgio);
char *virGetUnprivSGIOSysfsPath(const char *path, char *virGetUnprivSGIOSysfsPath(const char *path,
const char *sysfs_dir); 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); int virParseOwnershipIds(const char *label, uid_t *uidPtr, gid_t *gidPtr);

View File

@ -26,9 +26,9 @@
# include <fcntl.h> # include <fcntl.h>
# include <sys/stat.h> # include <sys/stat.h>
# include "virstring.h" # include "virstring.h"
# include "virutil.h"
# include "virerror.h" # include "virerror.h"
# include "virlog.h" # include "virlog.h"
# include "virscsihost.h"
# define VIR_FROM_THIS VIR_FROM_NONE # define VIR_FROM_THIS VIR_FROM_NONE
@ -173,8 +173,8 @@ testVirReadSCSIUniqueId(const void *data ATTRIBUTE_UNUSED)
int hostnum, unique_id; int hostnum, unique_id;
for (hostnum = 0; hostnum < 4; hostnum++) { for (hostnum = 0; hostnum < 4; hostnum++) {
if (virReadSCSIUniqueId(TEST_SCSIHOST_CLASS_PATH, if ((unique_id = virSCSIHostGetUniqueId(TEST_SCSIHOST_CLASS_PATH,
hostnum, &unique_id) < 0) { hostnum)) < 0) {
fprintf(stderr, "Failed to read hostnum=%d unique_id\n", hostnum); fprintf(stderr, "Failed to read hostnum=%d unique_id\n", hostnum);
return -1; return -1;
} }
@ -196,7 +196,7 @@ testVirReadSCSIUniqueId(const void *data ATTRIBUTE_UNUSED)
return 0; return 0;
} }
/* Test virFindSCSIHostByPCI */ /* Test virSCSIHostFindByPCI */
static int static int
testVirFindSCSIHostByPCI(const void *data ATTRIBUTE_UNUSED) testVirFindSCSIHostByPCI(const void *data ATTRIBUTE_UNUSED)
{ {
@ -212,25 +212,25 @@ testVirFindSCSIHostByPCI(const void *data ATTRIBUTE_UNUSED)
"sysfs/class/scsi_host") < 0) "sysfs/class/scsi_host") < 0)
goto cleanup; goto cleanup;
if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH, if (!(ret_host = virSCSIHostFindByPCI(TEST_SCSIHOST_CLASS_PATH,
pci_addr1, unique_id1)) || pci_addr1, unique_id1)) ||
STRNEQ(ret_host, "host0")) STRNEQ(ret_host, "host0"))
goto cleanup; goto cleanup;
VIR_FREE(ret_host); VIR_FREE(ret_host);
if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH, if (!(ret_host = virSCSIHostFindByPCI(TEST_SCSIHOST_CLASS_PATH,
pci_addr1, unique_id2)) || pci_addr1, unique_id2)) ||
STRNEQ(ret_host, "host1")) STRNEQ(ret_host, "host1"))
goto cleanup; goto cleanup;
VIR_FREE(ret_host); VIR_FREE(ret_host);
if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH, if (!(ret_host = virSCSIHostFindByPCI(TEST_SCSIHOST_CLASS_PATH,
pci_addr2, unique_id1)) || pci_addr2, unique_id1)) ||
STRNEQ(ret_host, "host2")) STRNEQ(ret_host, "host2"))
goto cleanup; goto cleanup;
VIR_FREE(ret_host); VIR_FREE(ret_host);
if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH, if (!(ret_host = virSCSIHostFindByPCI(TEST_SCSIHOST_CLASS_PATH,
pci_addr2, unique_id2)) || pci_addr2, unique_id2)) ||
STRNEQ(ret_host, "host3")) STRNEQ(ret_host, "host3"))
goto cleanup; goto cleanup;