aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Sébastien Pédron <dumbbell@FreeBSD.org>2023-12-08 21:51:10 +0000
committerJean-Sébastien Pédron <dumbbell@FreeBSD.org>2023-12-13 18:57:52 +0000
commitfe84281803d62a6846ecab5f5a7c8b4e49b0f0e0 (patch)
treefc3b6eb3f8f7e4a646bfbac4401c36cc39fb5b8a
parentd6d1e73e5f66f3b12881fffceff58ca54b506792 (diff)
downloadsrc-fe84281803d62a6846ecab5f5a7c8b4e49b0f0e0.tar.gz
src-fe84281803d62a6846ecab5f5a7c8b4e49b0f0e0.zip
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
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kobject.h49
-rw-r--r--sys/compat/linuxkpi/common/src/linux_kobject.c141
2 files changed, 186 insertions, 4 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h
index 06d71faaa873..dadf3b3b0849 100644
--- a/sys/compat/linuxkpi/common/include/linux/kobject.h
+++ b/sys/compat/linuxkpi/common/include/linux/kobject.h
@@ -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_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_kobject.c b/sys/compat/linuxkpi/common/src/linux_kobject.c
index ddd0a58660f1..02f8b8d5b709 100644
--- a/sys/compat/linuxkpi/common/src/linux_kobject.c
+++ b/sys/compat/linuxkpi/common/src/linux_kobject.c
@@ -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);
+}