sysfs学习(Talking to the Kernel through Sysfs)

背景与简介

  与proc文件系统类似,sysfs也是一个虚拟文件系统,提供内核子模块信息、设备信息、驱动信息等给用户空间。

  proc文件系统出现的初衷是提供进程信息给用户空间,例如ps命令就是通过proc文件系统实现。添加文件或者目录到proc文件系统较为容易,所以很多内核子系统都使用proc文件系统展示信息给用户空间。当然它也支持把用户态的输入带到内核模块中。proc文件系统现在已经有了太多无关的进程的信息了。

  在2.5开发版内核当中,/sys文件系统被引入。用于将内核的数据结构和属性导出到用户空间,避免proc系统的冗余。sysfs文件系统的优点有以下几个方面:

  • 更加简洁,文档规范的编程接口
  • 在设备从系统中移除后,自动清空目录及文件
  • 强制一个实体(item)对应一个文件的规则(one item per file rule),带来更加清晰的用户接口

  通过sysfs系统,用户空间的程序可以从系统内核子系统比如设备驱动上获得信息。程序可以发送信息并且控制内部的相关设置。这就是程序与linux内核交互的接口。

深入sys文件系统

sysfs’s origin

  一般情况下,sysfs是由linux内核编译的,内核编译中有设置CONFIG_SYSFS是否enable的选项,如果没有/ss没有被挂载,那么可以主动mount它:

mount -t sysfs sysfs /sys

  

sysfs’s datastructure

  sysfs的目录都是由kernel objects的数据结构(include/linux/kobject.h)表示的。有关kobject的详细信息可以参考《kobject之禅翻译》这篇博文。

sysfs的目录操作

  • int sysfs_create_dir(struct kobject *kobj);
  • void sysfs_remove_dir(struct kobject *kobj);
  • int sysfs_rename_dir(struct kobject *kobj, const char *new_name);

  创建目录,kobj需要填充与功能相关的name和父kobj的parent两个field。不过在内核开发的时候,上面三个api并不适用,下面这个接口适用于内核开发:

struct kobject * kobject_create_and_add(const char *name, struct kobject *parent);
  • name: sysfs中的名字
  • parent: 父目录的kobject
  • 如果成功返回了将会获得创建目录的kobject指针,失败返回NULL。

接下来举一个创建目录/sys/kernel的例子:

struct kobject *example_dev_kobj;
example_dev_kobj = kobject_create_and_add(example_dev, kernel_kobj);

  kernel_kobj是/sys/kernel的kobject,如果要创建在/sys/firmware里,那么用firmware_kobj。如果要直接创建一个目录在sys/下,那么第二项为NULL即可。

  跟着上面的示例,接下来讲删除的过程:

void kobject_del(struct kobject *kobj);

以上便是删除的接口,如果要删除上面的example_dev_kobj,只要调用该接口即可。

kobject_del(example_dev_kobj);

此外,还有rename的接口用于内核开发:

int kobject_rename(struct kobject *kobj, const char *new_name);

Sysfs的kobject的引用计数

  每一个kobject有一个field叫做kref的数据结构,用于保存引用计数,当任何模块需要用到这个kobjet的时候,引用计数就维护使用这个kobject的模块数量,当kref到0的时候,释放kobject的空间。在kobject_create_and_add执行之后,kref将会被初始化为1,表示在被当前的模块使用。有关引用计数的内核接口如下:

struct kobject* kobject_get(struct kobject *kobj);
struct kobject* kobject_put(struct kobject *kobj);

使用的时候,如果直接用到了内核的一些模块,kobject_get应该被调用,不再使用的时候,调用kobject_put。

sysfs中的文件

  以上讲了sysfs中的目录信息,接下来讲述sysfs中的具体文件。
文件被称为kobject的attribute,数据结构在include/linux/sysfs.h中,attribute重要的信息包括namemode两个内容:

  • name: attribute或者文件的名字
  • mode:文件的权限表示
    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);
};
  • attr 就是文件的表示
  • show是当这个文件被read的时候的处理函数的指针
  • store是这个文件被write的时候处理函数的指针

继续之前那个例子,假如我们要加入一个example_info的文件到之前创建的kobject: example_dev当中,需要用到下面这个方法:

struct kobj_attribute example_info_attr = _ATTR(example_info, 0666, example_show, example_store);

name是文件的名字,0666也就是所有用户都有读写权限,show_ptr是read函数指针,store是write函数指针。
example_info_attr可以被放到一个指针数组里:

struct attribute *example_attrs[] = {
	&example_info_attr.attr,
	NULL
};
// 注意:这里的NULL是不可以缺少的

以上的attribute指针数组需要被再次包装到attribute_group当中:

struct attribute_group example_attr_group = {
 .attrs = example_attrs
 };

为了去创建attributes,可以使用sysfs的API:

int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp);

其中,kobj是当前文件被创建在的父目录,grp是attributes的group。
为了去创建example_info文件到/sys/kernel/example_dev当中,以下的API需要被调用:

sysfs_create_group(example_dev_kobj, &example_attr_group);

在这个步骤结束后,一个叫做example_info的文件将会被创建出来。

接下来需要注意的是重写的show和store函数:

ssize_t (*show)(struct kobject * kobj, struct attribute * attr, char * buff);

其中,kobj就是目录kobject,attr是具体的文件,buff是read文件后得到的内容,大小不允许超过一个PAGE_SIZE。

 (*store)(struct kobject * kobj, struct attribute * attr, const char * buff, size_t size);

相反,对于store函数,buff是用户空间写入的信息,attr是具体文件,kobj仍然是attr所处的当前目录,size是写入信息的大小。
简单示例:

ssize_t example_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, “example show”);
/*Here any value of variable can be written and exposed to user space through this interface
also return value is the size of data written to the buffer*/
}

static ssize_t example_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
//here the value from the buff can be read and //respective action can be taken by module
return count;
//return the number of bytes read, if all the //bytes are read the count parameter which //was received by store routine
}

sysfs中的设备驱动接口

  驱动模块是用户空间和硬件的接口,硬件设备的信息可以由sys文件系统给用户提供。驱动并不需要显式地在sys文件系统中创建,而是在当驱动注册到子系统中,目录就被创建出来了,每一个驱动拥有一个struct device的指针,设备指针用于在驱动接口上创建文件。驱动把设备的每一部分信息作为一个文件,驱动使用以下具体的API用于用户空间:

int device_create_file(struct device *dev, const struct device_attribute *attr);

其中,dev是设备的指针,attr是集那个要被创建的文件,如果要删除文件,那么使用下面的API:

void device_remove_file(struct device *dev, const struct device_attribute *attr)

Sysfs 中对象的关系

  假设这里有一个目录:/sys/kernel/example1,kobject指针为ex1_kobj,现在有一个创建一个链接文件的需求在/sys/kernel/example2中,链接名字叫ex2在example1中,example2的目录叫ex2_kobj,可以通过符号链接来实现,API:

int sysfs_create_link(struct kobject *kobj, struct kobject *target, char *name);

kobj是存放目录的指针,例子中也就是就是ex1_kobj,target是目标目录,ex2_kobj,name是软链接的名字。示例就是:

sysfs_create_link(ex1_kobj, ex2_kobj, ex2);

删除的api为:

void sysfs_remove_link(struct kobject *kobj, char *name);

示例为:

sysfs_remove_link(ex2_kobj, ex2);

参考

1 Talking to the Kernel through Sysfs

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值