Linux内核文档之sysfs文件系统
2021-01-03 22:10:22 阿炯

sysfs - The filesystem for exporting kernel objects.
sysfs - 用于导出内核对象(kobject)的文件系统。


Sysfs是Linux 2.6所提供的一种虚拟文件系统。这个文件系统不仅可以把设备(devices)和驱动程序(drivers)的信息从内核输出到用户空间,也可以用来对设备和驱动程序做设置。Linux内核开发团队在Linux 2.5的开发过程中引入了“Linux驱动程序模型(Linux driver model)”,以解决2.4核心遭遇的以下的3个问题:
1)、没有统一的机制表达驱动程序和设备的关系。
2)、不存在一般的热插拔(hotplug)机制。
3)、procfs文件系统过度混乱,包含了许多非进程(process)的信息。

sysfs的目的是把一些原本在procfs中的,关于设备的部分,独立出来,以“设备层次结构架构(device tree)”的形式呈现。这个文件系统由Patrick Mochel所写,之后Maneesh Soni撰写“sysfs backing store path”,以降低在大型系统中对存储器的需求量。程序开发层也有提供:SYSFS(5)

sysfs一开始ramfs为基础,也是一个只存在于内存中的文件系统,ramfs是在2.4核心处于稳定阶段时加入的。ramfs是一个优雅的实现,简洁以及使用了VFS,稍后的一些存储器形式的文件系统都以它作为开发基础。

sysfs刚开始被命名成ddfs(Device Driver Filesystem),当初只是为了要对新的驱动程序模型调试而开发出来的。它在调试时,会把设备架构(device tree)的信息输出到procfs文件系统中。但在Linus Torvalds的急切督促下,ddfs被转型成一个以ramfs为基础的文件系统。在新的驱动程序模型被集成进2.5.1核心时,ddfs被改名成driverfs,以更确切描述它的用途。

在2.5核心开发的次年,新的“驱动程序模型”和"driverfs"证明了对核心中的其他子系统也有用处。kobjects被开发出来,作为核心对象的中央管理机制,而此时driverfs也被改名成sysfs。 每个被加入driver model tree内的对象,包括驱动程序、设备以及class设备,都会在sysfs文件系统中以一个目录呈现。对象的属性作为文件出现,符号链接代表对象间的关系。通常安装在/sys目录下:mount -t sysfs sysfs /sys

Patrick Mochel <mochel@osdl.org>
Mike Murphy <mamurph@cs.clemson.edu>
Revised: 16 August 2011 Original: 10 January 2003
中文版维护者:傅炜 Fu Wei <tekkamanninja@gmail.com>

What it is:
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并且位于内存的文件系统。它提供导出内核数据结构及其属性,以及它们之间关联到用户空间的方法。

sysfs is tied inherently to the kobject infrastructure. Please read Documentation/kobject.txt for more information concerning the kobject interface.

sysfs始终与kobject的底层结构紧密相关。请阅读Documentation/kobject.txt文档以获得更多关于kobject接口的信息。

Using sysfs
使用sysfs

~~~~~~~~~~~

sysfs is always compiled in if CONFIG_SYSFS is defined. You can access it by doing:

只要内核配置中定义了CONFIG_SYSFS,sysfs将会被编译进内核。你可以通过以下命令挂载它:
mount -t sysfs sysfs /sys

Directory Creation
创建目录

~~~~~~~~~~~~~~~~~~

For every kobject that is registered with the system, a directory is created for it in sysfs. That directory is created as a subdirectory of the kobject's parent, expressing internal object hierarchies to userspace. Top-level directories in sysfs represent the common ancestors of object hierarchies; i.e. the subsystems the objects belong to.

任何kobject在系统中注册后,就会有一个目录在sysfs中被创建。这个目录是作为该kobject的父对象所在目录的子目录创建的,用以准确地传递内核的对象层次到用户空间。sysfs中的顶层目录代表着内核对象层次的共同祖先;例如:某些对象属于某个子系统。

Sysfs internally stores a pointer to the kobject that implements a directory in the kernfs_node object associated with the directory. In the past this kobject pointer has been used by sysfs to do reference counting directly on the kobject whenever the file is opened or closed. With the current sysfs implementation the kobject reference count is only modified directly by the function sysfs_schedule_callback().

sysfs在与其目录关联的sysfs_dirent对象中内部保存一个指向实现目录的kobject的指针。以前,这个kobject指针被sysfs直接用于kobject文件打开和关闭的引用计数。而目前的sysfs实现中,kobject引用计数只能通过sysfs_schedule_callback()函数直接修改。

Attributes
属性

~~~~~~~~~~

Attributes can be exported for kobjects in the form of regular files in the filesystem. Sysfs forwards file I/O operations to methods defined for the attributes, providing a means to read and write kernel attributes.

kobject的属性可在文件系统中以普通文件的形式导出。sysfs为属性定义了面向文件I/O操作的方法,以提供对内核属性的读写。

Attributes should be ASCII text files, preferably with only one value per file. It is noted that it may not be efficient to contain only one value per file, so it is socially acceptable to express an array of values of the same type.

属性应为ASCII码文本文件。以一个文件只存储一个属性值为宜。但一个文件只包含一个属性值可能影响效率,所以一个包含相同数据类型的属性值数组也被广泛地接受。

Mixing types, expressing multiple lines of data, and doing fancy formatting of data is heavily frowned upon. Doing these things may get you publicly humiliated and your code rewritten without notice.

混合类型、表达多行数据以及一些怪异的数据格式会遭到强烈反对。这样做是很丢脸的,而且其代码会在未通知作者的情况下被重写。

An attribute definition is simply:
一个简单的属性结构定义如下:
struct attribute {
    char            *name;
    struct module           *owner;
    umode_t       mode;
};

int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);

A bare attribute contains no means to read or write the value of the attribute. Subsystems are encouraged to define their own attribute structure and wrapper functions for adding and removing attributes for a specific object type.

一个单独的属性结构并不包含读写其属性值的方法。子系统最好为增删特定对象类型的属性,而定义自己的属性结构和封装函数。

For example, the driver model defines struct device_attribute like:

例如:驱动程序模型定义的device_attribute结构体如下:
struct device_attribute{
    struct attribute        attr;
    ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
    ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
};

int device_create_file(struct device *, const struct device_attribute *);
void device_remove_file(struct device *, const struct device_attribute *);


It also defines this helper for defining device attributes:
为了定义设备属性,同时引入了辅助宏:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

For example, declaring:
例如,下面的声明:
static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);

is equivalent to doing:
等同于下面的代码:
static struct device_attribute dev_attr_foo = {
    .attr = {
         .name = "foo",
         .mode = S_IWUSR | S_IRUGO,
    },
    .show = show_foo,
    .store = store_foo,
};

Subsystem-Specific Callbacks
子系统特有的回调函数

~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When a subsystem defines a new attribute type, it must implement a set of sysfs operations for forwarding read and write calls to the show and store methods of the attribute owners.

当一个子系统定义一个新的属性类型时,必须实现一系列的sysfs操作,以帮助读写调用去实现属性所有者的显示和存储方法。

struct sysfs_ops{
    ssize_t (*show)(struct kobject *, struct attribute *, char *);
    ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};

[ Subsystems should have already defined a struct kobj_type as a descriptor for this type, which is where the sysfs_ops pointer is stored. See the kobject documentation for more information. ]

[子系统应已经定义了一个struct kobj_type结构体作为这个类型的描述符,并在此保存sysfs_ops的指针。更多的信息参见kobject的文档]

When a file is read or written, sysfs calls the appropriate method for the type. The method then translates the generic struct kobject and struct attribute pointers to the appropriate pointer types, and calls the associated methods.

当一个文件被读写时,sysfs会为这个类型调用适当的方法。这个方法会将一般的kobject和attribute结构体指针转换为适当的指针类型后调用相关联的函数。

To illustrate:
示例:

#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)

static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, char *buf){
    struct device_attribute *dev_attr = to_dev_attr(attr);
    struct device *dev = to_dev(kobj);
    ssize_t ret = -EIO;

    if (dev_attr->show)
        ret = dev_attr->show(dev, dev_attr, buf);

    if (ret >= (ssize_t)PAGE_SIZE) {
        print_symbol("dev_attr_show: %s returned bad count\n", (unsigned long)dev_attr->show);
    }
    
    return ret;
}        

Reading/Writing Attribute Data
读/写属性数据

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To read or write attributes, show() or store() methods must be specified when declaring the attribute. The method types should be as simple as those defined for device attributes:

在声明属性时,必须指定show()或store()函数,以实现属性的读或写。这些函数的类型应该和以下的设备属性定义一样简单。

ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);

IOW, they should take only an object, an attribute, and a buffer as parameters.

也就是说,它们应该只以一个处理对象、一个属性和一个缓冲指针作为参数。

sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the method. Sysfs will call the method exactly once for each read or write. This forces the following behavior on the method implementations:

sysfs会分配一个大小为(PAGE_SIZE)的缓冲区并传递给这个函数。sysfs将会为每次读写操作调用一次这个函数。这使得这些函数在执行时会出现下面以下的行为:

- On read(2), the show() method should fill the entire buffer. Recall that an attribute should only be exporting one value, or an array of similar values, so this shouldn't be that expensive.

- 在读方面(read(2)),show()函数应该填充整个缓冲区。前面提到,属性应只导出了一个属性值或是一个同类型属性值的数组,所以这个代价将不会太高。

This allows userspace to do partial reads and forward seeks arbitrarily over the entire file at will. If userspace seeks back to zero or does a pread(2) with an offset of '0' the show() method will be called again, rearmed, to fill the buffer.

这使得用户空间可以局部地读和任意向前搜素整个文件。如果用户空间向后搜索到0或使用”0”偏移执行一个pread(2)操作,show()方法将再次被调用,以重新填充缓存。

- On write(2), sysfs expects the entire buffer to be passed during the first write. Sysfs then passes the entire buffer to the store() method. A terminating null is added after the data on stores. This makes functions like sysfs_streq() safe to use.

- 在写方面(write(2)),sysfs希望第一次写操作时得到整个缓冲区,之后sysfs传递整个缓冲区给store()函数。

When writing sysfs files, userspace processes should first read the entire file, modify the values it wishes to change, then write the entire buffer back.

当要写sysfs文件时,用户空间进程首先读取整个文件,修改需要改变的值后,然后将值回写到整个缓冲区。


Attribute method implementations should operate on an identical buffer when reading and writing values.

当读写属性值时,属性函数的执行应操作相同的缓冲区。

Other notes:
注意:

- Writing causes the show() method to be rearmed regardless of current file position.

- 写操作将导致的show()方法重载,会忽略当前文件位置。

- The buffer will always be PAGE_SIZE bytes in length. On i386, this is 4096.

- 缓冲区应总是PAGE_SIZE的大小。对于i386,这个值为4096。

- show() methods should return the number of bytes printed into the buffer. This is the return value of scnprintf().

- show()函数应该返回写入缓冲区的字节数,也就是scnprintf()的返回值。

- show() must not use snprintf() when formatting the value to be returned to user space. If you can guarantee that an overflow will never happen you can use sprintf() otherwise you must use scnprintf().

- 格式化要返回给用户空间的值时,show()不得使用snprintf()。如果可以保证溢出永远不会发生时,你可以使用sprintf(),否则,你必须使用scnprintf()。

- store() should return the number of bytes used from the buffer. If the entire buffer has been used, just return the count argument.

- store()应返回缓冲区的已用字节数。如果整个缓冲区都已填满,只需要返回count参数。

- show() or store() can always return errors. If a bad value comes through, be sure to return an error.

- show()或store()可以返回错误值。当得到一个非法值,必须返回一个错误值。

- The object passed to the methods will be pinned in memory via sysfs referencing counting its embedded object. However, the physical entity (e.g. device) the object represents may not be present. Be sure to have a way to check this, if necessary.

- 一个传递给函数的对象将会通过sysfs调用对象内嵌的引用计数固定在内存中。尽管如此,对象代表的物理实体(如设备)可能已不存在。如有必要,应该实现一个检测机制。


A very simple (and naive) implementation of a device attribute is:
一个简单的(未经实验证实的)设备属性实现如下:
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf){
    return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
}

static ssize_t store_name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){
    snprintf(dev->name, sizeof(dev->name), "%.*s", (int)min(count, sizeof(dev->name) - 1), buf);
    return count;
}

static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);

(Note that the real implementation doesn't allow userspace to set the name for a device.)
(注意:真正的实现不允许用户空间设置设备名)


Top Level Directory Layout
顶层目录布局

~~~~~~~~~~~~~~~~~~~~~~~~~~

The sysfs directory arrangement exposes the relationship of kernel data structures.

sysfs目录的安排显示了内核数据结构之间的关系。

The top level sysfs directory looks like:
顶层的sysfs目录如下:
block/
bus/
class/
dev/
devices/
firmware/
net/
fs/


devices/ contains a filesystem representation of the device tree. It maps directly to the internal kernel device tree, which is a hierarchy of struct device.

devices/包含了一个设备树的文件系统表示。它直接映射了内部的内核设备树,反映了设备的层次结构。

bus/ contains flat directory layout of the various bus types in the kernel. Each bus's directory contains two subdirectories:

bus/包含了内核中各种总线类型的平面目录布局。每个总线目录包含两个子目录:
devices/
drivers/

devices/ contains symlinks for each device discovered in the system that point to the device's directory under root/.

devices/包含了系统中出现的每个设备的符号链接,它们指向root/下的设备目录。


drivers/ contains a directory for each device driver that is loaded for devices on that particular bus (this assumes that drivers do not span multiple bus types).

drivers/包含了每个已为特定总线上的设备而挂载的驱动程序的目录(这里假设驱动没有跨越多个总线类型)


fs/ contains a directory for some filesystems.  Currently each filesystem wanting to export attributes must create its own hierarchy below fs/ (see ./fuse.txt for an example).

fs/包含了一个为文件系统设立的目录。现在,每个想要导出属性的文件系统必须在fs/下创建自己的层次结构(参见Documentation/filesystems/fuse.txt)。


dev/ contains two directories char/ and block/. Inside these two directories there are symlinks named <major>:<minor>.  These symlinks point to the sysfs directory for the given device.  /sys/dev provides a quick way to lookup the sysfs interface for a device from the result of a stat(2) operation.

dev/包含两个子目录:char/和block/。在这两个子目录中,有以<major>:<minor>格式命名的符号链接。这些符号链接指向sysfs目录中相应的设备。/sys/dev提供一个通过一个stat(2)操作结果,查找设备sysfs接口快捷的方法。

More information can driver-model specific features can be found in Documentation/driver-model/.

更多有关driver-model的特性信息可以在Documentation/driver-model/中找到。

TODO: Finish this section.

完成这一节。


Current Interfaces
目前接口

~~~~~~~~~~~~~~~~~~

The following interface layers currently exist in sysfs:
以下的接口层普遍存在于当前的sysfs中:

- devices (include/linux/device.h)

----------------------------------

Structure:
结构体:
struct device_attribute {
    struct attribute        attr;
    ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
    ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
};

Declaring:
声明:
DEVICE_ATTR(_name, _mode, _show, _store);

Creation/Removal:
增加/删除属性:
int device_create_file(struct device *dev, const struct device_attribute * attr);
void device_remove_file(struct device *dev, const struct device_attribute * attr);

- bus drivers (include/linux/device.h)

--------------------------------------

Structure:
结构体:
struct bus_attribute {
    struct attribute        attr;
    ssize_t (*show)(struct bus_type *, char * buf);
    ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
};    

Declaring:
声明:
BUS_ATTR(_name, _mode, _show, _store);

Creation/Removal:
增加/删除属性:
int bus_create_file(struct bus_type *, struct bus_attribute *);
void bus_remove_file(struct bus_type *, struct bus_attribute *);

- device drivers (include/linux/device.h)

-----------------------------------------

Structure:
结构体:
struct driver_attribute {
    struct attribute        attr;
    ssize_t (*show)(struct device_driver *, char * buf);
    ssize_t (*store)(struct device_driver *, const char * buf, size_t count);
};

Declaring:
声明:
DRIVER_ATTR_RO(_name) DRIVER_ATTR_RW(_name);

Creation/Removal:
增加/删除属性:
int driver_create_file(struct device_driver *, const struct driver_attribute *);
void driver_remove_file(struct device_driver *, const struct driver_attribute *);

 
Documentation
文档

~~~~~~~~~~~~~

The sysfs directory structure and the attributes in each directory define an ABI between the kernel and user space. As for any ABI, it is important that this ABI is stable and properly documented. All new sysfs attributes must be documented in Documentation/ABI.See also Documentation/ABI/README for more information.

sysfs目录结构以及其中包含的属性定义了一个内核与用户空间之间的ABI。对于任何ABI,其自身的稳定和适当的文档是非常重要的。所有新的sysfs属性必须在Documentation/ABI中有文档,详见Documentation/ABI/README。

Linux 设备模型

1、设备模型概述

从2.6版本开始,Linux开发团队便为内核建立起一个统一的设备模型。在以前的内核中没有独立的数据结构用来让内核获得系统整体配合的信息。尽管缺乏这些信息,在多数情况下内核还是能正常工作的。然而,随着拓扑结构越来越复杂,以及要支持诸如电源管理等新特性的需求,向新版本的内核明确提出了这样的要求:需要有一个对系统结构的一般性抽象描述,即设备模型。

目的

I、设备、驱动、总线等彼此之间关系错综复杂。如果想让内核运行流畅,那就必须为每个模块编码实现这些功能。如此一来,内核将变得非常臃肿、冗余。而设备模型的理念即是将这些代码抽象成各模块共用的框架,这样不但代码简洁了,也可让设备驱动开发者摆脱这本让人头痛但又必不可少的一劫,将有限的精力放于设备差异性的实现。

II、设备模型用类的思想将具有相似功能的设备放到一起管理,并将相似部分萃取出来,使用一份代码实现。从而使结构更加清晰,简洁。

III、动态分配主从设备号,有效解决设备号的不足。设备模型实现了只有设备在位时才为其分配主从设备号,这与之前版本为每个设备分配一个主从设备号不同,使得有限的资源得到合理利用。

IV、设备模型提供sysfs文件系统,以文件的方式让本是抽象复杂而又无法捉摸的结构清晰可视起来。同时也给用户空间程序配置处于内核空间的设备驱动提供了一个友善的通道。

V、程序具有随意性,同一个功能,不同的人实现的方法和风格各不相同,设备驱动亦是如此。大量的设备亦若实现方法流程均不相同,对以后的管理、重构将是难以想象的工作量。设备模型恰是提供了一个模板,一个被证明过的最优的思路和流程,这减少了开发者设计过程中不必要的错误,也给以后的维护扫除了障碍。

2、设备模型结构

如下表,Linux设备模型包含以下四个基本结构:

类型

所包含的内容

内核数据结构

对应/sys

设备(Devices)

设备是此模型中最基本的类型,以设备本身的连接按层次组织

struct device

/sys/devices/*/*/.../

驱动(Drivers)

在一个系统中安装多个相同设备,只需要一份驱动程序的支持

struct device_driver

/sys/bus/pci/drivers/*/

总线(Bus)

在整个总线级别对此总线上连接的所有设备进行管理

struct bus_type

/sys/bus/*/

类别(Classes)

这是按照功能进行分类组织的设备层次树;如 USB 接口和 PS/2 接口的鼠标都是输入设备,都会出现在/sys/class/input/下

struct class

/sys/class/*/




device、driver、bus、class是组成设备模型的基本数据结构。kobject是构成这些基本结构的核心,kset又是相同类型结构kobject的集合。kobject和kset共同组成了sysfs的底层数据体系。本节采用从最小数据结构到最终组成一个大的模型的思路来介绍。当然,阅读时也可先从Device、Driver、Bus、Class的介绍开始,先总体了解设备模型的构成,然后再回到kobject和kset,弄清它们是如何将Device、Driver、Bus、Class穿插链接在一起的,以及如何将这些映像成文件并最终形成一个sysfs文件系统。

3、sys 文件系统

sysfs是一个基于内存的文件系统,它的作用是将内核信息以文件的方式提供给用户程序使用。

sysfs可以看成与proc,devfs和devpty同类别的文件系统,该文件系统是虚拟的文件系统,可以更方便对系统设备进行管理。它可以产生一个包含所有系统硬件层次视图,与提供进程和状态信息的proc文件系统十分类似。

sysfs把连接在系统上的设备和总线组织成为一个分级的文件,它们可以由用户空间存取,向用户空间导出内核的数据结构以及它们的属性。sysfs的一个目的就是展示设备驱动模型中各组件的层次关系,其顶级目录包括block,bus,drivers,class,power和firmware等.

sysfs提供一种机制,使得可以显式的描述内核对象、对象属性及对象间关系。sysfs有两组接口,一组针对内核,用于将设备映射到文件系统中,另一组针对用户程序,用于读取或操作这些设备。下表描述了内核中的sysfs要素及其在用户空间的表现:

sysfs在内核中的组成要素

在用户空间的显示

内核对象(kobject)

目录

对象属性(attribute)

文件

对象关系(relationship)

链接(Symbolic Link)



sysfs目录结构(block bus class dev devices firmware fs kernel module power):
/sys下的子目录所包含的内容
/sys/devices这是内核对系统中所有设备的分层次表达模型,也是/sys文件系统管理设备的最重要的目录结构;sys文件系统最重要的目录结构,该目录下是全局设备结构体系,包含所有被发现的注册在各种总线上的各种物理设备。一般来说,所有的物理设备都按其在总线上的拓扑结构来显示,但有两个例外,即platform devices和system devices。platform devices一般是挂在芯片内部的高速或者低速总线上的各种控制器和外设,它们能被CPU直接寻;system devices不是外设,而是芯片内部的核心结构,比如CPU,timer等,它们一般没有相关的驱动,但是会有一些体系结构相关的代码来配置它们。

/sys/dev

这个目录下维护一个按字符设备和块设备的主次号码(major:minor)链接到真实的设备(/sys/devices下)的符号链接文件;该目录下有字符设备(block)和块设备(char)两个子目录,里面全是以主次设备号(major:minor)命名的链接文件,链接到/sys/devices。

/sys/bus

这是内核设备按总线类型分层放置的目录结构, devices 中的所有设备都是连接于某种总线之下,在这里的每一种具体总线之下可以找到每一个具体设备的符号链接,它也是构成 Linux 统一设备模型的一部分。按总线类型分类设备,一般来说每个子目录(总线类型)下包含两个子目录,一个是devices,另一个是drivers,其中devices下是这个总线类型下的所有设备,这些设备都是符号链接,它们分别指向真正的设备(/sys/devices/…下);而drivers下是所有注册在这个总线上的驱动,每个driver子目录下 是一些可以观察和修改的driver参数。

/sys/class

这是按照设备功能分类的设备模型,如系统所有输入设备都会出现在/sys/class/input 之下,而不论它们是以何种总线连接到系统,它也是构成 Linux 统一设备模型的一部分;按功能分类设备,该目录下包含所有注册在kernel里面的设备类型,每个设备类型表达具有一种功能的设备。每个设备类型子目录下是具体设备的符号链接,这些链接指向/sys/devices/…下的具体设备。设备类型和设备并没有一一对应的关系,一个物理设备可能具备多种设备类型,一个设备类型只表达具有一种功能的设备,比如:系统所有输入设备都会出现在/sys/class/input之下,而不论它们是以何种总线连接到系统的(/sys/class也是构成linux统一设备模型的一部分)。

/sys/kernel

这里是内核所有可调整参数的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的slab 分配器等几项较新的设计在使用它,其它内核可调整参数仍然位于sysctl(/proc/sys/kernel) 接口中;

/sys/module

这里有系统中所有模块的信息,不论这些模块是以内联(inlined)方式编译到内核映像文件(vmlinuz)中还是编译为外部模块(ko文件),都可能会出现在/sys/module 中:

  • 编译为外部模块(ko文件)在加载后会出现对应的/sys/module/<module_name>/,并且在这个目录下会出现一些属性文件和属性目录来表示此外部模块的一些信息,如版本号、加载状态、所提供的驱动程序等;
  • 编译为内联方式的模块则只在当它有非0属性的模块参数时会出现对应的/sys/module/<module_name>,这些模块的可用参数会出现在/sys/modules/<modname>/parameters/<param_name> 中,
    • 如/sys/module/printk/parameters/time这个可读写参数控制着内联模块printk在打印内核消息时是否加上时间前缀;
    • 所有内联模块的参数也可以由"<module_name>.<param_name>=<value>"的形式写在内核启动参数上,如启动内核时加上参数"printk.time=1"与向"/sys/module/printk/parameters/time"写入1的效果相同;
  • 没有非0属性参数的内联模块不会出现于此。
/sys/power这里是系统中电源选项,这个目录下有几个属性文件可以用于控制整个机器的电源状态,如可以向其中写入控制命令让机器关机、重启等。
/sys/block从linux2.6.26版本开始已经移到了/sys/class/block。代表着系统中当前被发现的所有块设备。按照功能来说防止在/sys/class下会更合适,但由于历史遗留因素而一直存在于/sys/block,但从linux2.6.22内核开始这部分就已经标记为过去时,只有打开了CONFIG_SYSFS_DEPRECATED配置编译才会有这个目录存在,并且其中的内容在从linux2.6.26版本开始已经正式移到了/sys/class/block,旧的接口/sys/block为了向后兼容而保留存在,但其中的内容已经变为了指向它们在/sys/devices/中真实设备的符号链接文件。
/sys/fs该目录用来描述系统中所有的文件系统,包括文件系统本身和按照文件系统分类存放的已挂载点。
/sys/firmware该目录下包含对固件对象(firmware object)和属性进行操作和观察的接口,即这里是系统加载固件机制的对用户空间的接口(关于固件有专用于固件加载的一套API)。


sysfs是一个特殊文件系统,并没有一个实际存放文件的介质。

1)、kobject结构

sysfs的信息来源是kobject层次结构,读一个sysfs文件,就是动态的从kobject结构提取信息,生成文件。重启后里面的信息当然就没了。

sysfs文件系统与kobject结构紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。Kobject 是Linux 2.6引入的新的设备管理机制,在内核中由struct kobject表示。通过这个数据结构使所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux2.6设备模型的核心结构,Kobject是组成设备模型的基本结构。类似于C++中的基类,它嵌入于更大的对象的对象中,用来描述设备模型的组件。如bus,devices, drivers 等。都是通过kobject连接起来了,形成了一个树状结构。这个树状结构就与/sys向对应。

2)、sysfs 如何读写kobject 结构

sysfs就是利用VFS的接口去读写kobject的层次结构,建立起来的文件系统。kobject的层次结构的注册与注销XX_register()形成的。文件系统是个很模糊广泛的概念,linux把所有的资源都看成是文件,让用户通过一个统一的文件系统操作界面,也就是同一组系统调用,对属于不同文件系统的文件进行操作。这样,就可以对用户程序隐藏各种不同文件系统的实现细节,为用户程序提供了一个统一的,抽象的,虚拟的文件系统界面,这就是所谓"VFS(Virtual Filesystem Switch)"。这个抽象出来的接口就是一组函数操作。

要实现一种文件系统就是要实现VFS所定义的一系列接口,file_operations, dentry_operations, inode_operations等,供上层调用。

file_operations是描述对每个具体文件的操作方法(如:读,写);

dentry_operations结构体指明了VFS所有目录的操作方法;

inode_operations提供所有结点的操作方法。

举个例子,C程序中的文件打开:open(“hello.c”, O_RDONLY),它通过系统调用的流程是这样的:
open() -> 系统调用->  sys_open() -> filp_open()-> dentry_open() -> file_operations->open()

不同的文件系统,调用不同的file_operations->open(),在sysfs下就是sysfs_open_file()。我们使用不同的文件系统,就是将它们各自的文件信息都抽象到dentry和inode中去。这样对于高层来说,我们就可以不关心底层的实现,我们使用的都是一系列标准的函数调用。这就是VFS的精髓,实际上就是面向对象。

注意:sysfs是典型的特殊文件。它存储的信息都是由系统动态的生成的,它动态的包含了整个机器的硬件资源情况。从sysfs读写就相当于向kobject层次结构提取数据。


---------------------------------------------------------------------

Documentation/ABI/testing/sysfs-block.txt的中文翻译

如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。中文版翻译维护者(Chinese maintainer):徐红(1534342777@qq.com)。

以下为正文

---------------------------------------------------------------------
sysfs-块
系统文件——块
--------------------
What:/sys/block/<disk>/stat
Date:February 2008
Contact:Jerome Marchand <jmarchan@redhat.com>
Description:The /sys/block/<disk>/stat files displays the I/O statistics of disk <disk>. They contain 11 fields:
1 - reads completed successfully
2 - reads merged
3 - sectors read
4 - time spent reading (ms)
5 - writes completed
6 - writes merged
7 - sectors written
8 - time spent writing (ms)
9 - I/Os currently in progress
10 - time spent doing I/Os (ms)
11 - weighted time spent doing I/Os (ms)

For more details refer Documentation/iostats.txt

目录:/sys/block/<disk>/stat
日期:2008年2月
联系方式:Jerome Marchand <jmarchan@redhat.com>
摘要:/sys/block/<disk>/stat文件显示了磁盘I/O数据。它们包含了11个区域。
1.完全成功读取
2.混合读取
3.扇区读取
4.读取时间(ms)
5.完全写入
6.混合写入
7.扇区的写入
8.写入时间(ms)
9.当前进度中的I/O设备
10.I/O工作的时间(ms)
11.I/O工作的加权时间(ms)

更多的细节在Documentation/iostats.txt文档中。

What:/sys/block/<disk>/<part>/stat
Date:February 2008
Contact:Jerome Marchand <jmarchan@redhat.com>
Description:The /sys/block/<disk>/<part>/stat files display the I/O statistics of partition <part>. The format is the same as the above-written /sys/block/<disk>/stat format.

目录:/sys/block/<disk>/<part>/stat
日期:2008年2月
联系方式:Jerome Marchand <jmarchan@redhat.com>
摘要:/sys/block/<disk>/<part>/stat文件显示了分区的I/O数据。格式和上面/sys/block/<disk>/stat的格式一样。

What:/sys/block/<disk>/integrity/format
Date:June 2008
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Metadata format for integrity capable block device.
E.g. T10-DIF-TYPE1-CRC.

目录:/sys/block/<disk>/integrity/format
日期:2008年6月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:块设备完整性的元数据格式。
E.g. T10-DIF-TYPE1-CRC.

What:/sys/block/<disk>/integrity/read_verify
Date:June 2008
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Indicates whether the block layer should verify the integrity of read requests serviced by devices that support sending integrity metadata.

目录:/sys/block/<disk>/integrity/read_verify
日期:2008年6月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:表明块层是否应该通过支持发送完整元数据的设备来验证读请求服务的完整性。

What:/sys/block/<disk>/integrity/tag_size
Date:June 2008
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Number of bytes of integrity tag space available per 512 bytes of data.

目录:/sys/block/<disk>/integrity/tag_size
日期:2008年6月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:每512字节数据完整标签可用空间的字节数。

What:/sys/block/<disk>/integrity/write_generate
Date:June 2008
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Indicates whether the block layer should automatically generate checksums for write requests bound for devices that support receiving integrity metadata.

目录:/sys/block/<disk>/integrity/write_generate
日期:2008年6月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:表明块层是否应该为支持接收完整数据元的写请求约束设备自动生成校验。

What:/sys/block/<disk>/alignment_offset
Date:April 2009
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Storage devices may report a physical block size that is bigger than the logical block size (for instance a drive with 4KB physical sectors exposing 512-byte logical blocks to the operating system).  This parameter indicates how many bytes the beginning of the device is offset from the disk's natural alignment.

目录:/sys/block/<disk>/alignment_offset
日期:2009年4月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:存储设备可能会记录一个比逻辑块大小更大的物理块的大小(例如一个4KB物理扇区的驱动呈现给操作系统的是512B的逻辑块)。这个参数表示设备的开头离磁盘的自然对齐有多少字节的偏移。

What:/sys/block/<disk>/<partition>/alignment_offset
Date:April 2009
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Storage devices may report a physical block size that is bigger than the logical block size (for instance a drive with 4KB physical sectors exposing 512-byte logical blocks to the operating system).  This parameter indicates how many bytes the beginning of the partition is offset from the disk's natural alignment.

目录:/sys/block/<disk>/<partition>/alignment_offset
日期:2009年4月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:存储设备可能会记录一个比逻辑块大小更大的物理块的大小(例如一个4KB物理扇区的驱动呈现给操作系统的是512B的逻辑块)。这个参数表示分区的开头离磁盘的自然对齐有多少字节的偏移。

What:/sys/block/<disk>/queue/logical_block_size
Date:May 2009
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:This is the smallest unit the storage device can address. It is typically 512 bytes.

目录:/sys/block/<disk>/queue/logical_block_size
日期:2009年5月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:这是存储设备最小的可编址单元,通常为512字节。

What:/sys/block/<disk>/queue/physical_block_size
Date:May 2009
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:This is the smallest unit a physical storage device can write atomically.  It is usually the same as the logical block size but may be bigger.  One example is SATA drives with 4KB sectors that expose a 512-byte logical block size to the operating system.  For stacked block devices the physical_block_size variable contains the maximum physical_block_size of the component devices.

目录:/sys/block/<disk>/queue/physical_block_size
日期:2009年5月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:这是一个物理存储设备可自动写入的最小单元,通常和逻辑块大小一样,也可能大一点。比如,4KB扇区的SATA驱动呈现给操作系统一个512B的物理块大小。对于堆块设备,物理块大小的变量包含了组件设备的最大物理块的大小。

What:/sys/block/<disk>/queue/minimum_io_size
Date:April 2009
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Storage devices may report a granularity or preferred minimum I/O size which is the smallest request the device can perform without incurring a performance penalty.  For disk drives this is often the physical block size. For RAID arrays it is often the stripe chunk size. A properly aligned multiple of minimum_io_size is the preferred request size for workloads where a high number of I/O operations is desired.

目录:/sys/block/<disk>/queue/minimum_io_size
日期:2009年4月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:存储设备可能会记录一个粒度或优先级最小的I/O的大小,这是在不导致性能降低的前提下,可执行设备的最小要求。对于磁盘设备,这通常是物理块大小。对于RAID阵列,这通常是条纹快大小。恰当的最小输入输出大小的多重对齐是需要大量I/O操作的工作负载的首选请求。

What:/sys/block/<disk>/queue/optimal_io_size
Date:April 2009
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Storage devices may report an optimal I/O size, which is the device's preferred unit for sustained I/O. This is rarely reported for disk drives.  For RAID arrays it is usually the stripe width or the internal track size. A properly aligned multiple of optimal_io_size is the preferred request size for workloads where sustained throughput is desired.  If no optimal I/O size is reported this file contains 0.

目录:/sys/block/<disk>/queue/optimal_io_size
日期:2009年4月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:存储设备可能会记录一个最优I/O大小,这是持续的I/O首选单元。这很少为磁盘驱动记录。对于RAID阵列,这通常是条纹宽度或是内部跟踪大小。恰当的最优输入输出大小的多重对齐是需要持续吞吐量的工作负载的首选请求大小。如果没有记录最优I/O大小,这个文件置为0。

What:/sys/block/<disk>/queue/nomerges
Date:January 2010
Contact:
Description:Standard I/O elevator operations include attempts to merge contiguous I/Os. For known random I/O loads these attempts will always fail and result in extra cycles being spent in the kernel. This allows one to turn off this behavior on one of two ways: When set to 1, complex merge checks are disabled, but the simple one-shot merges with the previous I/O request are enabled. When set to 2,all merge tries are disabled. The default value is 0 which enables all types of merge tries.

目录:/sys/block/<disk>/queue/nomerges
日期:2010年1月
联系方式:
摘要:标准的I/O电梯运行包括尝试合并相邻I/O。对于已知的随机I/O负载,这些尝试通常会失败,并导致额外的周期用于内核。阻止这种行为的两种方式之一:当置为1时,复杂的合并检查被禁用,但是和前面的I/O请求的简单一次性合并被启用。当置为2时,所有的尝试合并都是被禁用的。合并默认值是0——所有类型的尝试合并都被启用。

What:/sys/block/<disk>/discard_alignment
Date:May 2011
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Devices that support discard functionality may internally allocate space in units that are bigger than the exported logical block size. The discard_alignment parameter indicates how many bytes the beginning of the device is offset from the internal allocation unit's natural alignment.

目录:/sys/block/<disk>/discard_alignment
日期:2011年5月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:支持丢弃功能的设备可能在比导出的逻辑块大的单元内部分配空间。丢弃对齐参数表明设备的开头离内部分配单元的自然对齐的偏移量有多少字节。

What:/sys/block/<disk>/<partition>/discard_alignment
Date:May 2011
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Devices that support discard functionality may internally allocate space in units that are bigger than the exported logical block size. The discard_alignment parameter indicates how many bytes the beginning of the partition is offset from the internal allocation unit's natural alignment.

目录:/sys/block/<disk>/<partition>/discard_alignment
日期:2011年5月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:支持丢弃功能的设备可能在比导出的逻辑块大的单元内部分配空间。丢弃对齐参数表明分区的开头离内部分配单元的自然对齐的偏移量有多少字节。

What:/sys/block/<disk>/queue/discard_granularity
Date:May 2011
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Devices that support discard functionality may internally allocate space using units that are bigger than the logical block size. The discard_granularity parameter indicates the size of the internal allocation unit in bytes if reported by the device. Otherwise the discard_granularity will be set to match the device's physical block size. A discard_granularity of 0 means that the device does not support discard functionality.

目录:/sys/block/<disk>/queue/discard_granularity
日期:2011年5月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:支持丢弃功能的设备可能用比逻辑块大的单元在内部分配空间。如果被设备记录,丢弃粒度参数表明内部分配单元以比特位单位的大小。否则,丢弃粒度将会被设置成匹配设备物理块大小的值。丢弃粒度为0表明设备不支持丢弃功能。

What:/sys/block/<disk>/queue/discard_max_bytes
Date:May 2011
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Devices that support discard functionality may have internal limits on the number of bytes that can be trimmed or unmapped in a single operation. Some storage protocols also have inherent limits on the number of blocks that can be described in a single command. The discard_max_bytes parameter is set by the device driver to the maximum number of bytes that can be discarded in a single operation. Discard requests issued to the device must not exceed this limit. A discard_max_bytes value of 0 means that the device does not support discard functionality.

目录:/sys/block/<disk>/queue/discard_max_bytes
日期:2011年5月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:支持丢弃功能的设备可能在单一操作上能够削减或映射的字节数有内部限制。一些存储协议对于单一命令中能被描述的块的数量也有固定的限制。丢弃最大字节参数被驱动设备设置成在单一操作中能够被丢弃的字节的最大数量。设备发出的丢弃请求不能超过这个限制。丢弃最大字节值为0表明该设备不支持丢弃功能。

What:/sys/block/<disk>/queue/discard_zeroes_data
Date:May 2011
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Devices that support discard functionality may return stale or random data when a previously discarded block is read back. This can cause problems if the filesystem expects discarded blocks to be explicitly cleared. If a device reports that it deterministically returns zeroes when a discarded area is read the discard_zeroes_data parameter will be set to one. Otherwise it will be 0 and the result of reading a discarded area is undefined.

目录:/sys/block/<disk>/queue/discard_zeroes_data
日期:2011年5月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:支持丢弃功能的设备当之前丢弃的块被读回时,可能返回过期或随机数据。如果文件系统想要显式地丢弃块这样可能会导致问题发生。如果设备报告当丢弃区域被读设备肯定返回0,丢弃零数据参数将被置1。否则将被置为0,并且读丢弃区域的结果是未定义的。

What:/sys/block/<disk>/queue/write_same_max_bytes
Date:January 2012
Contact:Martin K. Petersen <martin.petersen@oracle.com>
Description:Some devices support a write same operation in which a single data block can be written to a range of several contiguous blocks on storage. This can be used to wipe areas on disk or to initialize drives in a RAID configuration. write_same_max_bytes indicates how many bytes can be written in a single write same command. If write_same_max_bytes is 0, write same is not supported by the device.

目录:/sys/block/<disk>/queue/write_same_max_bytes
日期: 2012年1月
联系方式:Martin K. Petersen <martin.petersen@oracle.com>
摘要:一些设备在单个数据块可以被写到几个相邻的数据块中的存储器中支持写相同操作。这个可以用来擦除磁盘区域,还可以在RAID配置中初始化驱动器。写相同最大字节表明在一次写相同命令中有多少字节可以被写入。如果写相同最大字节为0,则说明设备不支持写相同。

目录:/proc/diskstats
日期:February 2008
摘要:The /proc/diskstats file displays the I/O statistics of block devices. Each line contains the following 14 fields:
1  major number
2  minor mumber
3  device name
4  reads completed successfully
5  reads merged
6  sectors read
7  time spent reading (ms)
8  writes completed
9  writes merged
10  sectors written
11  time spent writing (ms)
12  I/Os currently in progress
13  time spent doing I/Os (ms)
14  weighted time spent doing I/Os (ms)
==  ===================================
Kernel 4.18+ appends four more fields for discard tracking putting the total at 18:
15  discards completed successfully
16  discards merged
17  sectors discarded
18  time spent discarding
==  ===================================
Kernel 5.5+ appends two more fields for flush requests:
19  flush requests completed successfully
20  time spent flushing


本文部分参考自互联网,感谢原作者及译者。