Linux内核文档翻译——sysfs.txt
sysfs - _The_ filesystem for exporting kernel objects.
sysfs – 用于导出内核对象(kobject)的文件系统
Patrick Mochel <mochel@osdl.org>
Mike Murphy <mamurph@cs.clemson.edu>
Revised: 16 August 2011 Original: 10 January 2003
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。