linux sysfs 学习笔记

初识/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 属性

猜你喜欢

转载自blog.csdn.net/agave7/article/details/94721861