目录
一、摘要
二、重点
三、驱动结构模型
四、关键函数分析
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的引用计数设置为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;
}
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));
else
pr_err("%s failed for %s (error: %d parent: %s)\n",
__func__, kobject_name(kobj), error,
parent ? kobject_name(parent) : "'none'");
} else
kobj->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
// 设置上一层节点的目录项sysfs
parent = 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;
}