searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

linux kobject和ktype介绍

2024-12-05 09:24:34
1
0

Linux 内核用 kobject 来表示一个内核对象,它在源码中的定义为:

struct kobject {
	// 用来表示该内核对象的名称。如果该内核对象加入系统,那么它的 name 将会出现在
	// sysfs 文件系统中(表现形式是一个新的目录名)
	const char		*name;
	struct list_head	entry; // 用来将一系列的内核对象构成链表
	// 指向该内核对象的上层节点。通过引入该成员构建内核对象之间的层次化关系
	struct kobject		*parent; 
	// 当前内核对象所属的 kset 对象的指针。 kset 对象代表一个 subsystem,其中容纳了一系
	// 列同类型的 kobject 对象
	struct kset		*kset;
	// 定义了该内核对象的一组 sysfs 文件系统相关的操作函数和属性
	// 内核通过 ktype 成员将 kobject 对象的 sysfs 文件操作与其属性文件关联起来
	struct kobj_type	*ktype;
	// 用来表示该内核对象在 sysfs 文件系统中对应的目录项的实例
	struct kernfs_node	*sd; /* sysfs directory entry */
	// 其核心数据是一原子型变量,用来表示内核对象的引用计数。
	// 内核通过该成员追踪内核对象的生命周期
	struct kref		kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
	struct delayed_work	release;
#endif
	unsigned int state_initialized:1; // 表示该 kobject 所代表的内核对象初始化的状态
	unsigned int state_in_sysfs:1; // 表示该 kobject 所代表的内核对象有没有在 sysfs 文件中建立一个入口点
	unsigned int state_add_uevent_sent:1;
	unsigned int state_remove_uevent_sent:1;
	// 如果该 kobject 对象隶属于某一 kset, 那么它的状态变化可以导致其所在的 kset 对象向
	// 用户空间发送 event 消息。成员 uevent_suppress 用来表示当该 kobject 状态发生变化时,是
	// 否让其所在的 kset 向用户空间发送 event 消息。
	unsigned int uevent_suppress:1;
};

kobject 对象上的一些常用的操作函数:
kobject_set_name
看着复杂,其实就是赋值kobject->name

// 为一个kobject设置名字
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
{
	va_list vargs;
	int retval;

	va_start(vargs, fmt);
	retval = kobject_set_name_vargs(kobj, fmt, vargs);
	va_end(vargs);

	return retval;
}

kobject_init
初始化一个内核对象的 kobject 结构

void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
	...

	kobject_init_internal(kobj);
	kobj->ktype = ktype; // 设置ktype
	return;
}

// 真正的初始化工作发生在 kobject_init_internal 中
static void kobject_init_internal(struct kobject *kobj)
{
	if (!kobj)
		return;
	kref_init(&kobj->kref); // 将 kobject 的引用计数 refcount 初始化为 1
	INIT_LIST_HEAD(&kobj->entry);
	kobj->state_in_sysfs = 0; // 表示该内核对象尚未出现在 sysfs 文件树中
	kobj->state_add_uevent_sent = 0;
	kobj->state_remove_uevent_sent = 0;
	kobj->state_initialized = 1; // 置为 1 表示该内核对象已被初始化
}

kobject_add
主要功能有两个,一是建立 kobject 对象间的层次关系,二是在 sysfs 文件系统中建立一个目录。

int kobject_add(struct kobject *kobj, struct kobject *parent,
		const char *fmt, ...)
{
	va_list args;
	int retval;

        ...

	va_start(args, fmt);
	retval = kobject_add_varg(kobj, parent, fmt, args);
	va_end(args);

	return retval;
}

在kobject_add_varg函数中调用kobject_add_internal完成目录创建:

static int kobject_add_internal(struct kobject *kobj)
{
	int error = 0;
	struct kobject *parent;

	if (!kobj)
		return -ENOENT;

	if (!kobj->name || !kobj->name[0]) {
		WARN(1, "kobject: (%p): attempted to be registered with empty "
			 "name!\n", kobj);
		return -EINVAL;
	}

	parent = kobject_get(kobj->parent);

	/* join kset if set, use it as parent if we do not already have one */
	if (kobj->kset) {
		if (!parent)
			parent = kobject_get(&kobj->kset->kobj);
		kobj_kset_join(kobj); // 将 kobj 加入到所属 kset 链表的末尾
		// 把该 kobj->parent 或者 kset 中的 kobject 成员作为 kobj 的 parent
		kobj->parent = parent;
	}
	// 在 kobj 没有所属的 kset 的情况下
	pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
		 kobject_name(kobj), kobj, __func__,
		 parent ? kobject_name(parent) : "<NULL>",
		 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
	// 在 sysfs 文件系统中为指定的 kobject 创建一个目录,并对其进行初始化和配置
	error = create_dir(kobj);
	if (error) {
		...
	} else
		kobj->state_in_sysfs = 1;

	return error;
}

kobject_create
分配并初始化一个 kobject 对象,这里会传入默认的ktype对象dynamic_kobj_ktype

struct kobject *kobject_create(void)
{
	struct kobject *kobj;

	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
	if (!kobj)
		return NULL;

	kobject_init(kobj, &dynamic_kobj_ktype);
	return kobj;
}

为一个 kobject 对象创建一个属性文件使用的函数为 sysfs_create_file

static inline int __must_check sysfs_create_file(struct kobject *kobj,
						 const struct attribute *attr)
{
	return sysfs_create_file_ns(kobj, attr, NULL);
}

int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
			 const void *ns)
{
	BUG_ON(!kobj || !kobj->sd || !attr);

	return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, ns);

}

在内核中 struct kobj_type的定义为:

struct kobj_type {
	void (*release)(struct kobject *kobj);
	// 定义了一组针对 struct attribute 对象的操作函数的集合
	const struct sysfs_ops *sysfs_ops;
	// kobject 内核对象定义的属性成员
	struct attribute **default_attrs;
	const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
	const void *(*namespace)(struct kobject *kobj);
};

成员 sysfs_ops 是一 struct sysfs_ops 类型的指针, struct sysfs_ops 和struct attribute的定义为:

struct sysfs_ops {
	ssize_t	(*show)(struct kobject *, struct attribute *, char *);
	ssize_t	(*store)(struct kobject *, struct attribute *, const char *, size_t);
};

struct attribute {
	const char		*name;
	umode_t			mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	bool			ignore_lockdep:1;
	struct lock_class_key	*key;
	struct lock_class_key	skey;
#endif
};
0条评论
作者已关闭评论
c****q
8文章数
0粉丝数
c****q
8 文章 | 0 粉丝
原创

linux kobject和ktype介绍

2024-12-05 09:24:34
1
0

Linux 内核用 kobject 来表示一个内核对象,它在源码中的定义为:

struct kobject {
	// 用来表示该内核对象的名称。如果该内核对象加入系统,那么它的 name 将会出现在
	// sysfs 文件系统中(表现形式是一个新的目录名)
	const char		*name;
	struct list_head	entry; // 用来将一系列的内核对象构成链表
	// 指向该内核对象的上层节点。通过引入该成员构建内核对象之间的层次化关系
	struct kobject		*parent; 
	// 当前内核对象所属的 kset 对象的指针。 kset 对象代表一个 subsystem,其中容纳了一系
	// 列同类型的 kobject 对象
	struct kset		*kset;
	// 定义了该内核对象的一组 sysfs 文件系统相关的操作函数和属性
	// 内核通过 ktype 成员将 kobject 对象的 sysfs 文件操作与其属性文件关联起来
	struct kobj_type	*ktype;
	// 用来表示该内核对象在 sysfs 文件系统中对应的目录项的实例
	struct kernfs_node	*sd; /* sysfs directory entry */
	// 其核心数据是一原子型变量,用来表示内核对象的引用计数。
	// 内核通过该成员追踪内核对象的生命周期
	struct kref		kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
	struct delayed_work	release;
#endif
	unsigned int state_initialized:1; // 表示该 kobject 所代表的内核对象初始化的状态
	unsigned int state_in_sysfs:1; // 表示该 kobject 所代表的内核对象有没有在 sysfs 文件中建立一个入口点
	unsigned int state_add_uevent_sent:1;
	unsigned int state_remove_uevent_sent:1;
	// 如果该 kobject 对象隶属于某一 kset, 那么它的状态变化可以导致其所在的 kset 对象向
	// 用户空间发送 event 消息。成员 uevent_suppress 用来表示当该 kobject 状态发生变化时,是
	// 否让其所在的 kset 向用户空间发送 event 消息。
	unsigned int uevent_suppress:1;
};

kobject 对象上的一些常用的操作函数:
kobject_set_name
看着复杂,其实就是赋值kobject->name

// 为一个kobject设置名字
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
{
	va_list vargs;
	int retval;

	va_start(vargs, fmt);
	retval = kobject_set_name_vargs(kobj, fmt, vargs);
	va_end(vargs);

	return retval;
}

kobject_init
初始化一个内核对象的 kobject 结构

void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
	...

	kobject_init_internal(kobj);
	kobj->ktype = ktype; // 设置ktype
	return;
}

// 真正的初始化工作发生在 kobject_init_internal 中
static void kobject_init_internal(struct kobject *kobj)
{
	if (!kobj)
		return;
	kref_init(&kobj->kref); // 将 kobject 的引用计数 refcount 初始化为 1
	INIT_LIST_HEAD(&kobj->entry);
	kobj->state_in_sysfs = 0; // 表示该内核对象尚未出现在 sysfs 文件树中
	kobj->state_add_uevent_sent = 0;
	kobj->state_remove_uevent_sent = 0;
	kobj->state_initialized = 1; // 置为 1 表示该内核对象已被初始化
}

kobject_add
主要功能有两个,一是建立 kobject 对象间的层次关系,二是在 sysfs 文件系统中建立一个目录。

int kobject_add(struct kobject *kobj, struct kobject *parent,
		const char *fmt, ...)
{
	va_list args;
	int retval;

        ...

	va_start(args, fmt);
	retval = kobject_add_varg(kobj, parent, fmt, args);
	va_end(args);

	return retval;
}

在kobject_add_varg函数中调用kobject_add_internal完成目录创建:

static int kobject_add_internal(struct kobject *kobj)
{
	int error = 0;
	struct kobject *parent;

	if (!kobj)
		return -ENOENT;

	if (!kobj->name || !kobj->name[0]) {
		WARN(1, "kobject: (%p): attempted to be registered with empty "
			 "name!\n", kobj);
		return -EINVAL;
	}

	parent = kobject_get(kobj->parent);

	/* join kset if set, use it as parent if we do not already have one */
	if (kobj->kset) {
		if (!parent)
			parent = kobject_get(&kobj->kset->kobj);
		kobj_kset_join(kobj); // 将 kobj 加入到所属 kset 链表的末尾
		// 把该 kobj->parent 或者 kset 中的 kobject 成员作为 kobj 的 parent
		kobj->parent = parent;
	}
	// 在 kobj 没有所属的 kset 的情况下
	pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
		 kobject_name(kobj), kobj, __func__,
		 parent ? kobject_name(parent) : "<NULL>",
		 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
	// 在 sysfs 文件系统中为指定的 kobject 创建一个目录,并对其进行初始化和配置
	error = create_dir(kobj);
	if (error) {
		...
	} else
		kobj->state_in_sysfs = 1;

	return error;
}

kobject_create
分配并初始化一个 kobject 对象,这里会传入默认的ktype对象dynamic_kobj_ktype

struct kobject *kobject_create(void)
{
	struct kobject *kobj;

	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
	if (!kobj)
		return NULL;

	kobject_init(kobj, &dynamic_kobj_ktype);
	return kobj;
}

为一个 kobject 对象创建一个属性文件使用的函数为 sysfs_create_file

static inline int __must_check sysfs_create_file(struct kobject *kobj,
						 const struct attribute *attr)
{
	return sysfs_create_file_ns(kobj, attr, NULL);
}

int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
			 const void *ns)
{
	BUG_ON(!kobj || !kobj->sd || !attr);

	return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, ns);

}

在内核中 struct kobj_type的定义为:

struct kobj_type {
	void (*release)(struct kobject *kobj);
	// 定义了一组针对 struct attribute 对象的操作函数的集合
	const struct sysfs_ops *sysfs_ops;
	// kobject 内核对象定义的属性成员
	struct attribute **default_attrs;
	const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
	const void *(*namespace)(struct kobject *kobj);
};

成员 sysfs_ops 是一 struct sysfs_ops 类型的指针, struct sysfs_ops 和struct attribute的定义为:

struct sysfs_ops {
	ssize_t	(*show)(struct kobject *, struct attribute *, char *);
	ssize_t	(*store)(struct kobject *, struct attribute *, const char *, size_t);
};

struct attribute {
	const char		*name;
	umode_t			mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	bool			ignore_lockdep:1;
	struct lock_class_key	*key;
	struct lock_class_key	skey;
#endif
};
文章来自个人专栏
驱动
5 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0