@@ -15,6 +15,17 @@
#define DAXCTL_EXPORT __attribute__ ((visibility("default")))
+enum dax_subsystem {
+ DAX_UNKNOWN,
+ DAX_CLASS,
+ DAX_BUS,
+};
+
+static const char *dax_subsystems[] = {
+ [DAX_CLASS] = "/sys/class/dax",
+ [DAX_BUS] = "/sys/bus/dax/devices",
+};
+
/**
* struct daxctl_region - container for dax_devices
*/
@@ -444,26 +444,38 @@ static void dax_devices_init(struct daxctl_region *region)
{
struct daxctl_ctx *ctx = daxctl_region_get_ctx(region);
char daxdev_fmt[50];
- char *region_path;
+ size_t i;
if (region->devices_init)
return;
region->devices_init = 1;
sprintf(daxdev_fmt, "dax%d.", region->id);
- if (asprintf(®ion_path, "%s/dax", region->region_path) < 0) {
- dbg(ctx, "region path alloc fail\n");
- return;
+ for (i = 0; i < ARRAY_SIZE(dax_subsystems); i++) {
+ char *region_path;
+
+ if (i == DAX_BUS)
+ region_path = region->region_path;
+ else if (i == DAX_CLASS) {
+ if (asprintf(®ion_path, "%s/dax",
+ region->region_path) < 0) {
+ dbg(ctx, "region path alloc fail\n");
+ continue;
+ }
+ } else
+ continue;
+ sysfs_device_parse(ctx, region_path, daxdev_fmt, region,
+ add_dax_dev);
+ if (i == DAX_CLASS)
+ free(region_path);
}
- sysfs_device_parse(ctx, region_path, daxdev_fmt, region, add_dax_dev);
- free(region_path);
}
-static char *dax_region_path(const char *base, const char *device)
+static char *dax_region_path(const char *device, enum dax_subsystem subsys)
{
char *path, *region_path, *c;
- if (asprintf(&path, "%s/%s", base, device) < 0)
+ if (asprintf(&path, "%s/%s", dax_subsystems[subsys], device) < 0)
return NULL;
/* dax_region must be the instance's direct parent */
@@ -472,7 +484,11 @@ static char *dax_region_path(const char *base, const char *device)
if (!region_path)
return NULL;
- /* 'region_path' is now regionX/dax/daxX.Y', trim back to regionX */
+ /*
+ * 'region_path' is now regionX/dax/daxX.Y' (DAX_CLASS), or
+ * regionX/daxX.Y (DAX_BUS), trim it back to the regionX
+ * component
+ */
c = strrchr(region_path, '/');
if (!c) {
free(region_path);
@@ -480,6 +496,9 @@ static char *dax_region_path(const char *base, const char *device)
}
*c = '\0';
+ if (subsys == DAX_BUS)
+ return region_path;
+
c = strrchr(region_path, '/');
if (!c) {
free(region_path);
@@ -490,20 +509,15 @@ static char *dax_region_path(const char *base, const char *device)
return region_path;
}
-static void dax_regions_init(struct daxctl_ctx *ctx)
+static void __dax_regions_init(struct daxctl_ctx *ctx, enum dax_subsystem subsys)
{
- const char *base = "/sys/class/dax";
struct dirent *de;
- DIR *dir;
+ DIR *dir = NULL;
- if (ctx->regions_init)
- return;
-
- ctx->regions_init = 1;
-
- dir = opendir(base);
+ dir = opendir(dax_subsystems[subsys]);
if (!dir) {
- dbg(ctx, "no dax regions found\n");
+ dbg(ctx, "no dax regions found via: %s\n",
+ dax_subsystems[subsys]);
return;
}
@@ -516,7 +530,7 @@ static void dax_regions_init(struct daxctl_ctx *ctx)
continue;
if (sscanf(de->d_name, "dax%d.%d", ®ion_id, &id) != 2)
continue;
- dev_path = dax_region_path(base, de->d_name);
+ dev_path = dax_region_path(de->d_name, subsys);
if (!dev_path) {
err(ctx, "dax region path allocation failure\n");
continue;
@@ -529,6 +543,22 @@ static void dax_regions_init(struct daxctl_ctx *ctx)
closedir(dir);
}
+static void dax_regions_init(struct daxctl_ctx *ctx)
+{
+ size_t i;
+
+ if (ctx->regions_init)
+ return;
+
+ ctx->regions_init = 1;
+
+ for (i = 0; i < ARRAY_SIZE(dax_subsystems); i++) {
+ if (i == DAX_UNKNOWN)
+ continue;
+ __dax_regions_init(ctx, i);
+ }
+}
+
DAXCTL_EXPORT struct daxctl_dev *daxctl_dev_get_first(struct daxctl_region *region)
{
dax_devices_init(region);
@@ -91,7 +91,7 @@ int __sysfs_device_parse(struct log_ctx *ctx, const char *base_path,
struct dirent *de;
DIR *dir;
- log_dbg(ctx, "base: %s dev: %s\n", base_path, dev_name);
+ log_dbg(ctx, "base: '%s' dev: '%s'\n", base_path, dev_name);
dir = opendir(base_path);
if (!dir) {
log_dbg(ctx, "no \"%s\" devices found\n", dev_name);
The kernel is implementing a '/sys/bus/dax' ABI to allow for alternate device-DAX drivers to be bound to device instances. In support of this conversion, teach the libdaxctl subsystem-layout-specific code to parse the new layout. For backwards compatibility the implementation transparently and optionally supports either '/sys/bus/dax' or '/sys/class/dax'. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- daxctl/lib/libdaxctl-private.h | 11 ++++++ daxctl/lib/libdaxctl.c | 70 +++++++++++++++++++++++++++++----------- util/sysfs.c | 2 + 3 files changed, 62 insertions(+), 21 deletions(-)