linuxkpi: Handle bin attributes in sysfs attribute groups

For instance, this is used by DRM drivers to declare the EDID property
of an GPU output connector:

    sysctl -b sys.device.drmn1.card0.card0-DP-1.edid | edid-decode

    ...
    Block 0, Base EDID:
      EDID Structure Version & Revision: 1.4
      Vendor & Product Identification:
        Manufacturer: SAM
        Model: 29814
        Serial Number: 810635354 (0x3051505a)
        Made in: week 15 of 2025
    ...

Reviewed by:	bz, emaste, wulf
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D55176
This commit is contained in:
Jean-Sébastien Pédron
2026-02-08 11:11:39 +01:00
committed by Ed Maste
parent 607f6be6ec
commit 5bb0f63020
@@ -43,13 +43,6 @@ struct sysfs_ops {
size_t);
};
struct attribute_group {
const char *name;
mode_t (*is_visible)(struct kobject *,
struct attribute *, int);
struct attribute **attrs;
};
struct bin_attribute {
struct attribute attr;
size_t size;
@@ -59,6 +52,14 @@ struct bin_attribute {
struct bin_attribute *, char *, loff_t, size_t);
};
struct attribute_group {
const char *name;
mode_t (*is_visible)(struct kobject *,
struct attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};
#define __ATTR(_name, _mode, _show, _store) { \
.attr = { .name = __stringify(_name), .mode = _mode }, \
.show = _show, .store = _store, \
@@ -370,6 +371,7 @@ static inline int
sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
{
struct attribute **attr;
struct bin_attribute **bin_attr;
struct sysctl_oid *oidp;
/* Don't create the group node if grp->name is undefined. */
@@ -378,11 +380,19 @@ sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name);
else
oidp = kobj->oidp;
for (attr = grp->attrs; *attr != NULL; attr++) {
for (attr = grp->attrs; attr != NULL && *attr != NULL; attr++) {
SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO,
(*attr)->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE,
kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", "");
}
for (bin_attr = grp->bin_attrs;
bin_attr != NULL && *bin_attr != NULL;
bin_attr++) {
SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO,
(*bin_attr)->attr.name,
CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_MPSAFE,
kobj, (uintptr_t)*bin_attr, sysctl_handle_bin_attr, "", "");
}
return (0);
}
@@ -434,14 +444,20 @@ static inline void
sysfs_unmerge_group(struct kobject *kobj, const struct attribute_group *grp)
{
struct attribute **attr;
struct bin_attribute **bin_attr;
struct sysctl_oid *oidp;
SYSCTL_FOREACH(oidp, SYSCTL_CHILDREN(kobj->oidp)) {
if (strcmp(oidp->oid_name, grp->name) != 0)
continue;
for (attr = grp->attrs; *attr != NULL; attr++) {
for (attr = grp->attrs; attr != NULL && *attr != NULL; attr++) {
sysctl_remove_name(oidp, (*attr)->name, 1, 1);
}
for (bin_attr = grp->bin_attrs;
bin_attr != NULL && *bin_attr != NULL;
bin_attr++) {
sysctl_remove_name(oidp, (*bin_attr)->attr.name, 1, 1);
}
}
}