I.MX6ULL内核开发9:kobject-驱动的基石
目录
一、摘要
二、重点
三、驱动结构模型
四、关键函数分析
kobject_create_and_add()函数
kobject_create()函数
kobject_init()函数
kobject_init_internal()函数
kobject_add()函数
kobject_add_varg()函数
kobject_set_name_vargs()函数
kobject_add_internal()函数
create_dir()函数
sysfs_create_dir_ns()函数
一、摘要
- 构建一个kobject对象
- 构建一个sysfs中的目录项(kernfs_node)
- 把他们关联起来
二、重点
- 关注sysfs目录项与kobject对象的关联过程
- 关注kobject对象默认的属性文件接口
三、驱动结构模型
四、关键函数分析
kobject_create_and_add()函数
/home/geralt/linux_driver/kernel/ebf_linux_kernel_6ull_depth1/lib/kobject.c
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{struct kobject *kobj;int retval;// 创建并初始化kobj = kobject_create();if (!kobj)return NULL;// sysfs创建一个目录项并与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;
}
kobject_create()函数
/home/geralt/linux_driver/kernel/ebf_linux_kernel_6ull_depth1/lib/kobject.c
struct kobject *kobject_create(void)
{struct kobject *kobj;// 动态申请内存,存放kobject对象kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);if (!kobj)return NULL;kobject_init(kobj, &dynamic_kobj_ktype);return kobj;
}
static struct kobj_type dynamic_kobj_ktype = {.release = dynamic_kobj_release,.sysfs_ops = &kobj_sysfs_ops,
};
const struct sysfs_ops kobj_sysfs_ops = {.show = kobj_attr_show,.store = kobj_attr_store,
};
kobject_init()函数
/home/geralt/linux_driver/kernel/ebf_linux_kernel_6ull_depth1/lib/kobject.c
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{char *err_str;if (!kobj) {err_str = "invalid kobject pointer!";goto error;}if (!ktype) {err_str = "must have a ktype to be initialized properly!\n";goto error;}if (kobj->state_initialized) {/* do not error out as sometimes we can recover */pr_err("kobject (%p): tried to init an initialized object, something is seriously wrong.\n",kobj);dump_stack();}kobject_init_internal(kobj);kobj->ktype = ktype;return;error:pr_err("kobject (%p): %s\n", kobj, err_str);dump_stack();
}
kobject_init_internal()函数
home/geralt/linux_driver/kernel/ebf_linux_kernel_6ull_depth1/lib/kobject.c
static void kobject_init_internal(struct kobject *kobj)
{if (!kobj)return;// 将kobject的引用计数设置为1kref_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;
}
kobject_add()函数
home/geralt/linux_driver/kernel/ebf_linux_kernel_6ull_depth1/lib/kobject.c
int kobject_add(struct kobject *kobj, struct kobject *parent,const char *fmt, ...)
{va_list args;int retval;if (!kobj)return -EINVAL;if (!kobj->state_initialized) {pr_err("kobject '%s' (%p): tried to add an uninitialized object, something is seriously wrong.\n",kobject_name(kobj), kobj);dump_stack();return -EINVAL;}// 获取第一个可变参数,可变参数函数的实现与函数传参的栈结构有关va_start(args, fmt);retval = kobject_add_varg(kobj, parent, fmt, args);va_end(args);return retval;
}
kobject_add_varg()函数
home/geralt/linux_driver/kernel/ebf_linux_kernel_6ull_depth1/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;retval = kobject_set_name_vargs(kobj, fmt, vargs);if (retval) {pr_err("kobject: can not set name properly!\n");return retval;}// 第一次设置的kobj的parent指针kobj->parent = parent;return kobject_add_internal(kobj);
}
kobject_set_name_vargs()函数
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,va_list vargs)`
{const char *s;if (kobj->name && !fmt)return 0;// 参数格式化打印到s字符串中s = kvasprintf_const(GFP_KERNEL, fmt, vargs);if (!s)return -ENOMEM;/** ewww... some of these buggers have '/' in the name ... If* that's the case, we need to make sure we have an actual* allocated copy to modify, since kvasprintf_const may have* returned something from .rodata.*/if (strchr(s, '/')) {char *t;t = kstrdup(s, GFP_KERNEL);kfree_const(s);if (!t)return -ENOMEM;strreplace(t, '/', '!');s = t;}kfree_const(kobj->name);// 设置kobject对象的名称kobj->name = s;return 0;
}
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->parent = parent;}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>");error = create_dir(kobj);if (error) {kobj_kset_leave(kobj);kobject_put(parent);kobj->parent = NULL;/* be noisy on error issues */if (error == -EEXIST)pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n",__func__, kobject_name(kobj));elsepr_err("%s failed for %s (error: %d parent: %s)\n",__func__, kobject_name(kobj), error,parent ? kobject_name(parent) : "'none'");} elsekobj->state_in_sysfs = 1;return error;
}
create_dir()函数
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));if (error)return error;error = populate_dir(kobj);if (error) {sysfs_remove_dir(kobj);return error;}/** @kobj->sd may be deleted by an ancestor going away. Hold an* extra reference so that it stays until @kobj is gone.*/sysfs_get(kobj->sd);/** If @kobj has ns_ops, its children need to be filtered based on* their namespace tags. Enable namespace support on @kobj->sd.*/ops = kobj_child_ns_ops(kobj);if (ops) {BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);BUG_ON(ops->type >= KOBJ_NS_TYPES);BUG_ON(!kobj_ns_type_registered(ops->type));sysfs_enable_ns(kobj->sd);}return 0;
}
sysfs_create_dir_ns()函数
文件:/home/geralt/linux_driver/kernel/ebf_linux_kernel_6ull_depth1/fs/sysfs
int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
{struct kernfs_node *parent, *kn;kuid_t uid;kgid_t gid;BUG_ON(!kobj);if (kobj->parent)// 获取上一层节点的目录项parent = kobj->parent->sd;else// 设置上一层节点的目录项sysfsparent = sysfs_root_kn;if (!parent)return -ENOENT;kobject_get_ownership(kobj, &uid, &gid);kn = kernfs_create_dir_ns(parent, kobject_name(kobj),S_IRWXU | S_IRUGO | S_IXUGO, uid, gid,kobj, ns);if (IS_ERR(kn)) {if (PTR_ERR(kn) == -EEXIST)sysfs_warn_dup(parent, kobject_name(kobj));return PTR_ERR(kn);}// kobj对象关联sysfs目录项kobj->sd = kn;return 0;
}