总结写在最前面,后面代码解释,我自己都看着烦躁:
subsystem_register它首先是要有一个subsystem结构的数据,然后这个结构里的kset需要设置,而kset最重要的是kobject,kobject中的又要有目录项之类的,而这个目录文件要是没有指定父节点,缺省状态下是挂载在sysfs的根目录下的。
从这行代码subsystem_register(&fs_subsys);来简单分析subsystem_register
Fs_subsys定义:
decl_subsys(fs, NULL, NULL);
#define decl_subsys(_name,_type,_uevent_ops) \
struct subsystem _name##_subsys = { \
.kset = { \
.kobj = { .name = __stringify(_name) }, \
.ktype = _type, \
.uevent_ops =_uevent_ops, \
} \
}
subsystem的数据结构:
struct subsystem {
struct kset kset;
struct rw_semaphore rwsem;
};
/**
* subsystem_register - register a subsystem.
* @s: thesubsystem we're registering.
*
* Oncewe register the subsystem, we want to make sure that
* thekset points back to this subsystem for correct usage of
* therwsem.
*/
红字部分清晰的说明了这个函数的作用,就是用来注册一个子系统的
intsubsystem_register(struct subsystem * s)
{
……
if(!(error = kset_add(&s->kset)))
……
}
/**
* kset_add- add a kset object to the hierarchy.
* @k: kset.
*
* Simply, this adds the kset's embedded kobject to the
* hierarchy.
* Wealso try to make sure that the kset's embedded kobject
* hasa parent before it is added. We only care if the embedded
* kobjectis not part of a kset itself, since kobject_add()
* assignsa parent in that case.
* Ifthat is the case, and the kset has a controlling subsystem,
* thenwe set the kset's parent to be said subsystem.
*/
正如红字注释所说,这个函数的功能是增加kset自身的kobject
int kset_add(structkset * k)
{
if(!k->kobj.parent && !k->kobj.kset &&k->subsys) //如果没有父节点,没有kset,有subsys
k->kobj.parent=&k->subsys->kset.kobj; //父节点为子节点的设置对象
return kobject_add(&k->kobj);//增加对象
}
增加kset的对象到它所要求的阶层,红字代码为具体操作
/**
* kobject_add- add an object to the hierarchy.
* @kobj: object.
*/
intkobject_add(struct kobject * kobj)
{
returnkobject_shadow_add(kobj, NULL);
}
/**
* kobject_add- add an object to the hierarchy.
* @kobj: object. //如果是device之类的subsystem,这里的kobj已经是k->kset->kobj了,且只有name属性
* @shadow_parent:sysfs directory to add to.
*/
intkobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
注意红字部分的NULL和shadow_parent,可以看出注册fs这个子系统的时候,shadow_parent是NULL,还要特别关注它的类型,dentry,是不是很亲切,就是文件系统中的目录
截取个人认为kobject_shadow_add函数中最重要的几行代码
if (kobj->kset) { //前提是kset要存在,如果是device,fs的subsystem 这项应该不存在
spin_lock(&kobj->kset->list_lock);
if (!parent)
parent = kobject_get(&kobj->kset->kobj); //如果父节点不存在,kset的对象就是父节点
//如platform_type_bus的kobj->kset->kobj 就是device_subsys->kset->kobj
//其实可以这么理解,如果父节点也没,kset也没,就直接挂在sys下
//如果有父节点就挂在父节点下,如果有kset就挂在kset下
list_add_tail(&kobj->entry,&kobj->kset->list); //将kobj->entry加到kset的链表中spin_unlock(&kobj->kset->list_lock);
}
kobj->parent = parent;
error = create_dir(kobj, shadow_parent); //初始化话生成一个dentry,顺带引出inode和sd(sysfs dirent)
//kobj->dentry=dentry
上面的两段红字代码很关键,第一个红字代码是要找到挂载对象的父节点;第二个红字代码是要将对象挂载到父节点上
static intcreate_dir(struct kobject * kobj, struct dentry *shadow_parent)
/**
* sysfs_create_dir- create a directory for an object.
* @kobj: objectwe're creating directory for.
* @shadow_parent: parentparent object.
*/
intsysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
如果shadow_parent为NULL,且kobj->parent为NULL,那么就挂载sysfs的根目录下
parent =sysfs_mount->mnt_sb->s_root; //sysfs文件系统的根目录
error =create_dir(kobj,parent,kobject_name(kobj),&dentry); //对象,父节点,名字,要赋值的dentry
//这个函数的功能就是初始化dentry,顺带inode,sd(sysfsdirent)
//dentry->d_fsdata=sd,dentry->d_inode=inode ,sd->elememt=kobj,dentry->d_parent=partent
static int create_dir(struct kobject * k, struct dentry * p,
const char * n, struct dentry ** d)
{
int error;
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
mutex_lock(&p->d_inode->i_mutex);
*d = lookup_one_len(n, p, strlen(n)); //查找是否已经存在,
//不存在alloc一个dentry,且d_parent为p
if (!IS_ERR(*d)) {
if (sysfs_dirent_exist(p->d_fsdata, n)) //如果存在相同元素,返回错误
error = -EEXIST;
else
error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
SYSFS_DIR); //生成一个新的sd,sd->s_sibing挂载p->fsdata->s_children
//dentry->d_fsdata=sd
//上面两行注释结合,得出子sb挂载在父sb上
//sd->elememt=kobj
//dentry->d_op赋值
if (!error) { //sysfs_make_dirent这个执行成功
error = sysfs_create(*d, mode, init_dir); //init_dir是初始化一个新的inode
//创建一个新的索引节点inode
//d->d_inode =inode //d:dentry
if (!error) {
inc_nlink(p->d_inode);
(*d)->d_op = &sysfs_dentry_ops;
d_rehash(*d);
}
}
if (error && (error != -EEXIST)) {
struct sysfs_dirent *sd = (*d)->d_fsdata;
if (sd) {
list_del_init(&sd->s_sibling);
sysfs_put(sd);
}
d_drop(*d);
}
dput(*d);
} else
error = PTR_ERR(*d);
mutex_unlock(&p->d_inode->i_mutex);
return error;
}
综上所述,再结合上面的图,sysfs也有inode,dentry,但是多了一个新的东西,sd(sysfs dentry),这个结构是sysfs特有的,它挂载dentry->d_fsdata上,且它的s_element指向了kobj。另外一层的意义,即使不用dentry,也可以用sd来索引目录,操作之类的。
struct sysfs_dirent{
atomic_t s_count;
structlist_head s_sibling;
structlist_head s_children;
void *s_element;
int s_type;
umode_t s_mode;
structdentry *s_dentry;
structiattr *s_iattr;
atomic_t s_event;
};