linuxkpi: Add struct kset support in <linux/kobject.h>

[Why]
The amdgpu DRM driver started to use it in Linux 5.18.

Reviewed by:	manu
Approved by:	manu
Differential Revision:	https://reviews.freebsd.org/D43020
This commit is contained in:
Jean-Sébastien Pédron 2023-12-08 22:51:10 +01:00
parent d6d1e73e5f
commit fe84281803
No known key found for this signature in database
GPG key ID: 39E99761A5FD94CC
2 changed files with 186 additions and 4 deletions

View file

@ -35,8 +35,10 @@
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
struct kobject;
struct kset;
struct sysctl_oid;
#define KOBJ_CHANGE 0x01
@ -57,6 +59,7 @@ struct kobject {
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 @@ struct kobj_attribute {
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 @@ kobject_uevent_env(struct kobject *kobj, int action, char *envp[])
*/
}
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_ */

View file

@ -30,6 +30,10 @@
#include <linux/kobject.h>
#include <linux/sysfs.h>
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 @@ kobject_set_name(struct kobject *kobj, const char *fmt, ...)
}
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 @@ kobject_add_complete(struct kobject *kobj, struct kobject *parent)
if (error)
sysfs_remove_dir(kobj);
}
if (error != 0)
kset_leave(kobj);
return (error);
}
@ -129,13 +141,15 @@ kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
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 @@ kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
va_end(args);
if (error)
return (error);
return kobject_add_complete(kobj, parent);
return kobject_add_complete(kobj);
}
void
@ -166,6 +180,7 @@ linux_kobject_release(struct kref *kref)
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 @@ const struct sysfs_ops kobj_sysfs_ops = {
.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);
}