sysfs文件系统是linux系统启动的时候第一个初始化的文件系统。
1 sysfs_init
start_kernel
--------->vfs_caches_init
------------>mnt_init
-------------->sysfs_init
在sysfs_init函数中,对sysfs文件系统根目录的dentry,super_block,inode,挂载点实例mount 等这些重要的数据结构做初始化。
int __init sysfs_init(void)
{
int err = -ENOMEM;
//创建用于分配sysfs_dirent的slab
sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
sizeof(struct sysfs_dirent),
0, 0, NULL);
if (!sysfs_dir_cachep)
goto out;
err = sysfs_inode_init();
if (err)
goto out_err;
//注册sysfs文件系统结构
err = register_filesystem(&sysfs_fs_type);
if (!err) {
sysfs_mnt = kern_mount(&sysfs_fs_type); //调用文件系统的mount函数挂载文件系统
if (IS_ERR(sysfs_mnt)) {
printk(KERN_ERR "sysfs: could not mount!\n");
err = PTR_ERR(sysfs_mnt);
sysfs_mnt = NULL;
unregister_filesystem(&sysfs_fs_type);
goto out_err;
}
} else
goto out_err;
out:
return err;
out_err:
kmem_cache_destroy(sysfs_dir_cachep);
sysfs_dir_cachep = NULL;
goto out;
}
register_filesystem函数就是把sysfs_fs_type注册进file_systems全局结构中,每个文件系统都会有一个file_system_type结构,并且这些结构最终都会放入file_systems全局结构,以便于查找。sysfs的结构如下:
static struct file_system_type sysfs_fs_type = {
.name = "sysfs",
.mount = sysfs_mount,
.kill_sb = sysfs_kill_sb,
.fs_flags = FS_USERNS_MOUNT,
};
mount函数用于挂载特定的文件系统,而kill_sb则用于释放相关的操作。接着调用kern_mount,kern_mount调用完以后返回vfsmount结构,该结构包含于挂载点实例mount中,通过该结构可以方便的找到mount。
sysfs_init
--------->kern_mount
----------->kern_mount_data
------------>vfs_kern_mount
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
struct mount *mnt;
struct dentry *root;
if (!type)
return ERR_PTR(-ENODEV);
mnt = alloc_vfsmnt(name); //分配一个mount结构,并对其进行初始化
if (!mnt)
return ERR_PTR(-ENOMEM);
if (flags & MS_KERNMOUNT)
mnt->mnt.mnt_flags = MNT_INTERNAL;
root = mount_fs(type, flags, name, data); //挂载的核心函数,并返回该文件系统的root dentry
if (IS_ERR(root)) {
free_vfsmnt(mnt);
return ERR_CAST(root);
}
mnt->mnt.mnt_root = root; // root dentry
mnt->mnt.mnt_sb = root->d_sb; //super block
mnt->mnt_mountpoint = mnt->mnt.mnt_root; //挂载点
mnt->mnt_parent = mnt;
br_write_lock(&vfsmount_lock);
list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);//把挂载点放入s_mounts链表
br_write_unlock(&vfsmount_lock);
return &mnt->mnt;
}
可以看到,核心函数是mount_fs:
struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
{
struct dentry *root;
struct super_block *sb;
char *secdata = NULL;
int error = -ENOMEM;
if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
secdata = alloc_secdata();
if (!secdata)
goto out;
error = security_sb_copy_data(data, secdata);
if (error)
goto out_free_secdata;
}
//调用特定文件系统相关的mount 函数
root = type->mount(type, flags, name, data);
if (IS_ERR(root)) {
error = PTR_ERR(root);
goto out_free_secdata;
}
sb = root->d_sb;
BUG_ON(!sb);
WARN_ON(!sb->s_bdi);
WARN_ON(sb->s_bdi == &default_backing_dev_info);
sb->s_flags |= MS_BORN;
//安全相关的函数,可以暂且跳过
error = security_sb_kern_mount(sb, flags, secdata);
if (error)
goto out_sb;
/*
* filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE
* but s_maxbytes was an unsigned long long for many releases. Throw
* this warning for a little while to try and catch filesystems that
* violate this rule.
*/
WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
"negative value (%lld)\n", type->name, sb->s_maxbytes);
up_write(&sb->s_umount);
free_secdata(secdata);
return root;
out_sb:
dput(root);
deactivate_locked_super(sb);
out_free_secdata:
free_secdata(secdata);
out:
return ERR_PTR(error);
}
对于sysfs文件系统,其特定的mount函数是sysfs_mount:
static struct dentry *sysfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
struct sysfs_super_info *info;
enum kobj_ns_type type;
struct super_block *sb;
int error;
if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs)
return ERR_PTR(-EPERM);
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return ERR_PTR(-ENOMEM);
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
info->ns[type] = kobj_ns_grab_current(type);
//分配super_block,并初始化super_block
sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info);
if (IS_ERR(sb) || sb->s_fs_info != info)
free_sysfs_super_info(info);
if (IS_ERR(sb))
return ERR_CAST(sb);
if (!sb->s_root) {
//为该文件系统的根目录初始化dentry和inode
error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
if (error) {
deactivate_locked_super(sb);
return ERR_PTR(error);
}
sb->s_flags |= MS_ACTIVE;
}
return dget(sb->s_root);
}
先看sget,该函数的主要作用就是为特定文件系统分配一个super block结构,并初始化该结构,最后返回一个super block结构。然后调用sysfs_fill_super进一步初始化。
sysfs_mount
--------->sysfs_fill_super
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct dentry *root;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = SYSFS_MAGIC;
sb->s_op = &sysfs_ops;//设置super block的操作函数
sb->s_time_gran = 1;
/* get root inode, initialize and unlock it */
mutex_lock(&sysfs_mutex);
inode = sysfs_get_inode(sb, &sysfs_root); //分配并初始化该文件系统根目录的inode
mutex_unlock(&sysfs_mutex);
if (!inode) {
pr_debug("sysfs: could not get root inode\n");
return -ENOMEM;
}
/* instantiate and link root dentry */
root = d_make_root(inode); //分配并初始化该文件系统根目录的dentry
if (!root) {
pr_debug("%s: could not get root dentry!\n",__func__);
return -ENOMEM;
}
root->d_fsdata = &sysfs_root; //把根目录的sysfs_dirent放入dentry的d_fsdata中
sb->s_root = root;//在super block中记录下该根目录的dentry
sb->s_d_op = &sysfs_dentry_ops;
return 0;
}
上面函数比较重要的是sysfs_get_inode,该函数分配并初始化了该文件系统根目录的inode结构,然后d_make_root函数为该文件系统的根目录分配了dentry结构,最后一个很重要的操作是root->d_fsdata = &sysfs_root;把根目录的sysfs_dirent放入dentry的d_fsdata,前面已经说过在,在sysfs文件系统中,不管是目录还是文件,都有一个sysfs_dirent结构相对应,而在vfs中,所有的目录和文件都需要由一个dentry结构,所以在这里就把根目录的dentry和sysfs_dirent关联起来。下面先来看一下sysfs_get_inode函数:
sysfs_mount
--------->sysfs_fill_super
----------->sysfs_get_inode
struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd)
{
struct inode *inode;
inode = iget_locked(sb, sd->s_ino); //获取一个inode,如果之前没有过,则需要重新创建一个
if (inode && (inode->i_state & I_NEW))
sysfs_init_inode(sd, inode); //初始化该inode结构
return inode;
}
主要关注sysfs_init_inode函数:
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
struct bin_attribute *bin_attr;
inode->i_private = sysfs_get(sd);
inode->i_mapping->a_ops = &sysfs_aops;
inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
inode->i_op = &sysfs_inode_operations;
set_default_inode_attr(inode, sd->s_mode);
sysfs_refresh_inode(sd, inode);
/* initialize inode according to type */
switch (sysfs_type(sd)) {
case SYSFS_DIR:
inode->i_op = &sysfs_dir_inode_operations;//该操作函数很重要,后面在从上级目录,查找下级目录的dentry的时候,如果该dentry还没有建立,则需要调用indoe操作函数的lookup函数来新建一个dentry
inode->i_fop = &sysfs_dir_operations;
break;
case SYSFS_KOBJ_ATTR:
inode->i_size = PAGE_SIZE;
inode->i_fop = &sysfs_file_operations;
break;
case SYSFS_KOBJ_BIN_ATTR:
bin_attr = sd->s_bin_attr.bin_attr;
inode->i_size = bin_attr->size;
inode->i_fop = &bin_fops;
break;
case SYSFS_KOBJ_LINK:
inode->i_op = &sysfs_symlink_inode_operations;
break;
default:
BUG();
}
unlock_new_inode(inode);
}
sysfs_init_inode函数比较重要的是根据是目录还是文件为其赋值不同的inode操作函数,操作函数会在目录搜索,或者文件操作中会用到。接着看d_make_root:
sysfs_mount
--------->sysfs_fill_super
----------->d_make_root
struct dentry *d_make_root(struct inode *root_inode)
{
struct dentry *res = NULL;
if (root_inode) {
static const struct qstr name = QSTR_INIT("/", 1);//该dentry的名字为‘/’,是该文件系统的root dentry
res = __d_alloc(root_inode->i_sb, &name);//分配并初始化dentry
if (res)
d_instantiate(res, root_inode);
else
iput(root_inode);
}
return res;
}
__d_alloc函数不展开分析了,就是分配一个dentry,并初始化他,然后在d_instantiate函数把dentry和inode关联起来:dentry->d_inode = inode;
初始化完以后各个结构之间的关系大概如下:
每个文件系统,都有一个‘/’目录相对应,从上面的初始化可以看出,sysfs文件系统的根目录'/'是没有object结构相对应的。
2 kobject_create_and_add
接着会调用:
fs_kobj = kobject_create_and_add("fs", NULL);
该函数在当前文件系统的根目录下生成fs目录,后面注册的文件系统,应该都会在该fs下面添加新的目录,所以先要把该目录初始好。
start_kernel
--------->vfs_caches_init
------------>mnt_init
-------------->kobject_create_and_add
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{
struct kobject *kobj;
int retval;
kobj = kobject_create();//新建并初始化一个kobject结构
if (!kobj)
return NULL;
retval = kobject_add(kobj, parent, "%s", name);//创建object目录文件的核心结构
if (retval) {
printk(KERN_WARNING "%s: kobject_add error: %d\n",
__func__, retval);
kobject_put(kobj);
kobj = NULL;
}
return kobj;
}
主要关注kobject_add函数:
kobject_create_and_add
-------------->kobject_add_varg
----------------->kobject_add_internal
在kobject_add_varg中,先把kobj->parent设置为null,因为该文件系统顶层根目录是没有object结构的。
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
if (!kobj->name || !kobj->name[0]) {
WARN(1, "kobject: (%p): attempted to be registered with empty "
"name!\n", kobj);
return -EINVAL;
}
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) { //没有设置kset,不会走到这边
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj);
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
error = create_dir(kobj);
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
/* be noisy on error issues */
if (error == -EEXIST)
WARN(1, "%s failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory.\n",
__func__, kobject_name(kobj));
else
WARN(1, "%s failed for %s (error: %d parent: %s)\n",
__func__, kobject_name(kobj), error,
parent ? kobject_name(parent) : "'none'");
} else
kobj->state_in_sysfs = 1;
return error;
}
核心函数为create_dir:
create_dir
--------->sysfs_create_dir
int sysfs_create_dir(struct kobject * kobj)
{
enum kobj_ns_type type;
struct sysfs_dirent *parent_sd, *sd;
const void *ns = NULL;
int error = 0;
BUG_ON(!kobj);
if (kobj->parent)
parent_sd = kobj->parent->sd;
else
parent_sd = &sysfs_root; //由于kobject 没有设置kobj->parent,所以设置sysfs_dirent为sysfs_root
if (!parent_sd)
return -ENOENT;
if (sysfs_ns_type(parent_sd))
ns = kobj->ktype->namespace(kobj);
type = sysfs_read_ns_type(kobj);
error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
if (!error)
kobj->sd = sd;
return error;
}
create_dir
--------->sysfs_create_dir
-------------->create_dir
最终调用dir.c下面的create_dir函数:
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
enum kobj_ns_type type, const void *ns, 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;
int rc;
/* allocate */
sd = sysfs_new_dirent(name, mode, SYSFS_DIR); //新建一个sysfs_dirent 结构
if (!sd)
return -ENOMEM;
sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
sd->s_ns = ns;
sd->s_dir.kobj = kobj;//把kobject和新建的sysfs_dirent关联起来
/* link in */
//acxt结构只是个中间结构,用来传递sysfs_dirent数据
sysfs_addrm_start(&acxt, parent_sd);
rc = sysfs_add_one(&acxt, sd);
sysfs_addrm_finish(&acxt);
if (rc == 0)
*p_sd = sd;
else
sysfs_put(sd);
return rc;
}
在sysfs_add_one函数中,把新建的sysfs_dirent结构的s_parent设置为sysfs_root,并把该结构link到sysfs_root的孩子节点上。至此初始化完全,可以看一下相互结构关系:
可以看到,新建的fs目录,没有dentry和inode结构,和vfs文件系统对接,应该是需要dentry和inode结构。其实这两个结构,在遍历目录的时候会根据上层目录的inode节点的look_up操作函数会动态的创建,后面章节再具体分析该过程。