http://www.sudu.cn/info/19700101/290381.html
浅析linux 2.6.23下kobject如何生成sysfs目录文件
文章来源:http://gliethttp.cublog.cn//kobject_add()->kobject_shadow_add()->初始化kobj->parent之后->调用下面的create_dir()
//1.该函数位于linux-2.6.23/lib/kobject.c->create_dir()
//将kobj实体登记到以shadow_parent为父类管理实体下
static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
{
int error = 0;
if (kobject_name(kobj)) {
error = sysfs_create_dir(kobj, shadow_parent);
if (!error) {
//将attr属性作为文件添加到kobj的目录下,
//具体实现细节和下面讨论的sysfs_create_dir()实现细节区别不大[gliethttp_20071130]
if ((error = populate_dir(kobj)))
sysfs_remove_dir(kobj);
}
}
return error;
}
//2.该函数位于linux-2.6.23/fs/sysfs/dir.c->sysfs_create_dir()
//通过creat_dir()合法性检查之后,进行实质性的登记注册工作
int sysfs_create_dir(struct kobject *kobj,struct sysfs_dirent *shadow_parent_sd)
{
struct sysfs_dirent *parent_sd, *sd;
int error = 0;
BUG_ON(!kobj);
if (shadow_parent_sd)//参数强制指定parent管理目录
parent_sd = shadow_parent_sd;
//kobject定义了自己的parent,一般在kobject_shadow_add()中被指定为kobj->kset->kobj
else if (kobj->parent)
parent_sd = kobj->parent->sd;
//如果上边两个都没有定义,那么就将这个kobj登记到sysfs_mount根目录下
else if (sysfs_mount && sysfs_mount->mnt_sb)
parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
else
return -EFAULT;
//经过上面的几个if语句运算之后,该kobject已经找到了将要管理自己的父类目录parent_sd
//调用linux-2.6.23/fs/sysfs/dir.c->create_dir()
error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
if (!error)
kobj->sd = sd;
return error;
}
//3.该函数位于linux-2.6.23/fs/sysfs/dir.c->create_dir()
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
const char *name, struct sysfs_dirent **p_sd)
{
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
struct sysfs_addrm_cxt acxt;
struct sysfs_dirent *sd;
sd = sysfs_new_dirent(name, mode, SYSFS_DIR);//从cache中获取一个slab对象
if (!sd)
return -ENOMEM;
//将本kobject放到该sd中,这样父类目录通过parent_sd->s_children以及sd->s_sibling兄弟链表,
//使用sd->s_elem.dir.kobj可以轻松的实现父类目录parent反向定位kobject
//(这有些类似于μC/GUI-v3.Array0a中窗体层次管理方式[gliethttp_20071130]);在下面的sysfs_add_one()
//函数中有这样一个赋值语句sd->s_parent=parent_sd;故而儿子kobject也可以轻松的正向锁定管理自己的父类目录;
//于是儿子kobject和老子parent_sd都能够顺利获得对方的全部信息,实现绝对的双向独立控制,
//任何一方都可以独立自主的提出解除在内核中维系了或长或短的父子关系[gliethttp_20071130]
sd->s_elem.dir.kobj = kobj;
//在sysfs_sb中通过hash短链,核查父目录parent_sd是否确实已经存在了,
//如果存在那么找到父目录的inode节点,赋值给acxt->parent_inode = inode;
sysfs_addrm_start(&acxt, parent_sd);
if (!sysfs_find_dirent(parent_sd, name)) {
//gliethttp_20071130
//如果name文件不存在于当前parent目录下,那么将sd添加进去
sysfs_add_one(&acxt, sd);
sysfs_link_sibling(sd);//很简单,就是把该sd链接到parent_sd管理的单向链表中
/*
void sysfs_link_sibling(struct sysfs_dirent *sd)
{struct sysfs_dirent *parent_sd = sd->s_parent;
BUG_ON(sd->s_sibling);
sd->s_sibling = parent_sd->s_children;
//本sd为parent_sd->s_children,sd->s_sibling链接着所有先前的儿子们,linux内核不搞计划生育
parent_sd->s_children = sd;
}
*/
}
if (!sysfs_addrm_finish(&acxt)) {
sysfs_put(sd);
return -EEXIST;
}
*p_sd = sd;
return 0;
}
//4.该函数位于linux-2.6.23/fs/sysfs/dir.c->sysfs_new_dirent()
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
{
char *dup_name = NULL;
struct sysfs_dirent *sd;
if (type & SYSFS_COPY_NAME) {
name = dup_name = kstrdup(name, GFP_KERNEL);//拷贝name到内核内存--kmalloc分配
if (!name)
return NULL;
}
//gliethttp_20071130
//从cachep内的slab对象链中摘掉一个空闲slab对象,返回给sd
//对于slab的理解可以参看《我看slab算法中"着色"[cachep->colour_off]的物理意义》
//
http://blog.chinaunix.net/u1/38ArrayArray4/showart_362336.html
sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
if (!sd)
goto err_out1;
//下面进行一些必要的初始默认值设置
if (sysfs_alloc_ino(&sd->s_ino))//通过ida和idr获取一个全新的inode节点号
goto err_out2;
atomic_set(&sd->s_count, 1);
atomic_set(&sd->s_active, 0);
atomic_set(&sd->s_event, 1);
sd->s_name = name;
sd->s_mode = mode;
sd->s_flags = type;
return sd;
err_out2:
kmem_cache_free(sysfs_dir_cachep, sd);
err_out1:
kfree(dup_name);
return NULL;
}
//5.该函数位于linux-2.6.23/fs/sysfs/dir.c->sysfs_find_dirent()
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
const unsigned char *name)
{
struct sysfs_dirent *sd;
//检查父类目录parent_sd管理的所有文件(目录和文件),即parent目录下,看看有没有和name重名的,
//如果有,那么冲突,否则ok[gliethttp_20071130]
for (sd = parent_sd->s_children; sd; sd = sd->s_sibling)
if (sysfs_type(sd) && !strcmp(sd->s_name, name))
return sd;
return NULL;
}
//综述:从宏观角度来看,生成一个sysfs目录、文件主要是完成管理kobject的sd结构体和parent_sd父类结构体的一个双向互知通信问题,至于复杂一些的dentry结构体,在sysfs中并没有出现,但是作为系统中文件唯一标识的inode是一定要在任何一个独立fs文件系统中提供的,以上的理解还比较粗浅,更深入的综合性研究还有待时间[gliethttp_20071130]