// SPDX-License-Identifier: GPL-2.0-only#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <linux/limits.h> #include <libvfio.h> #define readlink_safe(_path, _buf) ({ \ int __ret; \ \ _Static_assert(!__builtin_types_compatible_p( \ __typeof__(_buf), char *), \ "readlink_safe: _buf must be an array, not a pointer"); \ \ __ret = readlink(_path, _buf, sizeof(_buf) - 1); \ if (__ret != -1) \ _buf[__ret] = 0; \ __ret; \}) static void readlink_base(const char *path, const char *data_fmt, void *out_data){ char rl_path[PATH_MAX]; int ret; ret = readlink_safe(path, rl_path); VFIO_ASSERT_NE(ret, -1); ret = sscanf(basename(rl_path), data_fmt, out_data); VFIO_ASSERT_EQ(ret, 1);} static int sysfs_val_get_int(const char *component, const char *name, const char *file){ char path[PATH_MAX]; char buf[32]; int ret; int fd; snprintf_assert(path, PATH_MAX, "/sys/bus/pci/%s/%s/%s", component, name, file); fd = open(path, O_RDONLY); if (fd < 0) return fd; VFIO_ASSERT_GT(read(fd, buf, ARRAY_SIZE(buf)), 0); VFIO_ASSERT_EQ(close(fd), 0); errno = 0; ret = strtol(buf, NULL, 0); VFIO_ASSERT_EQ(errno, 0, "sysfs path \"%s\" is not an integer: \"%s\"\n", path, buf); return ret;} static void sysfs_val_set(const char *component, const char *name, const char *file, const char *val){ char path[PATH_MAX]; int fd; snprintf_assert(path, PATH_MAX, "/sys/bus/pci/%s/%s/%s", component, name, file); VFIO_ASSERT_GT(fd = open(path, O_WRONLY), 0); VFIO_ASSERT_EQ(write(fd, val, strlen(val)), strlen(val)); VFIO_ASSERT_EQ(close(fd), 0);} static int sysfs_device_val_get(const char *bdf, const char *file){ return sysfs_val_get_int("devices", bdf, file);} static void sysfs_device_val_set(const char *bdf, const char *file, const char *val){ sysfs_val_set("devices", bdf, file, val);} static void sysfs_device_val_set_int(const char *bdf, const char *file, int val){ char val_str[32]; snprintf_assert(val_str, sizeof(val_str), "%d", val); sysfs_device_val_set(bdf, file, val_str);} int sysfs_sriov_totalvfs_get(const char *bdf){ return sysfs_device_val_get(bdf, "sriov_totalvfs");} int sysfs_sriov_numvfs_get(const char *bdf){ return sysfs_device_val_get(bdf, "sriov_numvfs");} void sysfs_sriov_numvfs_set(const char *bdf, int numvfs){ sysfs_device_val_set_int(bdf, "sriov_numvfs", numvfs);} char *sysfs_sriov_vf_bdf_get(const char *pf_bdf, int i){ char path[PATH_MAX]; char *out_vf_bdf; /* Fit "0000:00:00.0" */ out_vf_bdf = calloc_assert(16, sizeof(char)); snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/virtfn%d", pf_bdf, i); readlink_base(path, "%s", out_vf_bdf); return out_vf_bdf;} int sysfs_iommu_group_get(const char *bdf){ char path[PATH_MAX]; int group; snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/iommu_group", bdf); readlink_base(path, "%d", &group); return group;} char *sysfs_driver_get(const char *bdf){ char driver_path[PATH_MAX]; char path[PATH_MAX]; char *out_driver; int ret; snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/driver", bdf); ret = readlink_safe(path, driver_path); if (ret == -1) { if (errno == ENOENT) return NULL; VFIO_FAIL("Failed to read %s\n", path); } out_driver = strdup(basename(driver_path)); VFIO_ASSERT_NOT_NULL(out_driver); return out_driver;}
// SPDX-License-Identifier: GPL-2.0-only
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/limits.h>
#include <libvfio.h>
#define readlink_safe(_path, _buf) ({ \
int __ret; \
\
_Static_assert(!__builtin_types_compatible_p( \
__typeof__(_buf), char *), \
"readlink_safe: _buf must be an array, not a pointer"); \
\
__ret = readlink(_path, _buf, sizeof(_buf) - 1); \
if (__ret != -1) \
_buf[__ret] = 0; \
__ret; \
})
static void readlink_base(const char *path, const char *data_fmt, void *out_data)
{
char rl_path[PATH_MAX];
int ret;
ret = readlink_safe(path, rl_path);
VFIO_ASSERT_NE(ret, -1);
ret = sscanf(basename(rl_path), data_fmt, out_data);
VFIO_ASSERT_EQ(ret, 1);
}
static int sysfs_val_get_int(const char *component, const char *name,
const char *file)
{
char path[PATH_MAX];
char buf[32];
int ret;
int fd;
snprintf_assert(path, PATH_MAX, "/sys/bus/pci/%s/%s/%s", component, name, file);
fd = open(path, O_RDONLY);
if (fd < 0)
return fd;
VFIO_ASSERT_GT(read(fd, buf, ARRAY_SIZE(buf)), 0);
VFIO_ASSERT_EQ(close(fd), 0);
errno = 0;
ret = strtol(buf, NULL, 0);
VFIO_ASSERT_EQ(errno, 0, "sysfs path \"%s\" is not an integer: \"%s\"\n", path, buf);
return ret;
}
static void sysfs_val_set(const char *component, const char *name,
const char *file, const char *val)
{
char path[PATH_MAX];
int fd;
snprintf_assert(path, PATH_MAX, "/sys/bus/pci/%s/%s/%s", component, name, file);
VFIO_ASSERT_GT(fd = open(path, O_WRONLY), 0);
VFIO_ASSERT_EQ(write(fd, val, strlen(val)), strlen(val));
VFIO_ASSERT_EQ(close(fd), 0);
}
static int sysfs_device_val_get(const char *bdf, const char *file)
{
return sysfs_val_get_int("devices", bdf, file);
}
static void sysfs_device_val_set(const char *bdf, const char *file, const char *val)
{
sysfs_val_set("devices", bdf, file, val);
}
static void sysfs_device_val_set_int(const char *bdf, const char *file, int val)
{
char val_str[32];
snprintf_assert(val_str, sizeof(val_str), "%d", val);
sysfs_device_val_set(bdf, file, val_str);
}
int sysfs_sriov_totalvfs_get(const char *bdf)
{
return sysfs_device_val_get(bdf, "sriov_totalvfs");
}
int sysfs_sriov_numvfs_get(const char *bdf)
{
return sysfs_device_val_get(bdf, "sriov_numvfs");
}
void sysfs_sriov_numvfs_set(const char *bdf, int numvfs)
{
sysfs_device_val_set_int(bdf, "sriov_numvfs", numvfs);
}
char *sysfs_sriov_vf_bdf_get(const char *pf_bdf, int i)
{
char path[PATH_MAX];
char *out_vf_bdf;
/* Fit "0000:00:00.0" */
out_vf_bdf = calloc_assert(16, sizeof(char));
snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/virtfn%d", pf_bdf, i);
readlink_base(path, "%s", out_vf_bdf);
return out_vf_bdf;
}
int sysfs_iommu_group_get(const char *bdf)
{
char path[PATH_MAX];
int group;
snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/iommu_group", bdf);
readlink_base(path, "%d", &group);
return group;
}
char *sysfs_driver_get(const char *bdf)
{
char driver_path[PATH_MAX];
char path[PATH_MAX];
char *out_driver;
int ret;
snprintf_assert(path, PATH_MAX, "/sys/bus/pci/devices/%s/driver", bdf);
ret = readlink_safe(path, driver_path);
if (ret == -1) {
if (errno == ENOENT)
return NULL;
VFIO_FAIL("Failed to read %s\n", path);
}
out_driver = strdup(basename(driver_path));
VFIO_ASSERT_NOT_NULL(out_driver);
return out_driver;
}