Linux文件系统之sysfs.docx
- 文档编号:6194932
- 上传时间:2023-01-04
- 格式:DOCX
- 页数:25
- 大小:24.49KB
Linux文件系统之sysfs.docx
《Linux文件系统之sysfs.docx》由会员分享,可在线阅读,更多相关《Linux文件系统之sysfs.docx(25页珍藏版)》请在冰豆网上搜索。
Linux文件系统之sysfs
Linux文件系统之sysfs
一:
前言
在设备模型中,sysfs文件系统用来表示设备的结构.将设备的层次结构形象的反应到用户空间中.用户空间可以修改sysfs中的文件属性来修改设备的属性值,今天我们就来详细分析一下,sysfs的实现.
二:
sysfs的初始化和挂载
Sysfs文件系统的初始化是在sysfs_init()中完成的,代码如下:
int__initsysfs_init(void)
{
interr=-ENOMEM;
//创建一个分配sysfs_dirent的cache
sysfs_dir_cachep=kmem_cache_create("sysfs_dir_cache",
sizeof(structsysfs_dirent),
0,0,NULL);
if(!
sysfs_dir_cachep)
gotoout;
err=sysfs_inode_init();
if(err)
gotoout_err;
//注册sysfs文件系统s
err=register_filesystem(&sysfs_fs_type);
if(!
err){
//挂载sysfs文件系统
sysfs_mount=kern_mount(&sysfs_fs_type);
if(IS_ERR(sysfs_mount)){
printk(KERN_ERR"sysfs:
couldnotmount!
\n");
err=PTR_ERR(sysfs_mount);
sysfs_mount=NULL;
unregister_filesystem(&sysfs_fs_type);
gotoout_err;
}
}else
gotoout_err;
out:
returnerr;
out_err:
kmem_cache_destroy(sysfs_dir_cachep);
sysfs_dir_cachep=NULL;
gotoout;
}
每个kobject对应sysfs中的一个目录,kobject的每个属性对应sysfs文件系统中的文件.
structsysfs_dirent就是用来做kobject与dentry的互相转换用的.它们的关系如下图所示:
上图表示的是一个kobject的层次结构.dentry的d_fsdata字段指定该结点所表示的sysfs_dirent.sysfs_dirent.s_parent表示它的父kobject.sysfs_dirent.s_sibling表示它的兄弟结点.sysfs_dirent.s_dir.children表示它所属的子节点.
从上图可知.如果要遍历一个结点下面的子结点,只需要找到sysfs_dirent.s_dir.children结点
然后按着子节点的s_sibling域遍历即可.
当然,有时候也需要从structsysfs_dirent导出它所属的dentry结点.我们在代码中遇到的时候再进行分析.
Sysfs文件系统的file_system_type定义如下:
staticstructfile_system_typesysfs_fs_type={
.name="sysfs",
.get_sb=sysfs_get_sb,
.kill_sb=kill_anon_super,
};
通过前面文件系统的相关分析,我们知道在sys_mount()中最终会调用structfile_system_type的get_sb函数来实现文件系统的挂载.它的代码如下:
staticintsysfs_get_sb(structfile_system_type*fs_type,
intflags,constchar*dev_name,void*data,structvfsmount*mnt)
{
returnget_sb_single(fs_type,flags,data,sysfs_fill_super,mnt);
}
get_sb_single()的代码在前面已经涉及到,它对super_block.以及挂载的dentry和inode的赋值是在回调函数sysfs_fill_super,mnt()中完成的.代码如下:
staticintsysfs_fill_super(structsuper_block*sb,void*data,intsilent)
{
structinode*inode;
structdentry*root;
sb->s_blocksize=PAGE_CACHE_SIZE;
sb->s_blocksize_bits=PAGE_CACHE_SHIFT;
sb->s_magic=SYSFS_MAGIC;
sb->s_op=&sysfs_ops;
sb->s_time_gran=1;
sysfs_sb=sb;
/*getrootinode,initializeandunlockit*/
inode=sysfs_get_inode(&sysfs_root);
if(!
inode){
pr_debug("sysfs:
couldnotgetrootinode\n");
return-ENOMEM;
}
/*instantiateandlinkrootdentry*/
root=d_alloc_root(inode);
if(!
root){
pr_debug("%s:
couldnotgetrootdentry!
\n",__FUNCTION__);
iput(inode);
return-ENOMEM;
}
//将sysfs_root关联到root
root->d_fsdata=&sysfs_root;
sb->s_root=root;
return0;
}
在这里要注意几个全局量.sysfs_sb表示sysfs文件系统的super_block.sysfs_root表示sysfs文件系统根目录的structsysfs_dirent.
sysfs_get_inode(&sysfs_root)用来将sysfs_root导出相应的inode.代码如下:
structinode*sysfs_get_inode(structsysfs_dirent*sd)
{
structinode*inode;
//以super_block和sd->s_ino为哈希值,到哈希表中寻找相应的inode.如果不存在,则新建
inode=iget_locked(sysfs_sb,sd->s_ino);
//对新生成的inode进行初始化
if(inode&&(inode->i_state&I_NEW))
sysfs_init_inode(sd,inode);
returninode;
}
首先,它以sysfs文件系统的super_block和structsysfs_dirent.的s_ino成员的值做为哈希值到哈希表中寻找相应的inode.如果在哈希表中不存在这个inode,那就新建一个,并将它链入到哈希表.之后,调用sysfs_init_inode()对生成的inode进行初始化.显然.在mount的时候是不会生成inode的.必定会进入sysfs_init_inode()函数.代码如下:
staticvoidsysfs_init_inode(structsysfs_dirent*sd,structinode*inode)
{
structbin_attribute*bin_attr;
inode->i_blocks=0;
inode->i_mapping->a_ops=&sysfs_aops;
inode->i_mapping->backing_dev_info=&sysfs_backing_dev_info;
inode->i_op=&sysfs_inode_operations;
inode->i_ino=sd->s_ino;
lockdep_set_class(&inode->i_mutex,&sysfs_inode_imutex_key);
if(sd->s_iattr){
/*sysfs_direnthasnon-defaultattributes
*getthemforthenewinodefrompersistentcopy
*insysfs_dirent
*/
set_inode_attr(inode,sd->s_iattr);
}else
set_default_inode_attr(inode,sd->s_mode);
/*initializeinodeaccordingtotype*/
switch(sysfs_type(sd)){
caseSYSFS_DIR:
inode->i_op=&sysfs_dir_inode_operations;
inode->i_fop=&sysfs_dir_operations;
inode->i_nlink=sysfs_count_nlink(sd);
break;
caseSYSFS_KOBJ_ATTR:
inode->i_size=PAGE_SIZE;
inode->i_fop=&sysfs_file_operations;
break;
caseSYSFS_KOBJ_BIN_ATTR:
bin_attr=sd->s_bin_attr.bin_attr;
inode->i_size=bin_attr->size;
inode->i_fop=&bin_fops;
break;
caseSYSFS_KOBJ_LINK:
inode->i_op=&sysfs_symlink_inode_operations;
break;
default:
BUG();
}
unlock_new_inode(inode);
}
在这里,我们可以看到sysfs文件系统中的各种操作函数了..
在syfs文件系统中,怎么样判断一个目录下是否有这个文件呢?
在前面有关文件系统的分析中我们可以看.有关文件的查找实际上都会由inod->i_op->lookup()函数进行判断.在sysfs中,这个函数对应为sysfs_lookup().代码如下:
staticstructdentry*sysfs_lookup(structinode*dir,structdentry*dentry,
structnameidata*nd)
{
structdentry*ret=NULL;
//取得父结点对应的sysfs_dirent
structsysfs_dirent*parent_sd=dentry->d_parent->d_fsdata;
structsysfs_dirent*sd;
structinode*inode;
mutex_lock(&sysfs_mutex);
//父结点的sysfs_dirent中是否有相应的子结点
sd=sysfs_find_dirent(parent_sd,dentry->d_name.name);
/*nosuchentry*/
//如果没有.这个结点是不存在的
if(!
sd){
ret=ERR_PTR(-ENOENT);
gotoout_unlock;
}
/*attachdentryandinode*/
//如果有这个结点,为之生成inod结构.
inode=sysfs_get_inode(sd);
if(!
inode){
ret=ERR_PTR(-ENOMEM);
gotoout_unlock;
}
/*instantiateandhashdentry*/
dentry->d_op=&sysfs_dentry_ops;
//关联dentry与sysfs_dirent
dentry->d_fsdata=sysfs_get(sd);
d_instantiate(dentry,inode);
d_rehash(dentry);
out_unlock:
mutex_unlock(&sysfs_mutex);
returnret;
}
由此可见,它的判断会转入到相应的sysfs_dirent中进行判断.如果设备模型在创建目录/文件的时候并不会创建dentry或者inode.只会操作sysfs_dirent结构.如果找到了这个结构,就为这个结构生成inode.并将其关联到denry中.
sysfs_find_dirent()如下:
structsysfs_dirent*sysfs_find_dirent(structsysfs_dirent*parent_sd,
constunsignedchar*name)
{
structsysfs_dirent*sd;
for(sd=parent_sd->s_dir.children;sd;sd=sd->s_sibling)
if(!
strcmp(sd->s_name,name))
returnsd;
returnNULL;
}
它用的搜索方法就是我们在之前分析sysfs_dirent结构所讲述的.分析到这里,sysfs的大概轮廓就出现在我们的眼前了.^_^.接下来分析sysfs文件系统中目录的创建过程
三:
在sysfs文件系统中创建目录
在linux设备模型中,每注册一个kobject.就会为之创建一个目录.具体的流程在分析linux设备模型的时候再给出详细的分析.创建目录的接口为:
sysfs_create_dir().代码如下:
intsysfs_create_dir(structkobject*kobj)
{
structsysfs_dirent*parent_sd,*sd;
interror=0;
BUG_ON(!
kobj);
//如果kobject没有指定父结点,则将其父结点指定为sysfs的根目录syfs_root
if(kobj->parent)
parent_sd=kobj->parent->sd;
else
parent_sd=&sysfs_root;
//创建目录
error=create_dir(kobj,parent_sd,kobject_name(kobj),&sd);
//kobj->sd指向对应的sysfs_dirent
if(!
error)
kobj->sd=sd;
returnerror;
}
在这里,先为结点指定父目录,然后调用create_dir()在父目录下生成结点.代码如下:
staticintcreate_dir(structkobject*kobj,structsysfs_dirent*parent_sd,
constchar*name,structsysfs_dirent**p_sd)
{
//指定目录的模式
umode_tmode=S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO;
structsysfs_addrm_cxtacxt;
structsysfs_dirent*sd;
intrc;
/*allocate*/
//分配并初始化一个sysfs_dirent
sd=sysfs_new_dirent(name,mode,SYSFS_DIR);
if(!
sd)
return-ENOMEM;
//初始化sd->s_dir.kobj字段
sd->s_dir.kobj=kobj;
/*linkin*/
//acxt是一个临时变量.它用来存放父结点的相关信息
//设置acxt->parent_sd为父结点的sysfs_dirent.acxt->parent_inode为父结点的inode
sysfs_addrm_start(&acxt,parent_sd);
//设置sd->s_parent.并按inod值按顺序链入父结点的children链表
rc=sysfs_add_one(&acxt,sd);
sysfs_addrm_finish(&acxt);
if(rc==0)
*p_sd=sd;
else
sysfs_put(sd);
returnrc;
}
在这里,为子节点生成了对应的sysfs_dirent.设置了它的父结点域,并将其链入到父结点的children链表.这样,在文件系统中查找父目录下面的子结点了.
四:
在sysfs中创建一般属性文件
Kobject的每一项属性都对应在sysfs文件系统中,kobject对应的目录下的一个文件.文件名称与属性名称相同.创建一般属性的接口为sysfs_create_file().代码如下:
intsysfs_create_file(structkobject*kobj,conststructattribute*attr)
{
BUG_ON(!
kobj||!
kobj->sd||!
attr);
//kobject->sd:
为kobject表示目录的structsysfs_dirent结构
returnsysfs_add_file(kobj->sd,attr,SYSFS_KOBJ_ATTR);
}
最终会调用sysfs_add_file().参数attr.是要生成文件的属性值.
intsysfs_add_file(structsysfs_dirent*dir_sd,conststructattribute*attr,
inttype)
{
//文件对应的属性
umode_tmode=(attr->mode&S_IALLUGO)|S_IFREG;
structsysfs_addrm_cxtacxt;
structsysfs_dirent*sd;
intrc;
//创建一个新的sysfs_dirent.对应的名称为attr->name.即属性的名称
sd=sysfs_new_dirent(attr->name,mode,type);
if(!
sd)
return-ENOMEM;
//设置属性值
sd->s_attr.attr=(void*)attr;
//将子结点的structsysfs_dirent结构关链到父结点
sysfs_addrm_start(&acxt,dir_sd);
rc=sysfs_add_one(&acxt,sd);
sysfs_addrm_finish(&acxt);
if(rc)
sysfs_put(sd);
returnrc;
}
这个流程与创建目录的流程大部份相同.不相同的只是创建目录时,它的父目录为上一层结点,创建文件时,它的父目录就是kobject对应的structsysfs_dirent.
这样,在kobject对应的目录下面就可以看到这个文件了.^_^
文件建好之后,要怎么样去读写呢?
回忆一下,在sysfs文件系统中,inode的初始化:
staticvoidsysfs_init_inode(structsysfs_dirent*sd,structinode*inode)
{
……
…….
caseSYSFS_KOBJ_ATTR:
inode->i_size=PAGE_SIZE;
inode->i_fop=&sysfs_file_operations;
……
}
sysfs_file_operations的定义如下:
conststructfile_operationssysfs_file_operations={
.read=sysfs_read_file,
.write=sysfs_write_file,
.llseek=generic_file_llseek,
.open=sysfs_open_file,
.release=sysfs_release,
.poll=sysfs_poll,
};
文件的操作全部都在这里了,我们从打开文件说起.
sysfs_open_file()代码如下:
staticintsysfs_open_file(structinode*inode,structfile*file)
{
structsysfs_dirent*attr_sd=file->f_path.dentry->d_fsdata;
structkobject*kobj=attr_sd->s_parent->s_dir.kobj;
structsysfs_buffer*buffer;
structsysfs_ops*ops;
interror=-EACCES;
/*needattr_sdforattrandops,itsparentforkobj*/
if(!
sysfs_get_active_two(attr_sd))
return-ENODEV;
/*everykobjectwithanattributeneedsaktypeassigned*/
//将buffer->ops设置为kobj->ktype->sysfs_ops
if(kobj->ktype&&kobj->ktype->sysfs_ops)
ops=kobj->ktype->sysfs_ops;
else{
printk(KERN_ERR"missingsysfsattributeoperationsfor"
"kobject:
%s\n",kobject_name(kobj));
WARN_ON
(1);
gotoerr_out;
}
/*Fileneedswritesupport.
*Theinode'
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux 文件系统 sysfs