]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
driver core: Allow the constification of device attributes
authorThomas Weißschuh <linux@weissschuh.net>
Tue, 12 May 2026 16:39:14 +0000 (18:39 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 May 2026 11:36:52 +0000 (13:36 +0200)
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>
Link: https://patch.msgid.link/20260512-sysfs-const-attr-device_attr-prep-v3-4-cb7c17b34d52@weissschuh.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/core.c
include/linux/device.h

index cc0d6984f1d42f2390f95ee4e77af1c476df6a64..433fbb863fc07e765750fd2ec9fea799d93574aa 100644 (file)
@@ -2485,9 +2485,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;
 }
@@ -2501,6 +2503,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;
 }
 
@@ -3113,10 +3117,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);
index 62985a8a78d3183484208cf5b3ad452b97747ed6..7b2baffdd2f55f234ce844f6b24c9283ac70e6b9 100644 (file)
@@ -103,10 +103,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);
+       );
 };
 
 /**
@@ -134,11 +142,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) \
@@ -160,8 +207,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
@@ -220,8 +266,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr,
 #define DEVICE_ATTR_RW_NAMED(_name, _attrname)                            \
        struct device_attribute dev_attr_##_name = {                      \
                .attr = { .name = _attrname, .mode = 0644 }, \
-               .show = _name##_show,                                     \
-               .store = _name##_store,                                   \
+               __DEVICE_ATTR_SHOW_STORE(_name##_show, _name##_store)     \
        }
 
 /**
@@ -254,7 +299,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr,
 #define DEVICE_ATTR_RO_NAMED(_name, _attrname)                            \
        struct device_attribute dev_attr_##_name = {                      \
                .attr = { .name = _attrname, .mode = 0444 }, \
-               .show = _name##_show,                                     \
+               __DEVICE_ATTR_SHOW_STORE(_name##_show, NULL)              \
        }
 
 /**
@@ -278,7 +323,7 @@ ssize_t device_show_string(struct device *dev, struct device_attribute *attr,
 #define DEVICE_ATTR_WO_NAMED(_name, _attrname)                            \
        struct device_attribute dev_attr_##_name = {                      \
                .attr = { .name = _attrname, .mode = 0200 }, \
-               .store = _name##_store,                                   \
+               __DEVICE_ATTR_SHOW_STORE(NULL, _name##_store)             \
        }
 
 /**