diff --git a/sys/compat/linuxkpi/common/include/linux/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h --- a/sys/compat/linuxkpi/common/include/linux/kobject.h +++ b/sys/compat/linuxkpi/common/include/linux/kobject.h @@ -62,6 +62,7 @@ struct list_head entry; struct sysctl_oid *oidp; struct kset *kset; + struct sysctl_ctx_list sysctl_ctx; }; extern struct kobject *mm_kobj; diff --git a/sys/compat/linuxkpi/common/include/linux/sysfs.h b/sys/compat/linuxkpi/common/include/linux/sysfs.h --- a/sys/compat/linuxkpi/common/include/linux/sysfs.h +++ b/sys/compat/linuxkpi/common/include/linux/sysfs.h @@ -179,12 +179,13 @@ { struct sysctl_oid *oid; - oid = SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO, - attr->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, kobj, - (uintptr_t)attr, sysctl_handle_attr, "A", ""); - if (!oid) { + MPASS(kobj->oidp != NULL); + + oid = SYSCTL_ADD_OID(&kobj->sysctl_ctx, SYSCTL_CHILDREN(kobj->oidp), + OID_AUTO, attr->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, + kobj, (uintptr_t)attr, sysctl_handle_attr, "A", ""); + if (oid == NULL) return (-ENOMEM); - } return (0); } @@ -246,6 +247,8 @@ struct sysctl_oid *oid; int ctlflags; + MPASS(kobj->oidp != NULL); + ctlflags = CTLTYPE_OPAQUE | CTLFLAG_MPSAFE; if (attr->attr.mode & (S_IRUSR | S_IWUSR)) ctlflags |= CTLFLAG_RW; @@ -254,9 +257,9 @@ else if (attr->attr.mode & S_IWUSR) ctlflags |= CTLFLAG_WR; - oid = SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO, - attr->attr.name, ctlflags, kobj, - (uintptr_t)attr, sysctl_handle_bin_attr, "", ""); + oid = SYSCTL_ADD_OID(&kobj->sysctl_ctx, SYSCTL_CHILDREN(kobj->oidp), + OID_AUTO, attr->attr.name, ctlflags, + kobj, (uintptr_t)attr, sysctl_handle_bin_attr, "", ""); if (oid == NULL) return (-ENOMEM); @@ -315,15 +318,20 @@ struct attribute **attr; struct sysctl_oid *oidp; + MPASS(kobj->oidp != NULL); + /* 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); + oidp = SYSCTL_ADD_NODE(&kobj->sysctl_ctx, + 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, + SYSCTL_ADD_OID(&kobj->sysctl_ctx, SYSCTL_CHILDREN(oidp), + OID_AUTO, (*attr)->name, + CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", ""); } @@ -393,9 +401,16 @@ { struct sysctl_oid *oid; - oid = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->parent->oidp), + KASSERT(kobj->oidp == NULL, ("%s:%d: kobj %p oidp %p != NULL\n", + __func__, __LINE__, kobj, kobj->oidp)); + + sysctl_ctx_init(&kobj->sysctl_ctx); + + oid = SYSCTL_ADD_NODE(&kobj->sysctl_ctx, + SYSCTL_CHILDREN(kobj->parent->oidp), OID_AUTO, kobj->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, kobj->name); - if (!oid) { + if (oid == NULL) { + sysctl_ctx_free(&kobj->sysctl_ctx); return (-ENOMEM); } kobj->oidp = oid; @@ -409,7 +424,10 @@ if (kobj->oidp == NULL) return; - sysctl_remove_oid(kobj->oidp, 1, 1); + + sysctl_ctx_free(&kobj->sysctl_ctx); + /* If we fail, we cannot do much about it but leak. */ + kobj->oidp = NULL; } static inline bool