linux内核伪文件系统—sysfs分析
一、sysfs简介
sysfs
是一个伪文件系统。不代表真实的物理设备,在linux内核中,sysfs
文件系统将长期存在于内存中。sysfs
用于对具体的内核对象(例如物理设备)进行建模,并提供一种将设备和设备驱动程序关联起来的方法。使用
ls -l /sys
命令可以查看sysfs
文件系统中导出了哪些内核对象。如下图片所示:
从上图可见,sysfs
文件系统中导出了block、bus、class、dev、devices、firmware、fs、kernel、module、power内核对象(不同的内核配置,可能导出的内核对象有所差异)。
从内核源码来看。这里以bus
内核对象为例,内核源码将在buses_init()
函数中调用kset_create_and_add()
内核函数创建bus对象集合并将其添加到sysfs文件系统中。
开发人员可以使用sysfs
来确定有关正在运行的内核的有用信息,比如:内核在每个总线(bus)上发现了哪些设备,以及每个设备绑定了哪些驱动程序,都可以从sysfs文件系统获知。除此之外,sysfs还可以用于调试、优化设备以及其他的内核子系统。
当前块(block)子系统会使用sysfs
来挂载根分区。如果禁用了sysfs,就必须在内核引导命令行上通过它的主号(major)和副号(minor)指定引导设备。例如,对于/dev/hda1设备来说,命令可以是root=03:01
。
对于嵌入式系统的设计人员,根据实际运用场景,可以禁用sysfs
文件系统,以节省系统资源。
二、sysfs文件系统源码分析
首先,linux内核中关于sysfs
文件系统的源码位于(/fs/sysfs)目录下。如下图所示(源码已被编译):
从Makefile
文件可知,编译过程中,将编译5个源文件:file.o dir.o symlink.o mount.o group.o
本部分内容就不分析sysfs
文件系统的内部实现细节,主要分析以下两个问题:
(1)sysfs
文件系统在linux内核中如何挂载的?
(2)linux内核如何将内核对象集添加到sysfs
文件系统?
(2-1)sysfs
文件系统在linux内核中如何挂载
在start_kernel()
函数中将调用vfs_caches_init(totalram_pages);
函数进行虚拟文件系统的初始化,此函数中将调用mnt_init()
函数,在mnt_init()
函数中将调用sysfs_init()
对sysfs
文件系统进行挂载。如下图片:
代码片段:
void __init mnt_init(void)
{
//...
kernfs_init();
err = sysfs_init();
if (err)
printk(KERN_WARNING "%s: sysfs_init error: %d\n",
__func__, err);
//....
}
(/fs/sysfs/mount.c)
static struct file_system_type sysfs_fs_type = {
.name = "sysfs",
.mount = sysfs_mount,
.kill_sb = sysfs_kill_sb,
.fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
};
int __init sysfs_init(void)
{
int err;
sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,
NULL);
if (IS_ERR(sysfs_root))
return PTR_ERR(sysfs_root);
sysfs_root_kn = sysfs_root->kn;
err = register_filesystem(&sysfs_fs_type);
if (err) {
kernfs_destroy_root(sysfs_root);
return err;
}
return 0;
}
上述代码第1-6行代码,定义了sysfs文件系统描述类型,指定了.name
、.mount
、.kill_sb
、.fs_flags
。
在sysfs_init()
函数中调用kernfs_create_root()
(kernfs
是一个通用的内核虚拟文件系统,较为复杂本文暂不做过多分析)创建了kernfs_root。接着调用register_filesystem()
向内核注册sysfs
文件系统。
(2-2)linux内核如何将内核对象集添加到sysfs
文件系统?
上文写道,linux内核中调用了kset_create_and_add()
内核函数创建内核对象集,从而将内核对象集添加到sysfs文件系统下,本部分来看看该函数。
该函数有以下重要的函数调用关系:
由上图可见,kset_create_and_add()
函数最后将调用到sysfs_create_dir_ns()
这个函数。从而创建sysfs文件系统目录。代码片段如下所示:
(/fs/sysfs/dir.c)
int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
{
struct kernfs_node *parent, *kn;
BUG_ON(!kobj);
if (kobj->parent)
parent = kobj->parent->sd;
else
parent = sysfs_root_kn;
if (!parent)
return -ENOENT;
kn = kernfs_create_dir_ns(parent, kobject_name(kobj),
S_IRWXU | S_IRUGO | S_IXUGO, kobj, ns);
if (IS_ERR(kn)) {
if (PTR_ERR(kn) == -EEXIST)
sysfs_warn_dup(parent, kobject_name(kobj));
return PTR_ERR(kn);
}
kobj->sd = kn;
return 0;
}
三、总结
本文从linux内核代码以及实际的系统运行效果为出发点,描述了sysfs
文件系统的一些功能,并分析了linux内核如何初始化并挂载sysfs
文件系统,以及inux内核如何将内核对象集添加到sysfs
文件系统中的。
由于小生知识和精力有限,如若分享的文章存在有不妥的地方,请看官们多多批评,haha!
搜索关注【嵌入式小生】wx公众号获取更多精彩内容>>>>