From: Gregory Price <[email protected]>

Recent kernels add /sys/bus/dax/devices/daxX.Y/state to dax_kmem
devices for atomic whole-device hotplug. It reads 'unplugged',
'offline', 'online', 'online_kernel' or 'online_movable', and accepts
all but 'offline'.

Add an enum and get/set accessors for it. The getter returns
DAXCTL_KMEM_UNKNOWN when the attribute is absent, so callers can fall
back to per-block operations.

Signed-off-by: Gregory Price <[email protected]>
---
 daxctl/lib/libdaxctl-private.h |  9 ++++++
 daxctl/lib/libdaxctl.c         | 59 ++++++++++++++++++++++++++++++++++
 daxctl/lib/libdaxctl.sym       |  6 ++++
 daxctl/libdaxctl.h             | 18 +++++++++++
 4 files changed, 92 insertions(+)

diff --git a/daxctl/lib/libdaxctl-private.h b/daxctl/lib/libdaxctl-private.h
index b902e3d..00e906c 100644
--- a/daxctl/lib/libdaxctl-private.h
+++ b/daxctl/lib/libdaxctl-private.h
@@ -58,6 +58,15 @@ static const char *state_strings[] = {
        [MEM_ZONE_MOVABLE] = "online_movable",
 };
 
+/* dax_kmem daxX.Y/state strings */
+static const char *kmem_state_strings[] = {
+       [DAXCTL_KMEM_UNPLUGGED] = "unplugged",
+       [DAXCTL_KMEM_OFFLINE] = "offline",
+       [DAXCTL_KMEM_ONLINE] = "online",
+       [DAXCTL_KMEM_ONLINE_KERNEL] = "online_kernel",
+       [DAXCTL_KMEM_ONLINE_MOVABLE] = "online_movable",
+};
+
 /**
  * struct daxctl_region - container for dax_devices
  */
diff --git a/daxctl/lib/libdaxctl.c b/daxctl/lib/libdaxctl.c
index 01b1915..cbb42e3 100644
--- a/daxctl/lib/libdaxctl.c
+++ b/daxctl/lib/libdaxctl.c
@@ -1794,3 +1794,62 @@ DAXCTL_EXPORT int daxctl_dev_has_online_memory(struct 
daxctl_dev *dev)
        else
                return 0;
 }
+
+DAXCTL_EXPORT enum daxctl_kmem_state daxctl_dev_get_kmem_state(
+               struct daxctl_dev *dev)
+{
+       struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);
+       char *path = dev->dev_buf;
+       int len = dev->buf_len;
+       char buf[SYSFS_ATTR_SIZE];
+       int i;
+
+       if (snprintf(path, len, "%s/state", dev->dev_path) >= len) {
+               err(ctx, "%s: buffer too small!\n",
+                               daxctl_dev_get_devname(dev));
+               return DAXCTL_KMEM_UNKNOWN;
+       }
+
+       /* absent on older kernels */
+       if (sysfs_read_attr(ctx, path, buf) < 0)
+               return DAXCTL_KMEM_UNKNOWN;
+
+       for (i = DAXCTL_KMEM_UNPLUGGED; i <= DAXCTL_KMEM_ONLINE_MOVABLE; i++)
+               if (strcmp(buf, kmem_state_strings[i]) == 0)
+                       return i;
+
+       dbg(ctx, "%s: unrecognized kmem state '%s'\n",
+                       daxctl_dev_get_devname(dev), buf);
+       return DAXCTL_KMEM_UNKNOWN;
+}
+
+DAXCTL_EXPORT int daxctl_dev_set_kmem_state(struct daxctl_dev *dev,
+               enum daxctl_kmem_state state)
+{
+       struct daxctl_ctx *ctx = daxctl_dev_get_ctx(dev);
+       char *path = dev->dev_buf;
+       int len = dev->buf_len;
+
+       switch (state) {
+       case DAXCTL_KMEM_UNPLUGGED:
+       case DAXCTL_KMEM_ONLINE:
+       case DAXCTL_KMEM_ONLINE_KERNEL:
+       case DAXCTL_KMEM_ONLINE_MOVABLE:
+               break;
+       /* 'offline' is read-only */
+       case DAXCTL_KMEM_OFFLINE:
+       case DAXCTL_KMEM_UNKNOWN:
+       default:
+               dbg(ctx, "%s: invalid kmem state %d\n",
+                               daxctl_dev_get_devname(dev), state);
+               return -EINVAL;
+       }
+
+       if (snprintf(path, len, "%s/state", dev->dev_path) >= len) {
+               err(ctx, "%s: buffer too small!\n",
+                               daxctl_dev_get_devname(dev));
+               return -ENXIO;
+       }
+
+       return sysfs_write_attr(ctx, path, kmem_state_strings[state]);
+}
diff --git a/daxctl/lib/libdaxctl.sym b/daxctl/lib/libdaxctl.sym
index 43dd60b..d247542 100644
--- a/daxctl/lib/libdaxctl.sym
+++ b/daxctl/lib/libdaxctl.sym
@@ -113,3 +113,9 @@ global:
        daxctl_dev_get_mode;
        daxctl_dev_is_system_ram_mode;
 } LIBDAXCTL_10;
+
+LIBDAXCTL_12 {
+global:
+       daxctl_dev_get_kmem_state;
+       daxctl_dev_set_kmem_state;
+} LIBDAXCTL_11;
diff --git a/daxctl/libdaxctl.h b/daxctl/libdaxctl.h
index 7ec159e..e2812cc 100644
--- a/daxctl/libdaxctl.h
+++ b/daxctl/libdaxctl.h
@@ -77,6 +77,24 @@ int daxctl_dev_get_target_node(struct daxctl_dev *dev);
 int daxctl_dev_will_auto_online_memory(struct daxctl_dev *dev);
 int daxctl_dev_has_online_memory(struct daxctl_dev *dev);
 
+/*
+ * dax_kmem whole-device hotplug state (daxX.Y/state). UNKNOWN means the
+ * attribute is absent (older kernel, or device not bound to kmem) or
+ * reports a state this library does not recognize.
+ */
+enum daxctl_kmem_state {
+       DAXCTL_KMEM_UNKNOWN = -1,
+       DAXCTL_KMEM_UNPLUGGED = 0,
+       DAXCTL_KMEM_OFFLINE,
+       DAXCTL_KMEM_ONLINE,
+       DAXCTL_KMEM_ONLINE_KERNEL,
+       DAXCTL_KMEM_ONLINE_MOVABLE,
+};
+
+enum daxctl_kmem_state daxctl_dev_get_kmem_state(struct daxctl_dev *dev);
+int daxctl_dev_set_kmem_state(struct daxctl_dev *dev,
+               enum daxctl_kmem_state state);
+
 struct daxctl_memory;
 
 enum daxctl_dev_mode {
-- 
2.53.0-Meta


Reply via email to