在linux内核fs/sysfs目录下面dir.c是建立目录的文件, file.c定义了建立属性文件相关函数,创建二进制文件的函数定义在bin.c 中.
sysfs创建目录文件
sysfs建立目录的软件流程sysfs_create_dir()->create_dir()->sysfs_new_dirent()->sysfs_add_one();
在sysfs中每个目录都对应一个kobj结构 , 每个文件(包括目录文件)都对应一个sysfs_dirent对象 ,在建立目录和文件后, 内存中会形成一颗以sysfs_root为根的目录树结构.
下面是create_dir()的代码:
610 static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
611 const char *name, struct sysfs_dirent **p_sd)
612 {
613 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
614 struct sysfs_addrm_cxt acxt;
615 struct sysfs_dirent *sd;
616 int rc;
617
618 /* allocate */
619 sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
620 if (!sd)
621 return -ENOMEM;
622 sd->s_dir.kobj = kobj;
623
624 /* link in */
625 sysfs_addrm_start(&acxt, parent_sd);
626 rc = sysfs_add_one(&acxt, sd);
627 sysfs_addrm_finish(&acxt);
628
629 if (rc == 0)
630 *p_sd = sd;
631 else
632 sysfs_put(sd);
633
634 return rc;
635 }
第613行指定文件的mode为目录文件可读写, 接下来第619行sysfs_new_dirent()为文件分配对应的sysfs_dirent对象 ,, sd->s_dir.kobj = kobj找到它的kobj对象,也可以进一步说明这是一个目录文件.
第625-627行API的目的是将建立的sysfs_dirent对象加到以sysfs_root对象为根的目录树中 ,在以后动态建立文件时会根据名字查找到它
最后就是返回sysfs_dirent对象, 将kobj->sd指向它.
好了,这个目录的信息就已经记录在内存中了.
sysfs创建属性文件
sysfs建立属性文件的流程: sysfs_create_file()->sysfs_add_file()->sysfs_add_file_mode();
下面重点看看sysfs_add_file_mode()函数的实现:
480 int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
481 const struct attribute *attr, int type, mode_t amode)
482 {
483 umode_t mode = (amode & S_IALLUGO) | S_IFREG;
484 struct sysfs_addrm_cxt acxt;
485 struct sysfs_dirent *sd;
486 int rc;
487
488 sd = sysfs_new_dirent(attr->name, mode, type);
489 if (!sd)
490 return -ENOMEM;
491 sd->s_attr.attr = (void *)attr;
492
493 sysfs_addrm_start(&acxt, dir_sd);
494 rc = sysfs_add_one(&acxt, sd);
495 sysfs_addrm_finish(&acxt);
496
497 if (rc)
498 sysfs_put(sd);
499
500 return rc;
501 }
第488行函数在cache中创建一个sysfs_dirent对象 ,接下来sd->s_attr.attr = (void *)attr;初始化文件属性
第493-495行函数的目的会根据父目录的sysfs_dirent对象把刚才建立的sysfs_dirent加入到目录树中.
VFS动态创建sysfs文件
先看看sysfs目录文件索引节点操作方法的定义
const struct inode_operations sysfs_dir_inode_operations = {
.lookup = sysfs_lookup,
.setattr = sysfs_setattr,
};
在以前的文章中已经介绍过vfs查找文件创建inode的过程 inode->i_op->lookup()
在sysfs中目录文件inode定义的这个回调函数是sysfs_lookup()
665 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
666 struct nameidata *nd)
667 {
668 struct dentry *ret = NULL;
669 struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
670 struct sysfs_dirent *sd;
671 struct inode *inode;
672
673 mutex_lock(&sysfs_mutex);
674
675 sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
676
677 /* no such entry */
678 if (!sd) {
679 ret = ERR_PTR(-ENOENT);
680 goto out_unlock;
681 }
682
683 /* attach dentry and inode */
684 inode = sysfs_get_inode(sd);
685 if (!inode) {
686 ret = ERR_PTR(-ENOMEM);
687 goto out_unlock;
688 }
689
690 /* instantiate and hash dentry */
691 dentry->d_op = &sysfs_dentry_ops;
692 dentry->d_fsdata = sysfs_get(sd);
693 d_instantiate(dentry, inode);
694 d_rehash(dentry);
695
696 out_unlock:
697 mutex_unlock(&sysfs_mutex);
698 return ret;
699 }
先看第669行,在上篇文章中介绍过sysfs根目录的sysfs_dirent对象初始化给了根目录的dentry. 这个时候就需要取出这个sysfs_dirent对象了
第675行代码就是根据文件名字查找出对应的sysfs_dirent对象.
第684行函数会在内存中建立文件的索引节点inode, 并由sfs_dirent对象初始化这个indoe, 初始化indoe的函数为sysfs_init_inode() 前面已经分析过了.
第692行函数dentry->d_fsdata = sysfs_get(sd); 把这个文件的sysfs_dirent对象初始化给目录项对象dentyr.
693-694行,关联文件inode和dentry, 并把dentry加入到对应的散列表中.
到这里这个文件的inode和dentry就在内存中建立起来了.