Index: sys/compat/linuxkpi/common/include/linux/device.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/device.h +++ sys/compat/linuxkpi/common/include/linux/device.h @@ -40,7 +40,6 @@ #include #include #include -#include #include #include @@ -316,6 +315,10 @@ dev->devt = makedev(0, device_get_unit(dev->bsddev)); } kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev)); + + if (dev->groups) + return (sysfs_create_groups(&dev->kobj, dev->groups)); + return (0); } Index: sys/compat/linuxkpi/common/include/linux/sysfs.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/sysfs.h +++ sys/compat/linuxkpi/common/include/linux/sysfs.h @@ -175,6 +175,27 @@ sysfs_remove_file(kobj, attrs[i]); } +static inline int +sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp) +{ + struct attribute **attr; + struct sysctl_oid *oidp; + + /* Don't create the group node if grp->name is undefined. */ + if (grp->name) + oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->oidp), + OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name); + else + oidp = kobj->oidp; + for (attr = grp->attrs; *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", ""); + } + + return (0); +} + static inline void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp) { @@ -184,20 +205,40 @@ } static inline int -sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp) +sysfs_create_groups(struct kobject *kobj, const struct attribute_group **grps) { + int error = 0; + int i; + + for (i = 0; grps[i] && !error; i++) + error = sysfs_create_group(kobj, grps[i]); + while (error && --i >= 0) + sysfs_remove_group(kobj, grps[i]); + + return (error); +} + +static inline int +sysfs_merge_group(struct kobject *kobj, const struct attribute_group *grp) +{ + + /* Really expected behavior is to return failure if group exists. */ + return (sysfs_create_group(kobj, grp)); +} + +static inline void +sysfs_unmerge_group(struct kobject *kobj, const struct attribute_group *grp) +{ struct attribute **attr; struct sysctl_oid *oidp; - oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->oidp), - OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name); - for (attr = grp->attrs; *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", ""); + SLIST_FOREACH(oidp, SYSCTL_CHILDREN(kobj->oidp), oid_link) { + if (strcmp(oidp->oid_name, grp->name) != 0) + continue; + for (attr = grp->attrs; *attr != NULL; attr++) { + sysctl_remove_name(oidp, (*attr)->name, 1, 1); + } } - - return (0); } static inline int @@ -222,6 +263,22 @@ if (kobj->oidp == NULL) return; sysctl_remove_oid(kobj->oidp, 1, 1); +} + +static inline bool +sysfs_streq(const char *s1, const char *s2) +{ + int l1, l2; + + l1 = strlen(s1); + l2 = strlen(s2); + + if (l1 != 0 && s1[l1-1] == '\n') + l1--; + if (l2 != 0 && s2[l2-1] == '\n') + l2--; + + return (l1 == l2 && strncmp(s1, s2, l1) == 0); } #define sysfs_attr_init(attr) do {} while(0) Index: sys/sys/param.h =================================================================== --- sys/sys/param.h +++ sys/sys/param.h @@ -60,7 +60,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1300045 /* Master, propagated to newvers */ +#define __FreeBSD_version 1300046 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,