首先说这procfs和sysfs有什么区别呢?procfs不针对设备和设备驱动,而是针对整个内核信息的抽象接口。所以sysfs的出现就是为了独立出一个抽象接口来描述设备和驱动信息
另外,procfs和sysctl什么区别呢?procfs主要是用于展示内核信息(一般只读的),而sysctl虽然在/proc/sys下,但它主要是暴露一些内核参数,而用户也可以写入这个来动态修改
- proc
以/proc/cpuinfo的过程倒推一下这个procfs的过程
#创建一个proc,第一个参数是名字,第二个参数是mode,第三个是父级,第四个cpuinfo_proc_ops必须是proc_ops结构体指针
#很明显,这个和sysfs差不多意思,NULL表示直接在/proc下创建proc,可以传入proc_dir_entry作为父级
#返回的也是一个proc_dir_entry结构体,也就是一个procfs目录
proc_create("cpuinfo", 0, NULL, &cpuinfo_proc_ops);
#比如这里就cat /proc/cpuinfo的话,就是调用open了
#open的话就是去调用cpuinfo_open?然后返回的就是一个seq_open的内容?
static int cpuinfo_open(struct inode *inode, struct file *file)
{
return seq_open(file, &cpuinfo_op);
}
static const struct proc_ops cpuinfo_proc_ops = {
.proc_flags = PROC_ENTRY_PERMANENT,
.proc_open = cpuinfo_open,
.proc_read_iter = seq_read_iter,
.proc_lseek = seq_lseek,
.proc_release = seq_release,
};
#这个结构体初始化一些函数指针
const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = show_cpuinfo,
};
#具体的实现
show_cpuinfo
如果想实现一个目录呢?就可以先搞一个proc_dir_entry,然后proc_mkdir创建
这块可以参照fs/dirty_pages.c中的内容,比较简短易读
- sysctl
需要CONFIG_PROC_SYSCTL、CONFIG_SYSCTL的支持
原理:需要先在proc中注册/proc/sys,然后注册ctl_table这些
start_kernel
proc_root_init
proc_sys_init
int __init proc_sys_init(void)
{
struct proc_dir_entry *proc_sys_root;
proc_sys_root = proc_mkdir("sys", NULL);//创建目录
proc_sys_root->proc_iops = &proc_sys_dir_operations;
proc_sys_root->proc_dir_ops = &proc_sys_dir_file_operations;
proc_sys_root->nlink = 0;
return sysctl_init_bases();
}
int __init sysctl_init_bases(void)
{
register_sysctl_init("kernel", kern_table);
register_sysctl_init("vm", vm_table);
return 0;
}
register_sysctl_init
__register_sysctl_init
register_sysctl_sz
__register_sysctl_table
#注册ctl_table
使用:其实只要在对应的ctl_table下加上对应的条目就好了,然后再去实现对应的handler的功能就好了
- sysfs
sysfs目录下的各个子目录中存放的设备信息并非独立的,我们可以看成不同的目录是从不同的角度来描述某个设备信息;
这个基本过程应该就是:kobject_create_and_add创建一个目录,这个创建的是sysfs接口的目录,,,然后sysfs_create_group创建的这些kobj_attribute才是真正的sysfs文件,,,然后去实现对应的show store等函数。那么读取呢写入是怎么到show和store上的呢?通过VFS吧,读写sysfs本质上就是读文件
- 挂载
可以手动mount,比如mount -t sysfs sysfs /sys
或者/etc/fstab中有的也可能会有这个条目,但是我在现在的机器上没有找到,看来是自动搞到systemd中去了
- kobject对象(目录)
kobject可不只是给sysfs用的,还可以有其他的作用,引用计数、udev事件通知(netlink?)
相关内容在lib/kobject.c中
#这就是创建一个kobject/kset并加入到sysfs中,其实就是相当于创建一个sysfs目录
kobject_create_and_add
kset_create_and_add ##区别在于kset是kobject的集合,管理一组kobject
#kobject_create_and_add第二个参数是父指针,也就是指向他的父级目录,比如kernel_kobj这种的,其实都是kobject_create_and_add
#创建出来的,一堆这个创建出来,并指定父指针,就形成了一种层级结构
#kobject_create_and_add("X",NULL);传入null就是直接在/sys下创建,也就是最顶级的
- 属性
创建属性其实就是在目录下创建具体的文件了,他需要上一步中创建的kobject对象,主要在/include/linux/sysfs.h中
#这些宏很好理解,就是object结构体的赋值,传函数指针等
__ATTR
__ATTR_RO
__ATTR_WO
__ATTR_RW
#这就是attribute结构体,应该属于上层抽象了
#如果是创建sysfs结构体的话,因为是对应kobject结构体的,所以应该是一个kobj_attribute
struct attribute {
const char *name;
umode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
bool ignore_lockdep:1;
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
#这就是要使用__ATTR宏要定义的结构体的kobj_attribute类型
struct kobj_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);
};
#其实这时候就可以写完了,定义好相关结构体后,kobject_create_and_add创建kobject,sysfs_create_file创建file
#后面就再去实现对应的show、store函数就行了
需要注意:kobj_attribute和kobject的这些声明要在show store这些函数的后面,因为得先有这些函数才能正确初始化
- 属性组
能够统一管理一些属性,比如同一目录下的一些属性统一管理的话,可以考虑搞到一个属性组里
struct attribute_group {
const char *name;
umode_t (*is_visible)(struct kobject *,
struct attribute *, int);
umode_t (*is_bin_visible)(struct kobject *,
struct bin_attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};
#用法示例
#像这个,先创建一个kobject(也就是目录),然后创建一个属性
#把属性挂到属性组里面
#接下来只要kobject_create_and_add创建这个kobject,然后sysfs_create_group创建属性组就好了
static struct kobj_attribute vm_cpumask_attr = __ATTR_RW(vm_cpumask);
static struct attribute *cpufreq_monitor_attrs[] = {
&vm_cpumask_attr.attr,
NULL,
};
static struct attribute_group cpufreq_monitor_group = {
.attrs = cpufreq_monitor_attrs,
};
其他:
sysfs_emit
:这个函数是用于简化sysfs中show的方法的函数,show没什么好特殊写的话,使用这个函数就可以,专门用于sysfs上下文
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 857879363@qq.com