[RFC PATCH 3/8] dax/kmem: add the reclaim opt-in (CAP_RECLAIM) for private nodes

Gregory Price <[email protected]> Wed, 22 Jul 2026 14:35:14 -0400
Newsgroups dev.linux.lists.nvdimm,org.kernel.vger.linux-cxl,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add the first per-service opt-in for a private node: "reclaim".
Also introduces the KMEM_PRIVATE_CAP_ATTR() helper for future bits.

Sets NODE_PRIVATE_CAP_RECLAIM for the device's private node.

A private kmem node opted into reclaim recovers THP compatibility.

Signed-off-by: Gregory Price <[email protected]>
---
 drivers/dax/kmem.c | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index c4c18aeb43c69..cf6cb927e5ed5 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -117,7 +117,7 @@ static int kmem_anon_mmap(struct file *filp, struct vm_area_struct *vma)
 	 * Without reclaim/compaction, high-order allocations can fail despite
 	 * memory still being available. Can be relaxed with reclaim support.
 	 */
-	if (data->private)
+	if (!node_allows_reclaim(data->numa_node))
 		vm_flags_set(vma, VM_NOHUGEPAGE);
 	mpol_get(data->policy);
 	kmem_vma_set_policy(vma, data->policy);
@@ -595,8 +595,44 @@ static ssize_t dax_file_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RW(dax_file);
 
+/* NODE_PRIVATE_CAP_* opt-in toggles - captured in data->caps */
+#define KMEM_PRIVATE_CAP_ATTR(name, CAP)				\
+static ssize_t name##_show(struct device *dev,				\
+			   struct device_attribute *attr, char *buf)	\
+{									\
+	struct dax_kmem_data *data = dev_get_drvdata(dev);		\
+									\
+	return sysfs_emit(buf, "%d\n", !!(data->caps & (CAP)));		\
+}									\
+static ssize_t name##_store(struct device *dev,				\
+			    struct device_attribute *attr,		\
+			    const char *buf, size_t len)		\
+{									\
+	struct dax_kmem_data *data = dev_get_drvdata(dev);		\
+	bool enable;							\
+	ssize_t rc;							\
+									\
+	rc = kstrtobool(buf, &enable);					\
+	if (rc)								\
+		return rc;						\
+									\
+	guard(mutex)(&data->lock);					\
+									\
+	if (data->state != DAX_KMEM_UNPLUGGED)				\
+		return -EBUSY;						\
+	if (enable)							\
+		data->caps |= (CAP);					\
+	else								\
+		data->caps &= ~(CAP);					\
+	return len;							\
+}									\
+static DEVICE_ATTR_RW(name)
+
+KMEM_PRIVATE_CAP_ATTR(reclaim, NODE_PRIVATE_CAP_RECLAIM);
+
 /* Per-service opt-ins. Visibility toggled by 'private' control */
 static struct attribute *dax_kmem_private_attrs[] = {
+	&dev_attr_reclaim.attr,
 	NULL,
 };
 static const struct attribute_group dax_kmem_private_group = {
-- 
2.53.0-Meta