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 @@ -35,8 +35,10 @@ #include #include #include +#include struct kobject; +struct kset; struct sysctl_oid; #define KOBJ_CHANGE 0x01 @@ -57,6 +59,7 @@ const struct kobj_type *ktype; struct list_head entry; struct sysctl_oid *oidp; + struct kset *kset; }; extern struct kobject *mm_kobj; @@ -77,6 +80,17 @@ const char *buf, size_t count); }; +struct kset_uevent_ops { + /* TODO */ +}; + +struct kset { + struct list_head list; + spinlock_t list_lock; + struct kobject kobj; + const struct kset_uevent_ops *uevent_ops; +}; + static inline void kobject_init(struct kobject *kobj, const struct kobj_type *ktype) { @@ -154,6 +168,41 @@ */ } +void kset_init(struct kset *kset); +int kset_register(struct kset *kset); +void kset_unregister(struct kset *kset); +struct kset * kset_create_and_add(const char *name, + const struct kset_uevent_ops *u, struct kobject *parent_kobj); + +static inline struct kset * +to_kset(struct kobject *kobj) +{ + if (kobj != NULL) + return container_of(kobj, struct kset, kobj); + else + return NULL; +} + +static inline struct kset * +kset_get(struct kset *kset) +{ + if (kset != NULL) { + struct kobject *kobj; + + kobj = kobject_get(&kset->kobj); + return to_kset(kobj); + } else { + return NULL; + } +} + +static inline void +kset_put(struct kset *kset) +{ + if (kset != NULL) + kobject_put(&kset->kobj); +} + void linux_kobject_kfree_name(struct kobject *kobj); #endif /* _LINUXKPI_LINUX_KOBJECT_H_ */ diff --git a/sys/compat/linuxkpi/common/src/linux_kobject.c b/sys/compat/linuxkpi/common/src/linux_kobject.c --- a/sys/compat/linuxkpi/common/src/linux_kobject.c +++ b/sys/compat/linuxkpi/common/src/linux_kobject.c @@ -30,6 +30,10 @@ #include #include +static void kset_join(struct kobject *kobj); +static void kset_leave(struct kobject *kobj); +static void kset_kfree(struct kobject *kobj); + struct kobject * kobject_create(void) { @@ -101,12 +105,16 @@ } static int -kobject_add_complete(struct kobject *kobj, struct kobject *parent) +kobject_add_complete(struct kobject *kobj) { const struct kobj_type *t; int error; - kobj->parent = parent; + if (kobj->kset != NULL) { + kset_join(kobj); + kobj->parent = &kobj->kset->kobj; + } + error = sysfs_create_dir(kobj); if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) { struct attribute **attr; @@ -120,6 +128,10 @@ if (error) sysfs_remove_dir(kobj); } + + if (error != 0) + kset_leave(kobj); + return (error); } @@ -129,13 +141,15 @@ va_list args; int error; + kobj->parent = parent; + va_start(args, fmt); error = kobject_set_name_vargs(kobj, fmt, args); va_end(args); if (error) return (error); - return kobject_add_complete(kobj, parent); + return kobject_add_complete(kobj); } int @@ -155,7 +169,7 @@ va_end(args); if (error) return (error); - return kobject_add_complete(kobj, parent); + return kobject_add_complete(kobj); } void @@ -166,6 +180,7 @@ kobj = container_of(kref, struct kobject, kref); sysfs_remove_dir(kobj); + kset_leave(kobj); name = kobj->name; if (kobj->ktype && kobj->ktype->release) kobj->ktype->release(kobj); @@ -219,3 +234,121 @@ .show = lkpi_kobj_attr_show, .store = lkpi_kobj_attr_store, }; + +const struct kobj_type linux_kset_kfree_type = { + .release = kset_kfree +}; + +static struct kset * +kset_create(const char *name, + const struct kset_uevent_ops *uevent_ops, + struct kobject *parent_kobj) +{ + struct kset *kset; + + kset = kzalloc(sizeof(*kset), GFP_KERNEL); + if (kset == NULL) + return (NULL); + + kset->uevent_ops = uevent_ops; + + kobject_set_name(&kset->kobj, "%s", name); + kset->kobj.parent = parent_kobj; + kset->kobj.kset = NULL; + + return (kset); +} + +void +kset_init(struct kset *kset) +{ + kobject_init(&kset->kobj, &linux_kset_kfree_type); + INIT_LIST_HEAD(&kset->list); + spin_lock_init(&kset->list_lock); +} + +static void +kset_join(struct kobject *kobj) +{ + struct kset *kset; + + kset = kobj->kset; + if (kset == NULL) + return; + + kset_get(kobj->kset); + + spin_lock(&kset->list_lock); + list_add_tail(&kobj->entry, &kset->list); + spin_unlock(&kset->list_lock); +} + +static void +kset_leave(struct kobject *kobj) +{ + struct kset *kset; + + kset = kobj->kset; + if (kset == NULL) + return; + + spin_lock(&kset->list_lock); + list_del_init(&kobj->entry); + spin_unlock(&kset->list_lock); + + kset_put(kobj->kset); +} + +struct kset * +kset_create_and_add(const char *name, const struct kset_uevent_ops *u, + struct kobject *parent_kobj) +{ + int ret; + struct kset *kset; + + kset = kset_create(name, u, parent_kobj); + if (kset == NULL) + return (NULL); + + ret = kset_register(kset); + if (ret != 0) { + linux_kobject_kfree_name(&kset->kobj); + kfree(kset); + return (NULL); + } + + return (kset); +} + +int +kset_register(struct kset *kset) +{ + int ret; + + if (kset == NULL) + return -EINVAL; + + kset_init(kset); + ret = kobject_add_complete(&kset->kobj); + + return ret; +} + +void +kset_unregister(struct kset *kset) +{ + if (kset == NULL) + return; + + kobject_del(&kset->kobj); + kobject_put(&kset->kobj); +} + +static void +kset_kfree(struct kobject *kobj) +{ + struct kset *kset; + + kset = to_kset(kobj); + kfree(kset); +}