Linux那些事儿之我是Sysfs(10)sysfs 创建目录

每当我们新增一个kobject结构的时候,同时会在/sys下创建一个目录。

kobject_add()  ->  create_dir() -> sysfs_create_dir()

此时,我还想重申,kernel代码的更新换代是很快的,我们的目的是懂得代码背后的原理,知识,或曰哲学。我不想讲的太细,因为关于sysfs的部分从2.6.10到现在2.6.22已经改了很多了。但其总体架构没变。写此文的目的是让您跟着我的思路走一遍,对sysfs有了一个总体上的认识。然后自己就可以去看最新的代码了。最新的代码肯定是效率更高,条理逻辑更清晰。

sysfs_create_dir()流程图如下:
                     -> create_dir()
                                          -> *d = sysfs_get_dentry()
                                                               -> lookup_hash()
                                                                                    -> __lookup_hash()
                                                                                    -> cached_lookup()
                                                                                    -> new = d_alloc(base, name);
                                                                                    -> inode->i_op->lookup(inode, new, nd)
                                          -> sysfs_create(*d, mode, init_dir)
                                                               -> sysfs_new_inode(mode)
                                                               -> init_dir(inode); // Call back function
                                          -> sysfs_make_dirent()
                                                               -> sysfs_new_dirent()
                                                               -> dentry->d_fsdata = sysfs_get(sd);
                                                               -> dentry->d_op = &sysfs_dentry_ops;
                                          -> (*d)->d_op = &sysfs_dentry_ops;

    135 int sysfs_create_dir(struct kobject * kobj)
    136 {
    137         struct dentry * dentry = NULL;
    138         struct dentry * parent;
    139         int error = 0;
    140
    141         BUG_ON(!kobj);
    142
    143         if (kobj->parent)
    144                 parent = kobj->parent->dentry;
    145         else if (sysfs_mount && sysfs_mount->mnt_sb)
    146                 parent = sysfs_mount->mnt_sb->s_root;
    147         else
    148                 return -EFAULT;
    149
    150         error = create_dir(kobj,parent,kobject_name(kobj),&dentry);
    151         if (!error)
    152                 kobj->dentry = dentry;
    153         return error;
    154 }
143-148就是找到父辈的kobject,再调用create_dir();

     95 static int create_dir(struct kobject * k, struct dentry * p,
     96                       const char * n, struct dentry ** d)
     97 {
     98         int error;
     99         umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
    100
    101         down(&p->d_inode->i_sem);
    102         *d = sysfs_get_dentry(p,n);
    103         if (!IS_ERR(*d)) {
    104                 error = sysfs_create(*d, mode, init_dir);
    105                 if (!error) {
    106                         error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
    107                                                 SYSFS_DIR);
    108                         if (!error) {
    109                                 p->d_inode->i_nlink++;
    110                                 (*d)->d_op = &sysfs_dentry_ops;
    111                                 d_rehash(*d);
    112                         }
    113                 }
    114                 if (error && (error != -EEXIST))
    115                         d_drop(*d);
    116                 dput(*d);
    117         } else
    118                 error = PTR_ERR(*d);
    119         up(&p->d_inode->i_sem);
    120         return error;
    121 }
99行,设置‘文件’ 属性,101获取信号量。

(1)sysfs_get_dentry()
102行sysfs_get_dentry()。它的作用是根据父辈dentry和文件名得到dentry结构。首先在缓存中找,如果找到就返回,找不到就用d_alloc()新建一个dentry结构。我们是新建文件夹,缓存中自然是没有的,所以要用d_alloc()来新建一个。接着我们调用lookup函数,它定义如下。

struct inode_operations sysfs_dir_inode_operations = {
             .lookup = sysfs_lookup,
};

    204 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
    205                                 struct nameidata *nd)
    206 {
    207         struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
    208         struct sysfs_dirent * sd;
    209         int err = 0;
    210
    211         list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
    212                 if (sd->s_type & SYSFS_NOT_PINNED) {
    213                         const unsigned char * name = sysfs_get_name(sd);
    214
    215                         if (strcmp(name, dentry->d_name.name))
    216                                 continue;
    217
    218                         if (sd->s_type & SYSFS_KOBJ_LINK)
    219                                 err = sysfs_attach_link(sd, dentry);
    220                         else
    221                                 err = sysfs_attach_attr(sd, dentry);
    222                         break;
    223                 }
    224         }
    225
    226         return ERR_PTR(err);
    227 }

前面讲过lookup函数的作用。它在inode代表的文件夹下查找有没有名为dentry.d name.name的文件。如果有,就将其对应的inode结构从信息的载体中读出来。由于是新建的文件夹,所以lookup函数在我们这个故事里根本没做事。但是我还是忍不住想分析一下lookup函数。

sysfs文件系统中,文件夹的inode和dentry结构一直都是存在于内存中的,所以不用再进行读取了。而文件,链接的inode事先是没有的,需要从载体中读出。这就是212行这个判断的作用。可以看出,如果是文件夹,循环里面啥都没做。

#define SYSFS_NOT_PINNED /
(SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)

但是sysfs的lookup还有它不同之处。其他文件系统像ext3格式中普通文件的inode,在文件创建之时就已经创建了。但是,sysfs不一样,它在创建普通文件时,只是先创建一个sysfs_dirent结构。创建inode的工作是推迟到lookup函数来完成的。在下一节sysfs_create_file()会看到这一点。

sysfs_attach_attr()和sysfs_attach_link()的作用就是根据dentry和sysfs_dirent新建一个inode。

总之,我们通过sysfs_get_dentry()得到了一个新建的dentry结构。

(2)sysfs_create()分析 (104行)
sysfs_create()->sysfs_new_inode(mode) -> new_inode(sysfs_sb)
创建一个新的索引节点inode。sysfs_sb是sysfs的超级块(super_block)结构。mode则是inode的属性,它记录了如下信息,比如,文件类型(是文件夹,链接,还是普通文件),inode的所有者,创建时间等等。

(3)sysfs make dirent()分析 (104行)
至此,我们得到了一个dirent结构,初始化,再把它连接到上层目录的sysfs_dirent的s_children链表里去。sysfs_make_dirent()为刚刚新建出来的dentry建立一个dirent结构。并将dentry和dirent联系起来。

(4)总结
在sysfs下创建一个目录,提供的函数是sysfs_create_dir()。创建了dentry, dirent, inode
结构, 它们之间的连接关系见图1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值