101 kobject:驱动的基石

一、kobject:驱动的基石

构建一个 kobject对象

构建一个sysfs中的目录项( kernfs_node )。

把他们关联起来。

struct kobject

struct kernfs_node {
    atomic_t        count;
    atomic_t        active;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lockdep_map  dep_map;
#endif
    /*  
     * Use kernfs_get_parent() and kernfs_name/path() instead of
     * accessing the following two fields directly.  If the node is
     * never moved to a different parent, it is safe to access the
     * parent directly.
     */
    struct kernfs_node  *parent;
    const char      *name;

    struct rb_node      rb; 

    const void      *ns;    /* namespace tag */
    unsigned int        hash;   /* ns + name hash */
    union {
        struct kernfs_elem_dir      dir;
        struct kernfs_elem_symlink  symlink;
        struct kernfs_elem_attr     attr;
    };  

    void            *priv;

    unsigned short      flags;
    umode_t         mode;
    unsigned int        ino;
    struct kernfs_iattrs    *iattr;
};

二、重点

关注 sysfs目录项kobject对象 的关联过程。

关注 kobject对象 默认的属性文件操作接口 (操作接口 -> 目录 -> kobject)。

使用 kobject_create_and_add 函数:创建一个 kobject 对象,指定其名字和父节点;并在 sysfs 中创建一个对应的目录项。

三、kobject_create_and_add()函数

定义在:lib/kobject.c

/* 可以分为两步 */
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{
	struct kobject *kobj;
	int retval;
	/* 1、创建并初始化一个kobject对象。
	 * 定义见下。
	 */
	kobj = kobject_create();
	if (!kobj)
		return NULL;
	/* 2、创建1个sysfs目录项 kernfs_node,并与 kobject对象 关联。
	 * 详见下。
	 */
	retval = kobject_add(kobj, parent, "%s", name);
	if (retval) {
		pr_warn("%s: kobject_add error: %d\n", __func__, retval);
		kobject_put(kobj);
		kobj = NULL;
	}
	return kobj;
}

1、kobject_create()函数

lib/kobject.c

struct kobject *kobject_create(void)
{
	struct kobject *kobj;
	/* 动态申请内存,存放kobject对象 */
	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
	if (!kobj)
		return NULL;
	/* 初始化 kobject 的 ktype成员(sysfs相关的操作集)。
	 * 创建的 kobject 的 ktype成员 都会被初始化为 dynamic_kobj_ktype。
	 * 定义见下。
	 */
	kobject_init(kobj, &dynamic_kobj_ktype);
	return kobj;
}
static struct kobj_type dynamic_kobj_ktype = {
	.release	= dynamic_kobj_release,
	.sysfs_ops	= &kobj_sysfs_ops,
};
/* kobject对象属性文件的读写接口 */
const struct sysfs_ops kobj_sysfs_ops = {
	.show	= kobj_attr_show,
	.store	= kobj_attr_store,
};
kobject_init()函数

lib/kobject.c

void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
...
	/* 初始化 kobject 结构体内部的一些标志位。
	 * 详见下。 
	 */
	kobject_init_internal(kobj);
	/*设置目录属性文件的操作接口*/
	kobj->ktype = ktype;
	return;
...
}
kobject_init_internal()函数

lib/kobject.c

/* 主要是初始化 kobject 内部的一些标志位 */
static void kobject_init_internal(struct kobject *kobj)
{
	if (!kobj)
		return;
	/* 将kobject的引用计数设置为1 */
	kref_init(&kobj->kref);
	/* 初始化链表节点 */
	INIT_LIST_HEAD(&kobj->entry);
	/* 该kobject对象还没和sysfs目录项关联 */
	kobj->state_in_sysfs = 0;
	kobj->state_add_uevent_sent = 0;
	kobj->state_remove_uevent_sent = 0;
	/* kobject对象的初始化标志 */
	kobj->state_initialized = 1;
}

2、kobject_add()函数

lib/kobject.c
/* sysfs 创建一个目录项并与 kobject对象 关联 */
retval = kobject_add(kobj, parent, “%s”, name);

/* parent 指向上一级的 kobject */
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()函数

lib/kobject.c

static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
					   struct kobject *parent,
					   const char *fmt, va_list vargs)
{
	int retval;
	/* 初始化 kobject->name
	 * 详见下 
	 */
	retval = kobject_set_name_vargs(kobj, fmt, vargs);
	if (retval) {
		pr_err("kobject: can not set name properly!\n");
		return retval;
	}
	/* 第一次设置kobj的parent指针。 
	 * parent 成员指向上一层的 kobject节点。
	 */
	kobj->parent = parent;
	/* 详见下 */
	return kobject_add_internal(kobj);
}
kobject_set_name_vargs()函数

lib/kobject.c

int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
				  va_list vargs)
{
	const char *s;
	...
	/* 参数格式化打印到s字符串中 */
	s = kvasprintf_const(GFP_KERNEL, fmt, vargs);
	...
	/* 设置kobject对象的名称 */
	kobj->name = s;
	...
}
	
kobject_add_internal()函数

lib/kobject.c

static int kobject_add_internal(struct kobject *kobj)
{
	struct kobject *parent;
	...
	parent = kobject_get(kobj->parent);
	
	if (kobj->kset) {
		/* 如果parent为空,parent设置为 kobj->kset->kobj */
		if (!parent)
			parent = kobject_get(&kobj->kset->kobj);
		/* 把该 kobject 加入到 kset 链表的末尾 */
		kobj_kset_join(kobj);
		/* 第二次设置kobj的parent指针 */
		kobj->parent = parent;
	}
	...
	/* 此函数负责在 sysfs 下创建目录项 
	 * 详见下
	 */
	error = create_dir(kobj);
	...
	kobj->state_in_sysfs = 1;
	...
}
create_dir()函数

lib/kobject.c

static int create_dir(struct kobject *kobj)
{
	const struct kobj_ns_type_operations *ops;
	int error;
	/* 详见下 */
	error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));
	...
}
sysfs_create_dir_ns()函数

fs/sysfs/dir.c

int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
{
	/* 
	 * 此结构体类型对应一个 sysfs 目录节点
	 */
	struct kernfs_node *parent, *kn;
	kuid_t uid;
	kgid_t gid;

	BUG_ON(!kobj);
	
	/* 注意这里的 parent是用来指定 kernfs_node 的上层节点 */
	if (kobj->parent)
		/* 获取上一层节点的目录项 */
		parent = kobj->parent->sd;
	else
		/* 设置上一层节点的目录项为 sysfs 根目录 */
		parent = sysfs_root_kn;

	if (!parent)
		return -ENOENT;
	/* 创建的1个 kernfs_node 节点。
	 * 详见下。 
	 */
	kn = kernfs_create_dir_ns(parent, kobject_name(kobj),
				  S_IRWXU | S_IRUGO | S_IXUGO, uid, gid,
				  kobj, ns);
	...
	/* kobj对象关联sysfs目录项,另一个方向上关联 */
	kobj->sd = kn;
	return 0;
}
kernfs_create_dir_ns()函数
struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
					 const char *name, umode_t mode,
					 kuid_t uid, kgid_t gid,
					 void *priv, const void *ns)
{
	struct kernfs_node *kn;
	int rc;

	/* allocate 
	 * 详见下
	 */
	kn = kernfs_new_node(parent, name, mode | S_IFDIR,
			     uid, gid, KERNFS_DIR);
	...
	/* 将 sysfs 目录项关联 kobject 对象,一个方向上关联 */
	kn->priv = priv;
	...
}
kernfs_new_node()函数
struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
				    const char *name, umode_t mode,
				    kuid_t uid, kgid_t gid,
				    unsigned flags)
{
	struct kernfs_node *kn;
	/* 创建一个 kernfs_node 类型变量 */
	kn = __kernfs_new_node(kernfs_root(parent),
			       name, mode, uid, gid, flags);
	if (kn) {
		kernfs_get(parent);
		kn->parent = parent;
	}
	return kn;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值