初识/sys
linux 的根目录下有一个/sys 目录,里面的内容如下
# ls /sys
block class devices fs module
bus dev firmware kernel power
sysfs 的作用
sysfs is a ram-based filesystem initially based on ramfs. It provides
a means to export kernel data structures, their attributes, and the
linkages between them to userspace.
sysfs最初是基于ramfs的基于ram的文件系统。它提供了一种将内核数据结构、它们的属性以及它们之间的连接导出到用户空间的方法。
如何在/sys下添加文件
参考 linux-4.14.63\samples\kobject\kobject-example.c
1.添加目录
/*
* Create a simple kobject with the name of "kobject_example",
* located under /sys/kernel/
*/
example_kobj = kobject_create_and_add("kobject_example", kernel_kobj);
理解,/sys 中的每一个目录都对应一个kobject 。
2.添加文件
/* Create the files associated with this kobject */
retval = sysfs_create_group(example_kobj, &attr_group);
kobject-example.c 会生成 /sys/kernel/kobject_example 目录,该目录下会有bar baz foo 三个属性文件
# ls /sys/kernel/kobject_example/
bar baz foo
可以用cat echo 命令读写属性值
cat /sys/kernel/kobject_example/foo
echo 1 > /sys/kernel/kobject_example/foo
3.代码理解
kobject_create_and_add //linux-4.14.63\lib\kobject.c
kobject_create //创建kobject 并初始化结构体
kobject_add(kobj, parent, "%s", name)
kobject_add_varg(kobj, parent, fmt, args)
kobject_set_name_vargs(kobj, fmt, vargs) //设置name
kobj->parent = parent; //绑定parent kobject
return kobject_add_internal(kobj);
create_dir(kobj) //创建目录
sysfs_create_group //linux-4.14.63\fs\sysfs\group.c
return internal_create_group(kobj, 0, grp)
error = create_files(kn, kobj, grp, update) //创建文件
理解kobject 与kset
用面向对象的思想来看,kobject 是一个基类,kset 继承自 kobject
参考: 从面向对象的角度看Linux设备模型 - colddown的专栏 - CSDN博客
kset 一般对应于 /sys 下的一级子目录,诸如 bus devices class 等。同种类型kobject 的集合。
参考 linux-4.14.63\samples\kobject\kset-example.c
添加一个kset
/*
* Create a kset with the name of "kset_example",
* located under /sys/kernel/
*/
example_kset = kset_create_and_add("kset_example", NULL, kernel_kobj);
单从效果上看,它跟kobject_create_and_add 是一样的,最终都是生成目录。
但是意义上有所不同,例如内核代码中定义了多种不同类型的kset :bus_kset , devices_kset,class_kset 等。它们所代表的不单是一个kobject,还包含更的东西。例如:uevent_ops
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops; //
}
用面向对象的思想来看,kset 继承了kobject ,uevent_ops,list_lock , list这些可以看做是私有成员。
理解/sys/bus 的创建
在内核启动完之后,/sys/目录下就已经生成了bus class 等目录,这些目录是什么时候创建的呢?
这里以/sys/bus 为例,跟踪一下代码流程。/sys/bus 也是对应于一个 kset ,kset 的创建一般都是用kset_create_and_add 接口。在内核源码中通过查找命令 "grep kset_create_and_add " 很容易找到
/sys/bus 创建的地方。
int __init buses_init(void) //linux-4.14.63\drivers\base\bus.c
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
if (!bus_kset)
return -ENOMEM;
system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
if (!system_kset)
return -ENOMEM;
return 0;
}
buses_init 被调用过程
start_kernel
rest_init
pid = kernel_thread(kernel_init, NULL, CLONE_FS);
kernel_init
kernel_init_freeable
do_basic_setup
driver_init
buses_init
bus_kset 被谁使用?
答:bus_kset 被 bus_register 使用
int bus_register(struct bus_type *bus)
{
//省略
priv->subsys.kobj.kset = bus_kset;
//省略
}
bus_register 的作用是注册一种总线类型,注册好后可以在/sys/bus/目录下看到对应名字的目录
例如:/sys/bus/platform /sys/bus/i2c /sys/bus/spi
理解/sys/module/xxx 的创建
当 insmod xxx.ko 成功后,会自动生成 /sys/module/xxx 目录
为了明白其过程,先来理解 insmod
insmod 是 busybox 中的命令工具,其源码位于busybox-1.28.3\modutils\insmod.c
参考文章:module_init机制的理解 - weixin_37571125的博客 - CSDN博客
insmod_main //busybox-1.28.3\modutils\insmod.c
bb_init_module
init_module
#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
可以看出 insmod 最终是系统调用 __NR_init_module
对应到内核代码是:
//linux-4.14.63\kernel\module.c
SYSCALL_DEFINE3(init_module, void __user *, umod,
unsigned long, len, const char __user *, uargs)
{
//省略
return load_module(&info, uargs, 0);
}
static int load_module(struct load_info *info, const char __user *uargs,
int flags)
{
//省略
/* Link in to sysfs. */
err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
}
追踪到mod_sysfs_setup
mod_sysfs_setup(mod, info, mod->kp, mod->num_kp)
/*创建 /sys/module/xxx */
mod_sysfs_init(mod)
mod->mkobj.kobj.kset = module_kset; //指定ket属于/sys/module
err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
"%s", mod->name);
/*sys/module/xxx/holders*/
mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj)
/*sys/module/xxx/parameters 里面是模块的加载参数*/
module_param_sysfs_setup(mod, kparam, num_params)
/*sys/module/xxx/refcnt ...等属性 */
module_add_modinfo_attrs(mod)
梳理:insmod -> syscall -> init_module -> mod_sysfs_setup 。由此产生/sys/module/xxx 下的内容。
小结
可以看出,sysfs 在内核代码中有很多的应用。/sys 目录下能看到的东西,都跟sysfs 有关。
/sys 下的目录 都对应于内核代码中的一个kobject 或者 kset (理解kset 是kobject 的派生类,这很重要)
/sys 下的普通文件 都对应于内核代码中的一个attr 属性