[PATCH 4/5] driver core: Allow the constification of device attributes

Thomas Weißschuh
2026-04-08T19:30:54Z

Allow device attribute to reside in read-only memory.
Both const and non-const attributes are handled by the utility macros
and attributes can be migrated one-by-one.

Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
drivers/base/core.c | 12 ++++++----
include/linux/device.h | 62 +++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 763e17e9f148..8a48cb2137ae 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2419,9 +2419,11 @@ static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,

if (dev_attr->show)
ret = dev_attr->show(dev, dev_attr, buf);
+ else if (dev_attr->show_const)
+ ret = dev_attr->show_const(dev, dev_attr, buf);
if (ret >= (ssize_t)PAGE_SIZE) {
- printk("dev_attr_show: %pS returned bad count\n",
- dev_attr->show);
+ printk("dev_attr_show: %pS/%pS returned bad count\n",
+ dev_attr->show, dev_attr->show_const);
}
return ret;
}
@@ -2435,6 +2437,8 @@ static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,

if (dev_attr->store)
ret = dev_attr->store(dev, dev_attr, buf, count);
+ else if (dev_attr->store_const)
+ ret = dev_attr->store_const(dev, dev_attr, buf, count);
return ret;
}

@@ -3048,10 +3052,10 @@ int device_create_file(struct device *dev,
int error = 0;

if (dev) {
- WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
+ WARN(((attr->attr.mode & S_IWUGO) && !(attr->store || attr->store_const)),
"Attribute %s: write permission without 'store'\n",
attr->attr.name);
- WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
+ WARN(((attr->attr.mode & S_IRUGO) && !(attr->show || attr->show_const)),
"Attribute %s: read permission without 'show'\n",
attr->attr.name);
error = sysfs_create_file(&dev->kobj, &attr->attr);
diff --git a/include/linux/device.h b/include/linux/device.h
index 714e36d610e3..a529a8eaaa9a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -104,10 +104,18 @@ struct device_type {
*/
struct device_attribute {
struct attribute attr;
- ssize_t (*show)(struct device *dev, struct device_attribute *attr,
- char *buf);
- ssize_t (*store)(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count);
+ __SYSFS_FUNCTION_ALTERNATIVE(
+ ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+ char *buf);
+ ssize_t (*show_const)(struct device *dev, const struct device_attribute *attr,
+ char *buf);
+ );
+ __SYSFS_FUNCTION_ALTERNATIVE(
+ ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+ ssize_t (*store_const)(struct device *dev, const struct device_attribute *attr,
+ const char *buf, size_t count);
+ );
};

/**
@@ -135,11 +143,50 @@ ssize_t device_store_bool(struct device *dev, struct device_attribute *attr,
ssize_t device_show_string(struct device *dev, struct device_attribute *attr,
char *buf);

+typedef ssize_t __device_show_handler_const(struct device *dev, const struct device_attribute *attr,
+ char *buf);
+typedef ssize_t __device_store_handler_const(struct device *dev, const struct device_attribute *attr,
+ const char *buf, size_t count);
+
+#ifdef CONFIG_CFI
+
+#define __DEVICE_ATTR_SHOW_STORE(_show, _store) \
+ .show = _Generic(_show, \
+ __device_show_handler_const * : NULL, \
+ default : _show \
+ ), \
+ .show_const = _Generic(_show, \
+ __device_show_handler_const * : _show, \
+ default : NULL \
+ ), \
+ .store = _Generic(_store, \
+ __device_store_handler_const * : NULL, \
+ default : _store \
+ ), \
+ .store_const = _Generic(_store, \
+ __device_store_handler_const * : _store, \
+ default : NULL \
+ ),
+
+#else
+
+#define __DEVICE_ATTR_SHOW_STORE(_show, _store) \
+ .show = _Generic(_show, \
+ __device_show_handler_const * : (void *)_show, \
+ default : _show \
+ ), \
+ .store = _Generic(_store, \
+ __device_store_handler_const * : (void *)_store, \
+ default : _store \
+ ), \
+
+#endif
+
+
#define __DEVICE_ATTR(_name, _mode, _show, _store) { \
.attr = {.name = __stringify(_name), \
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
- .show = _show, \
- .store = _store, \
+ __DEVICE_ATTR_SHOW_STORE(_show, _store) \
}

#define __DEVICE_ATTR_RO_MODE(_name, _mode) \
@@ -161,8 +208,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr,
#define __DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) { \
.attr = {.name = __stringify(_name), .mode = _mode, \
.ignore_lockdep = true }, \
- .show = _show, \
- .store = _store, \
+ __DEVICE_ATTR_SHOW_STORE(_show, _store) \
}
#else
#define __DEVICE_ATTR_IGNORE_LOCKDEP __DEVICE_ATTR

--
2.53.0