sysfs文件系统

        sysfs文件系统是内核2.6的一个特性,通过in-memory文件系统的方式把内核对象(object)信息暴露给用户程序。参考:https://www.kernel.org/pub/linux/kernel/people/mochel/doc/papers/ols-2005/mochel.pdf

note:本文是对sysfs的一些简单介绍,有很多不足之处----对于代码的结构都介绍的不够详细,相关代码在内核fs/sysfs目录下

介绍

sysfs是一种代表内核对象的机制,内核对象的属性和内核对象相互之间的关系。从sysfs的目的来看,是把原本在procfs中的,关于设备的部分独立出来,以“设备层次结构”的形式呈现。它提供了两个组件,一个内核编程接口来把这些item通过sysfs暴露出来;另外一个组件是用户接口,来view和操作这些item(对应着相应的内核对象)。从内核的角度来看,sysfs是作为一个基础架构的核心组件,所以接口很简单,要执行的任务也很简单。

sysfs是内核和用户空间的一个通道。用户空间的程序可以通过很多方式来利用这个信息。比如说现有的利用就有io调度器(决定操作系统把io请求传递给存储volume)的参数和udev程序。因为sysfs是最简单也是最抽象的接口,它和每个子系统的交互其实很多。尤其是对于kobject和设备驱动,他们都是2.6的内核的新的特性,他们都和sysfs相互纠缠着使用。这方面的知识我还要自己去脑补,比如下面这些。

历史

sysfs源自ramfs(大概是linux内核2.4版的时候出现的),ramfs的诞生或许只是为了验证当时刚刚出现的VFS文件系统。这为后来写memory-based的文件系统打下了基础。sysfs原来叫做ddfs(device driver fs),本来是用于作为新诞生的设备模型(device model)的调试工具(debug tool)的。而在这之前,调试的代码是使用procfs的,通过输出一个设备tree来进行相关的调试。不过大概是因为设备模型的出现,加上Linus
Torvarlds不停的督促,于是就有了这个文件系统。

在2.5.1的时候,它把名字改为了driverfs,又隔了一年,因为这个设备模型和driverfs证明了对其他的子系统也有作用,kobject这个数据结构被用来提供一种中心化的控制机制,最后从driverfs改名字为sysfs,来表明它对所有的子系统是没有偏见的。

相关内核知识

note:很多都可以参考《linux设备驱动程序》的第十四章设备模型http://oss.org.cn/kernel-book/ldd3/ch14.html

Kobject

对每个在sysfs中发现的目录,有一个kobject潜伏在内核某处,每个kobject输出一个或者多个属性,它出现在kobject的sysfs目录,作为包含内核产生的信息的文件。sysfs文件系统所读写的信息是存放在kobject中的;

那么怎么理解kobject所在的位置呢?Kobject是基础的结构,它保持设备模型在一起,初始的它作为一个简单的引用计数,但是他的责任随着时间增长,并且有了它自己的战场;一个kobject,很少对它自己感兴趣,它存在仅仅是为了结合一个高级对象到设备模型。Kobject被嵌入到其他结构(比如bus和device,相当于cpp的容器)中,kobject结构的作用相当于C++中的基类。因为C语言没有直接表达继承的功能,因此将一个结构嵌入到另一个结构的事情必须使用(如device,bus和drivers都是典型的容器。这些容器就是通过kobject连接起来了,组成一个树状结构)。

但是c语言这种结构嵌入的设计方式,常常会出现一些问题,比如在这里,对于一个struct kobject指针,什么是包含这个结构的指针呢?这或许可以使用内核中常用的宏container_of。

设备驱动和设备模型

机器上有各种各样的设备,设备需要设备驱动来使得应用程序可以使用它。在2.5内核开发循环中,是为内核创建一个统一的设备模型。这需要一个通用的描述系统结构的抽象。linux设备模型是一个复杂的数据结构,设备模型代码负责这些方面,而不强加于驱动作者之上。和设备模型的直接交互通常由其他各种内核子系统处理。通过sysfs和用户空间交互也是一个设备模型的功能。

Kset和subsystem

虽然说kobject可以类比是对象的基类,那么kset则像是kobject的基类,顶层容器类。当我们读或者写一个属性的时候,sysfs会访问一个特殊的结构,通过kobject来访问的ksets结构。这个结构包括一些基本的读写特殊类型的kobject属性的操作。这些函数把kobject和它的属性翻译成更高级别的对象,然后传递给show和store函数。一个kset包含一个子系统指针(称为subsys),那么什么是子系统呢?

一个子系统是作为一个整体对内核一个高级部分的代表. 子系统常常(但是不是一直)出现在 sysfs 层次的顶级. 一些内核中的例子子系统包括block_subsys(/sys/block, 给块设备), devices_subsys(/sys/devices, 核心设备层次),一个子系统由一个简单结构代表:

struct subsystem {
 struct kset kset;
 struct rw_semaphore rwsem;
};

一个子系统, 因此, 其实只是一个对 kset 的包装, 有一个旗标丢在里面.

设备驱动 and 字符设备驱动

计算机本科的操作系统课程应该要求写过设备驱动程序。用mknode命令创建设备文件。然后通过内核提供的接口来注册字符设备,主要是完成几个参数的提供(主设备号,名字和文件操作的数据结构的填充)。随着内核功能的增加,这个结构的定义也越来越复杂,不过我们写驱动的时候也只要写一些最基本的。

加载sysfs:mount和fstab

加载mount -tsysfs sysfs /sys

/etc/fstab;fstab包含了文件系统和存储设备的信息。同时fsck,mount等命令都利用该文件。

Sysfs文件系统导航

# ll /sys

total 0

drwxr-xr-x  2 root root 0 Nov 21 17:09 block

drwxr-xr-x 19 root root 0 Nov 21 17:09 bus

drwxr-xr-x 56 root root 0 Nov 21 17:09 class

drwxr-xr-x  4 root root 0 Nov 21 17:09 dev

drwxr-xr-x 14 root root 0 Nov 21 17:09 devices

drwxr-xr-x  5 root root 0 Nov 21 17:09 firmware

drwxr-xr-x  5 root root 0 Nov 21 17:09 fs

drwxr-xr-x  5 root root 0 Nov 21 17:09 hypervisor

drwxr-xr-x  7 root root 0 Nov 21 17:09 kernel

drwxr-xr-x 117 root root 0 Nov 21 17:09module

drwxr-xr-x  2 root root 0 Nov 21 17:10 power

最高层次的目录表示了代表了注册了sysfs的主要的几个子系统。这些目录在系统开启的时候,当这些子系统把他们自己注册到kobject core的时候就创建了。当这些子系统初始化后,他们开始去发现对象(注册到他们分别的目录)。下面将分别介绍。

Block:块设备子系统,包含了系统发现的每个块设备的信息,然后在每个块设备的子目录中包含了描述这个块设备的属性的文件,包括块设备的大小和dev_t号码。也有指向实际的物理设备的符号链接。并且,还有一个目录是关于IO调度器的接口的,主要是一些统计信息和一些可以用于优化系统性能的特征。

然后是一个块设备的分区。主要是关于这个分区的一些只读的属性。

Bus:总线子系统包含了内核支持注册的每种物理总线类型。每种总线类型包含了两个子目录,分别是devices和drivers。Devices目录包含了整个系统的那种总线的发现的每个设备。驱动目录包含了注册了这种总线的所有的设备驱动,每种设备的驱动有一个目录,使得可以查看和操作驱动的一些参数。

Class:代表了每个设备注册内核的每个设备class。一个设备class描述了一个设备的功能类型。一个设备可能有不止一个逻辑功能。每一个class和class对象可能包含一些属性(暴露的参数)用来描述和控制class object。

Devices:包含了一个全局的设备层次结构。因为设备都是按照上级和下级的关系出现的。有两种特殊类型的设备,一个是平台设备,另外一个是系统设备。

Firmware:包含处理固件的对象和属性。

Module:每个加载到内核的模块。

Power:power子系统

通用内核信息

初始化

利用的是fs/sysfs/mount.c的内容,通过sysfs_init这个函数来初始化的。这个函数被VFS的初始化函数直接调用(很早就被调用了,因为很多的subsystems都依靠于sysfs来注册他们的对象)

这个函数主要做了三件事情:

1.      creat a kmem_cahe:这个cache用来sysfs_dirent对象的分配。(我们知道kmalloc和kfree用来实现数据结构的使用和释放,而更加高效的方式就是使用这种slab高速缓存管理器)。

sysfs_dir_cachep= kmem_cache_create("sysfs_dir_cache",sizeof(struct sysfs_dirent), 0, 0, NULL);

当需要分配一个你需要的结构体空间的时候,只需要调用kmen_cache_alloc函数。

2.      在VFS中注册。

register_filesystem(&sysfs_fs_type);

3.      内部的挂载。做这个是为了保证其他的内核代码总是可以使用sysfs,即使是在启动阶段。

sysfs_mnt= kern_mount(&sysfs_fs_type);

内核配置

Sysfs在默认情况下是被编译进了内核的。他依靠于CONFIG_SYSFS这个内核选项。(只是在CONFIG_EMBEDDED这个选项设置了的时候。这个菜可以进行自定义的配置。)

内核接口overview

对内核代码可见的函数大概分为三类;除了这些还有一些特殊类型的,那就是二进制属性和属性组。

1.内核对象(目录)

2.对象属性(常规文件)

3.对象之间的关系(符号链接)

对象的属性

对象的属性在外表现为sysfs中的常规文件,使用struct attribute数据结构来表示。它的函数主要有sysfs_create(remove,update)_file,文件的创建当然是名字,和mode,然后就是module的owner(这个待会再仔细说),然后就是创建在哪个目录下(由kobject的位置表示)。

关于属性和模块的关系?

owener是由create_file的调用者设定的,来指向这个属性代码所处的模块.比如说,网络设备有很多统计信息,通过sysfs表达为属性信息。这种统计属性应该放在外部模块中,这样就不需要加载了,能够使得网络设备更好的发挥作用。当这个外部模块加载后,里面包含的属于每一个注册的网络设备的属性都创建起来。这个模块也可以在任何时候卸载,将每个网络设备的属性从sysfs中移除掉。

当这个属性文件被访问的时候,owner这个字段是用来做引用计数的(通过update函数).VFS调用的属性文件操作通过sysfs内部函数设置。

包装的对象属性

struct attribute(数据结构和相应的函数)并没有包含读和写的属性。sysfs没有指定这些函数的格式和参数,这是一个显示的设计。

使用sysfs属性的子系统创建了一种新的数据类型用来包装struct attribute。通过定义一个包装纸数据结构struct device_attribute,这种数据我也没能力在这里描述了。这个可以让我们保护下层的代码,免受sysfs细节的影响。

当一个属性被读写的时候,sysfs通过kobject使用一个特殊的数据结构,叫做kset。这个结构包括基本的读写属性(特殊类型的kobjects)的操作,这些函数将kobject和属性转化为更高级别的对象,然后再把这些对象传送给show和store函数指针。再次说明,这帮助你确保了类型的安全,因为它保证了下层接受函数接收的参数是更高级别的对象。

一般来说,程序员都不喜欢对象之间的类型转换,因为如果数据结构中的字段的位置改变的话,这很容易导致很难发现的bugs。通过内核中帮助函数,执行迁移指针的减法操作来进行对象间类型转换,从而保证了对象类型安全(即使字段位置可能改变)。

读写属性

sysfs一定会尽量使得读写属性越简单越好,当一个属性文件打开后,一个页大小的page被分配用来在用户空间和内核空间来传递数据,当一个属性读的时候,这个buffer会被传送给下游的函数,比如show(是负责用来填充数据的,并且合适的格式化的)。这个数据然后被传递到用户空间。

而当写一个sysfs属性文件的时候,数据首先被复制到内核buffer,然后传给下游的函数(along with buffer的大小)。这个函数负责解析数据。一般认为写入buffer的数据是ascii字符,也认为写入的数据的大小不到一页的大小。如果按照传统,一个文件的大小应该不超过一个页。

然后就是属性的更新啦,如果一个属性的值改变了,内核代码可以通过update函数通知用户空间程序。

内核对象之间的关系

sysfs文件系统有通常的树结构,它代表的kobjects的层次组织。但是内核中对象间的关系常常比那个复杂。(符号链接)符号链接是为了防止冗余信息的出现。例子,考虑一个pci网络设备和驱动,当系统启动时,这个pci设备被发现,然后给他创建了一个sysfs目录,即使它还没有绑定到一个驱动。过了一些时间后,这个网络驱动才加载,这个驱动也可能不和任何设备发生绑定。这是一个和物理pci设备不一样的对象类型,所以也会给它创建一个新的目录。在driver的目录下面就会有一个符号链接,指向他绑定的真正的设备。

·属性组

为什么要有属性组呢?为了在一次调用的时候就可以轻松的添加或者删除一组属性。这个attribute_group数据结构和相应的函数也是有定义的,也可能是一个子目录。比如说网络设备的统计信息就是一个很好的例子。

二进制属性

这是一种特殊类型的常规文件。和procfs的接口有点像,因为有的需要已知的特殊的格式,比如说PCI配置空间。

现有的sysfs的用户

比如udev,使用了libsysfs的c语言中的库;另外pciutils也使用了sysfs来访问pci配置信息。

时间: 2024-11-05 22:36:30

sysfs文件系统的相关文章

Linux设备模型——设备驱动模型和sysfs文件系统解读

本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的.在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解.其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解. 内核版本:2.6.30 1. What is sysfs? 个人理解:sysfs向用户空间展示了驱动设备的层次结构.我们都知道设备和对应的驱动都是由内

20150225 IMX257 设备驱动模型之sysfs文件系统知识点整合(二)

20150225 IMX257 设备驱动模型之sysfs文件系统知识点整合(二) 2012-02-25 李海沿 前天我们实现了一个简单的sysfs的kobject的驱动程序,可是有没有发现很多东西都不懂,原因就是在我们对sysfs和kobject的工作原理不懂,虽然我一直不提倡整天接触那些乏味的知识点,也一直不喜欢谈论太多的知识点,但是有的时候,理论知识是实践的基础,有些基础的知识点还是不得不提,下面进入正题. 一.sysfs介绍 在linux2.6内核以后,引入了一个新的文件系统sysfs,它

proc文件系统、sysfs文件系统、kobject操作

Proc文件系统是提供一个接口给用户,让用户可以查看系统运行的一些状态信息,让用户修改内核的一些参数,比方说printk的打印级别就可以通过proc去修改 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 t

概述sysfs文件系统【转】

转自:http://blog.csdn.net/npy_lp/article/details/78933292 内核源码:linux-2.6.38.8.tar.bz2 目标平台:ARM体系结构 sysfs是基于内存的文件系统,用于向用户空间导出内核对象并且能对其进行读写. 1.sysfs文件系统不支持特殊文件,只支持目录.普通文件(文本或二进制文件)和符号链接文件等三种类型,在内核中都使用struct  sysfs_dirent结构体来表示,相当于其他文件系统在硬盘或flash里的数据.源代码如

sysfs文件系统的建立【转】

http://blog.csdn.net/dndxhej/article/details/7434615 对sysfs和设备模型有了解的都会知道sysfs实际是为了将设备模型导出到用户空间的一个内存文件系统. 设备模型的关键结构体kobject会组成设备模型的树形结构,而sysfs的关键结构体sysfs_dirent也是类似的树形的结构,vfs中的dentry同样是类似的树形结构. sysfs目录文件的创建都是由设备模型的上层构件(bus device driver class)在注册的时候调用

sysfs文件系统与Linux设备模型

由于linux的内核空间和用户空间是严格分开的,所以sysfs可以看做是用户空间和内核空间的一座桥梁, sysfs把连接在系统上的设备和总线组织成为一个分级的文件,他们可以由用户空间存取,向用户空间导出内核数据结构以及他们的属性. /sys/ 的顶级目录包括:block, device, bus, drivers, class, power, firmware. block 目录包含所有块设备 devices 目录包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构 bus 目录包含系统中

根文件系统挂载过程

目录 注册挂载rootfs文件系统 解压initramfs到rootfs中 prepare_namespace挂载磁盘上的文件系统 注册挂载rootfs文件系统 首先是rootfs的注册和挂载,rootfs作为一切后续文件操作的基石. start_kernel vfs_caches_init mnt_init init_rootfs注册rootfs文件系统 init_mount_tree 挂载rootfs文件系统 vfs_kern_mount mount_fs type->mount其实是roo

构建最简单的根文件系统

       本文将介绍如何构建一个最简单的根文件系统,并且初步分析内核如何执行第一个内核程序.     挂接根文件系统       在挂接根文件系统之前,需要制作根文件系统.根文件系统里面需要一些基本的命令,目录和设备文件,下面来介绍如何使用busybox来制作根文件系统.       我们都知道,init进程是系统启动后执行的第一个应用程序,根据一般的Linux应用程序配置结构,一个可执行文件通常搭配一个对于的配置文件,例如samba功能对于/etc/samba/smb.conf配置文件,n

linux文件系统---10

进入 Linux 根目录(即“/”, Linux 文件系统的入口, 也是处于最高一级的目录),运行“ls –l”命令,可以看到 Linux 系统包含以下目录. 1./bin 包含基本命令,如 ls.cp.mkdir 等,这个目录中的文件都是可执行的. 2./boot Linux 系统的内核及引导系统程序所需要的文件,如 vmlinuz.initrd.img 文件都位于这个目录中. 3./dev 设备文件存储目录,应用程序通过对这些文件的读写和控制就可以访问实际的设备. 4./etc 系统配置文件