分类: 嵌入式
2012-07-27 14:53:49
Linux2.6内核引入了sysfs 文件系统。sysfs 被看成是与proc同类别的文件系统。sysfs 把连接在系统上的设备和总线组织成分级的文件,使其从用户空间可以访问到。
sysfs的挂载过程,她是这样被挂载的。mount -t sysfs sysfs /sys Sysfs 被加载在/sys/ 目录下,它的子目录包括:
? Block:在系统中发现的每个块设备在该目录下对应一个子目录。每个子目录中又包含一些属性文件,它们描述了这个块设备的各方面属性,如:设备大小。(loop块设备是使用文件来模拟的)
? Bus:在内核中注册的每条总线在该目录下对应一个子目录, 如:ide pci scsi usb pcmcia其中每个总线目录内又包含两个子目录:devices 和drivers , devices目录包含了在整个系统中发现的属于该总线类型的设备,drivers目录包含了注册到该总线的所有驱动。
? Class:将设备按照功能进行的分类,如/sys/class/net目录下包含了所有网络接口。
? Devices:包含系统所有的设备。
? Kernel:内核中的配置参数
? Module:系统中所有模块的信息
? Firmware:系统中的固件
? Fs: 描述系统中的文件系统
? Power:系统中电源选项
sysfs是一个特殊文件系统,并没有一个实际存放文件的介质。断电后就没有了。简而言之,sysfs的信息来源是kobject层次结构,读一个sysfs文件,就是动态的从kobject结构提取信息,生成文件。
所以,首先,我要先讲一讲sysfs文件系统的信息来源 -- kobject层次结构。kobject层次结构就是linux的设备模型。
sysfs 的内核文档\Documentation\filesystems\sysfs.txt 翻译如下:
sysfs - 用于导出内核对象(kobject)的文件系统
简介:
~~~~~~~~~~~
sysfs 是一个最初基于ramfs的位于内存的文件系统。它提供一些方法以导出内核的数据结构、他们的属性和他们与用户空间的连接。sysfs 始终与kobject的底层结构紧密相关。请阅读Documentation/kobject.txt 文档以获得更多关于 kobject 接口的信息。
使用
~~~~~~~~~~~
sysfs 通常被编译进内核。你可以通过使用以下命令访问它:
mount -t sysfs sysfs /sys
(此命令含义是挂载 sysfs 到根目录下的sys目录)
创建目录
~~~~~~~~~~~~~~~~~~
一旦有 kobject 在系统中注册,就会有一个目录在sysfs中被创建。 这个目录是作为 kobject 的 parent 下的子目录创建的,以准确的传递内核的对象层次到用户空间。 sysfs中的顶层目录代表着内核对象层次的共同祖先;例如:某些对象属于某个子系统。 Sysfs内部存储着 kobject ,这些 kobject 在 d_fsdata 指针(在 kobject的dentry结构体中)中拥有目录。 这使得 sysfs 可以在文件打开和关闭时,直接在 kobject 上实现引用计数。
属性
~~~~~~~~~~
kobject 的属性能在文件系统中以普通文件的形式导出。Sysfs 为属性定义了面向文件 I/O 操作的方法,以提供对内核属性的读写。属性应为 ASCII 码文本文件,以一个文件只存储一个属性值为宜。但一个文件只包含一个属性值可能影响效率, 所以一个包含相同数据类型的属性值数组也是被广泛接受的。混合类型、表达多行数据以及一些怪异的数据格式是会遭强烈反对。这样做是很丢脸的,而且你的代码会在未通知你的情况下被重写。
一个简单的属性结构定义如下:(到2.6.22.2已添加了struct module * owner;)
struct attribute {
char * name;
mode_t mode;
};
int sysfs_create_file(struct kobject * kobj, struct attribute * attr);
void sysfs_remove_file(struct kobject * kobj, struct attribute * attr);
一个裸的属性并不包含读写其属性值的方法。
最好为子系统定义自己的属性和为了增删特殊对象类型的属性而包装过的函数。例如:驱动程序模型定义的device_attribute 结构体如下:
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device * dev, char * buf);
ssize_t (*store)(struct device * dev, const char * buf);
};
int device_create_file(struct device *, struct device_attribute *);
void device_remove_file(struct device *, struct device_attribute *);
它为了定义设备的属性也定义了辅助的宏:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = { \
.attr = {.name = stringify(_name) , .mode = _mode }, \
.show = _show, \
.store = _store, \
};
例如:声明static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
等同于这样的代码
static struct device_attribute dev_attr_foo = {
.attr = {
.name = "foo",
.mode = S_IWUSR | S_IRUGO,
},
.show = show_foo,
.store = store_foo,
};
子系统特有的调用
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
当一个子系统定义一个新属性类型时,一系列的sysfs操作必须被执行,以帮助读写函数实现属性所有者的显示和储存的方法。
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *);
};
[子系统应已经定义了一个kobj_type 结构体作为这个类型的描述符,存储 sysfs_ops 的指针。更多的信息参见 kobject 的文档]
当一个文件被读写时, sysfs 会为这个类型调用适当的方法。这个方法会将一般的 kobject 和 attribute 结构体指针 转换为适当的指针类型后调用相关联的函数。
示例:
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
#define to_dev(d) container_of(d, struct device, kobj)
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 = 0;
if (dev_attr->show)
ret = dev_attr->show(dev, buf);
return ret;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
读写属性数据
在声明属性时,show() 或 store() 方法必须被指明,以实现属性的读或写。这些方法的类型应该和以下的设备属性的定义一样简单。
ssize_t (*show)(struct device * dev, char * buf);
ssize_t (*store)(struct device * dev, const char * buf);
也就是说,他们应该只以一个处理对象和一个缓冲指针作为参数。sysfs 会分配一个缓冲区的大小(PAGE_SIZE)并传递给这个方法。Sysfs 将会为每次读写操作调用一次这个方法。这导致了这些方法的执行会出现以下的行为: implementations:
-在读方面,show() 方法应该填充整个缓冲区。回想起属性应只导出了一个属性值或是一个同类型的属性值的数组, 所以这个代价将不会不太高。这使得用户空间可以局部地读和任意的搜索整个文件。
-在些方面,sysfs 希望在第一次写操作时得到整个缓冲区。之后 Sysfs 传递整个缓冲区给 store()方法。
当要写 sysfs 文件时,用户空间进程应该首先读整个文件,修该想要改变的值,然后回写整个缓冲区。在读写属性值时,属性方法的执行应操作相同的缓冲区。
注记:
- 缓冲区应总是 PAGE_SIZE 大小。对于i386,这个值为4096。
- show() 方法应该返回写入缓冲区的字节数,也就是 snprintf()的返回值。
- show() 应始终使用 snprintf()。
- store() 应返回缓冲区的已用字节数,可使用 strlen()。
- show() 或 store() 可以返回错误值。当得到一个非法值,必须返回一个错误值。
- 一个传递给方法的对象将会通过 sysfs 调用对象内嵌的引用计数固定在内存中。尽管如此,对象代表的物
理实体(如设备)可能已不存在。如有必要,应该实现一个检测机制。一个简单的(未经实验证实的)设备属性例程如下:
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", dev->name);
}
static ssize_t store_name(struct device * dev, const char * buf)
{
sscanf(buf, "%20s", dev->name);
return strnlen(buf, PAGE_SIZE);
}
static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
(注意:真实的程序不允许用户空间设置设备名。)
~~~~~~~~~~~~~~~~~~~~~~~~~~
顶层目录
sysfs 目录的安排显示了内核数据结构之间的关系。
:顶层 sysfs 目录如下:
block/
bus/
class/
devices/
firmware/
net/
fs/
devices/ 包含了一个设备树的文件系统表示。 他直接以内核设备树的形式反映了设备的层次结构。
bus/ 包含了各种内核总线类型的固定目录布局。每个总线目录包含两个子目录:
devices/
drivers/
devices/ 包含了每个系统中出现的设备 指向 设备目录/dev 的动态链接。
drivers/ 包含了一个每个已为特定总线上的设备而挂载的驱动程序的目录(这里假定驱动没有多个总线类型)。
fs/ 包含了一个为文件系统设立的目录。 现在每个想要导出属性的文件系统必须在 fs/ 下创建自己的层次结构
below fs/ (可参见./fuse.txt 作为参考)。
更多有关driver-model 的特性信息可以在Documentation/driver-model/.
Documentation/driver-model/中找到。
~~~~~~~~~~~~~~~~~~
当前接口
以下的接口层普遍出现在sysfs中:
- devices (include/linux/device.h)
- 设备
----------------------------------
结构体:
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device * dev, char * buf);
ssize_t (*store)(struct device * dev, const char * buf);
};
声明:
DEVICE_ATTR(_name, _str, _mode, _show, _store);
增/删属性:
int device_create_file(struct device *device, struct device_attribute * attr);
void device_remove_file(struct device * dev, struct device_attribute * attr);
- bus drivers (include/linux/device.h)
- 总线驱动程序
--------------------------------------
结构体:
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char * buf);
};
Declaring:声明:
BUS_ATTR(_name, _mode, _show, _store)
增/删属性:
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);
};
Declaring:
声明:
DRIVER_ATTR(_name, _mode, _show, _store)
增/删属性
int driver_create_file(struct device_driver *, struct driver_attribute *);
void driver_remove_file(struct device_driver *, struct driver_attribute *);