mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
virutil: Introduce virReadSCSIUniqueId
Introduce a new function to read the current scsi_host entry and return the value found in the 'unique_id' file. Add a 'scsihosttest' test (similar to the fchosttest, but incorporating some of the concepts of the mocked pci test library) in order to read the unique_id file like would be found in the /sys/class/scsi_host tree.
This commit is contained in:
parent
aa9dac09b3
commit
fbd91d496e
@ -2144,6 +2144,7 @@ virParseOwnershipIds;
|
||||
virParseVersionString;
|
||||
virPipeReadUntilEOF;
|
||||
virReadFCHost;
|
||||
virReadSCSIUniqueId;
|
||||
virScaleInteger;
|
||||
virSetBlocking;
|
||||
virSetCloseExec;
|
||||
|
@ -1681,6 +1681,54 @@ virGetDeviceUnprivSGIO(const char *path,
|
||||
# define SYSFS_FC_HOST_PATH "/sys/class/fc_host/"
|
||||
# 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;
|
||||
}
|
||||
|
||||
/* virReadFCHost:
|
||||
* @sysfs_prefix: "fc_host" sysfs path, defaults to SYSFS_FC_HOST_PATH
|
||||
* @host: Host number, E.g. 5 of "fc_host/host5"
|
||||
@ -2033,6 +2081,15 @@ virFindFCHostCapableVport(const char *sysfs_prefix)
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
int
|
||||
virReadSCSIUniqueId(const char *sysfs_prefix ATTRIBUTE_UNUSED,
|
||||
int host ATTRIBUTE_UNUSED,
|
||||
unsigned int *result ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED,
|
||||
int host ATTRIBUTE_UNUSED,
|
||||
|
@ -164,6 +164,10 @@ 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);
|
||||
int virReadFCHost(const char *sysfs_prefix,
|
||||
int host,
|
||||
const char *entry,
|
||||
|
@ -83,6 +83,7 @@ EXTRA_DIST = \
|
||||
domainsnapshotxml2xmlin \
|
||||
domainsnapshotxml2xmlout \
|
||||
fchostdata \
|
||||
scsihostdata \
|
||||
interfaceschemadata \
|
||||
lxcconf2xmldata \
|
||||
lxcxml2xmldata \
|
||||
@ -188,6 +189,7 @@ endif WITH_REMOTE
|
||||
|
||||
if WITH_LINUX
|
||||
test_programs += fchosttest
|
||||
test_programs += scsihosttest
|
||||
endif WITH_LINUX
|
||||
|
||||
if WITH_LIBVIRTD
|
||||
@ -1146,8 +1148,13 @@ fchosttest_SOURCES = \
|
||||
fchosttest.c testutils.h testutils.c
|
||||
fchosttest_LDADD = $(LDADDS)
|
||||
|
||||
scsihosttest_SOURCES = \
|
||||
scsihosttest.c testutils.h testutils.c
|
||||
scsihosttest_LDADD = $(LDADDS)
|
||||
|
||||
else ! WITH_LINUX
|
||||
EXTRA_DIST += fchosttest.c
|
||||
EXTRA_DIST += scsihosttest.c
|
||||
endif ! WITH_LINUX
|
||||
|
||||
if WITH_LINUX
|
||||
|
254
tests/scsihosttest.c
Normal file
254
tests/scsihosttest.c
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "testutils.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
# include <fcntl.h>
|
||||
# include <sys/stat.h>
|
||||
# include "virstring.h"
|
||||
# include "virutil.h"
|
||||
# include "virerror.h"
|
||||
# include "virlog.h"
|
||||
|
||||
# define VIR_FROM_THIS VIR_FROM_NONE
|
||||
|
||||
VIR_LOG_INIT("tests.scsihosttest");
|
||||
|
||||
char *scsihost_class_path;
|
||||
# define TEST_SCSIHOST_CLASS_PATH scsihost_class_path
|
||||
|
||||
/*
|
||||
* Initialized/create a mock sysfs environment with 4 scsi_host devices
|
||||
* located on "0000:00:1f.1" and "0000:00:1f.2". Each directory will
|
||||
* contain 4 unique_id files having the same value.
|
||||
*
|
||||
* The environment is:
|
||||
*
|
||||
* 4 files:
|
||||
*
|
||||
* sys/devices/pci0000:00/0000:00:1f.1/ata1/host0/scsi_host/host0/unique_id
|
||||
* sys/devices/pci0000:00/0000:00:1f.1/ata2/host1/scsi_host/host1/unique_id
|
||||
* sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/scsi_host/host0/unique_id
|
||||
* sys/devices/pci0000:00/0000:00:1f.2/ata2/host1/scsi_host/host1/unique_id
|
||||
*
|
||||
* 4 symlinks:
|
||||
*
|
||||
* sys/class/scsi_host/host0 -> link to 1f.1 host 0
|
||||
* sys/class/scsi_host/host1 -> link to 1f.1 host 1
|
||||
* sys/class/scsi_host/host2 -> link to 1f.2 host 0
|
||||
* sys/class/scsi_host/host3 -> link to 1f.2 host 1
|
||||
*
|
||||
* The unique_id's for host0 and host2 are set to "1"
|
||||
* The unique_id's for host1 and host3 are set to "2"
|
||||
*/
|
||||
|
||||
static int
|
||||
create_scsihost(const char *fakesysfsdir, const char *devicepath,
|
||||
const char *unique_id, const char *hostname)
|
||||
{
|
||||
char *unique_id_path = NULL;
|
||||
char *link_path = NULL;
|
||||
char *spot;
|
||||
int ret = -1;
|
||||
int fd = -1;
|
||||
|
||||
if (virAsprintfQuiet(&unique_id_path, "%s/devices/pci0000:00/%s/unique_id",
|
||||
fakesysfsdir, devicepath) < 0 ||
|
||||
virAsprintfQuiet(&link_path, "%s/class/scsi_host/%s",
|
||||
fakesysfsdir, hostname) < 0) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Rather than create path & file, temporarily snip off the file to
|
||||
* create the path
|
||||
*/
|
||||
if (!(spot = strstr(unique_id_path, "unique_id"))) {
|
||||
fprintf(stderr, "Did not find unique_id in path\n");
|
||||
goto cleanup;
|
||||
}
|
||||
spot--;
|
||||
*spot = '\0';
|
||||
if (virFileMakePathWithMode(unique_id_path, 0755) < 0) {
|
||||
fprintf(stderr, "Unable to make path to '%s'\n", unique_id_path);
|
||||
goto cleanup;
|
||||
}
|
||||
*spot = '/';
|
||||
|
||||
/* Rather than create path & file, temporarily snip off the file to
|
||||
* create the path
|
||||
*/
|
||||
if (!(spot = strstr(link_path, hostname))) {
|
||||
fprintf(stderr, "Did not find hostname in path\n");
|
||||
goto cleanup;
|
||||
}
|
||||
spot--;
|
||||
*spot = '\0';
|
||||
if (virFileMakePathWithMode(link_path, 0755) < 0) {
|
||||
fprintf(stderr, "Unable to make path to '%s'\n", link_path);
|
||||
goto cleanup;
|
||||
}
|
||||
*spot = '/';
|
||||
|
||||
if ((fd = open(unique_id_path, O_CREAT|O_WRONLY, 0444)) < 0) {
|
||||
fprintf(stderr, "Unable to create '%s'\n", unique_id_path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (safewrite(fd, unique_id, 1) != 1) {
|
||||
fprintf(stderr, "Unable to write '%s'\n", unique_id);
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_DEBUG("Created unique_id '%s'", unique_id_path);
|
||||
|
||||
/* The link is to the path not the file - so remove the file */
|
||||
if (!(spot = strstr(unique_id_path, "unique_id"))) {
|
||||
fprintf(stderr, "Did not find unique_id in path\n");
|
||||
goto cleanup;
|
||||
}
|
||||
spot--;
|
||||
*spot = '\0';
|
||||
if (symlink(unique_id_path, link_path) < 0) {
|
||||
fprintf(stderr, "Unable to create symlink '%s' to '%s'\n",
|
||||
link_path, unique_id_path);
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_DEBUG("Created symlink '%s'", link_path);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FORCE_CLOSE(fd);
|
||||
VIR_FREE(unique_id_path);
|
||||
VIR_FREE(link_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
init_scsihost_sysfs(const char *fakesysfsdir)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (create_scsihost(fakesysfsdir,
|
||||
"0000:00:1f.1/ata1/host0/scsi_host/host0",
|
||||
"1", "host0") < 0 ||
|
||||
create_scsihost(fakesysfsdir,
|
||||
"0000:00:1f.1/ata2/host1/scsi_host/host1",
|
||||
"2", "host1") < 0 ||
|
||||
create_scsihost(fakesysfsdir,
|
||||
"0000:00:1f.2/ata1/host0/scsi_host/host0",
|
||||
"1", "host2") < 0 ||
|
||||
create_scsihost(fakesysfsdir,
|
||||
"0000:00:1f.2/ata2/host1/scsi_host/host1",
|
||||
"2", "host3") < 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Test virReadSCSIUniqueId */
|
||||
static int
|
||||
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) {
|
||||
fprintf(stderr, "Failed to read hostnum=%d unique_id\n", hostnum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* host0 and host2 have unique_id == 1
|
||||
* host1 and host3 have unique_id == 2
|
||||
*/
|
||||
if ((hostnum == 0 || hostnum == 2) && unique_id != 1) {
|
||||
fprintf(stderr, "The unique_id='%d' for hostnum=%d is wrong\n",
|
||||
unique_id, hostnum);
|
||||
return -1;
|
||||
} else if ((hostnum == 1 || hostnum == 3) && unique_id != 2) {
|
||||
fprintf(stderr, "The unique_id='%d' for hostnum=%d is wrong\n",
|
||||
unique_id, hostnum);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX"
|
||||
|
||||
static int
|
||||
mymain(void)
|
||||
{
|
||||
int ret = -1;
|
||||
char *fakesysfsdir = NULL;
|
||||
|
||||
if (VIR_STRDUP_QUIET(fakesysfsdir, FAKESYSFSDIRTEMPLATE) < 0) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!mkdtemp(fakesysfsdir)) {
|
||||
fprintf(stderr, "Cannot create fakesysfsdir");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
setenv("LIBVIRT_FAKE_SYSFS_DIR", fakesysfsdir, 1);
|
||||
|
||||
if (init_scsihost_sysfs(fakesysfsdir) < 0) {
|
||||
fprintf(stderr, "Failed to create fakesysfs='%s'\n", fakesysfsdir);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virAsprintfQuiet(&scsihost_class_path, "%s/class/scsi_host",
|
||||
fakesysfsdir) < 0) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_DEBUG("Reading from '%s'", scsihost_class_path);
|
||||
|
||||
if (virtTestRun("testVirReadSCSIUniqueId",
|
||||
testVirReadSCSIUniqueId, NULL) < 0) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
|
||||
virFileDeleteTree(fakesysfsdir);
|
||||
VIR_FREE(fakesysfsdir);
|
||||
VIR_FREE(scsihost_class_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
VIRT_TEST_MAIN(mymain)
|
||||
#else
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
return EXIT_AM_SKIP;
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user