Documentation/filesystems/sysfs.txt 文档翻译--sysfs

sysfs - 用于导出内核对象的文件系统。

1.sysfs是一个基于ram的文件系统,最初基于ramfs。 它提供了一种方法,可以将内核数据结构,它们的属性以及它们之间的链接导出到用户空间。
sysfs本质上与kobject基础结构相关联。有关kobject接口的更多信息,请阅读Documentation/kobject.txt

2.使用sysfs
如果定义了CONFIG_SYSFS,则始终编译sysfs。 你可以通过这样做进行访问:mount -t sysfs sysfs /sys

3.sysfs中目录的创建
对于在系统中注册的每个kobject,都会在sysfs中为其创建一个目录。 该目录创建为kobject父项的子目录,表示内部对象层次结构到用户
空间。 sysfs中的顶级目录代表对象层次结构的共同祖先; 即对象所属的子系统。
Sysfs在内部存储指向kobject的指针,该kobject实现与该目录关联的kernfs_node对象中的目录。 在过去,只要文件被打开或关闭,sysfs
就会使用这个kobject指针直接在kobject上进行引用计数。 使用当前的sysfs实现,kobject引用计数仅由函数sysfs_schedule_callback()
直接修改。

4.属性
可以在文件系统中以常规文件的形式为kobjects导出属性。 Sysfs将文件I/O操作转换为属性定义的方法,从而提供读取和写入内核属性的方法。
属性应该是ASCII文本文件,最好每个文件只有一个值。 注意,每个文件仅包含一个值可能效率不高,因此表达相同类型数组也是可接受的。
混合类型,表达多行数据以及进行数据格式化是非常不受欢迎的。 做这些事情可能会让你公开羞辱,你的代码会被重写,恕不另行通知。

属性定义很简单:

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);

bare属性不包含读取或写入属性值的方法。 鼓励子系统定义自己的属性结构和包装函数,以便为特定对象类型添加和删除属性。

例如,驱动程序模型定义struct 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 *);

它还定义了这个帮助函数来定义设备属性:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _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,
};

5.子系统特定的回调
当子系统定义新的属性类型时,它必须实现一组sysfs操作,以便将读取和写入调用转发到属性所有者的show()和store()方法。

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

[子系统应该已经为此类型定义了一个struct kobj_type描述符,这是存储sysfs_ops指针的位置。 有关更多信息,请参阅kobject文档。]

读取或写入文件时,sysfs会调用该类型的相应方法。 然后,该方法将通用struct kobject和struct attribute 指针转换为适当的指针类型,
并调用相关联的函数方法。

作为插图:

#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;
}

6.读/写属性数据
要读取或写入属性,必须在声明属性时指定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,他们应该只将一个object,一个attribute和一个buffer 作为参数。

sysfs分配一个大小为(PAGE_SIZE)的缓冲区并将其传递给该方法。 Sysfs将为每次读取或写入调用该方法一次。 这会在方法实现上强制执
行以下行为:

- 在read(2)中,show()方法应该填满整个缓冲区。 回想一下,一个属性应该只导出一个值,或者一个类似值的数组,所以应该不会有那
么大的开销。
这允许用户空间随意对整个文件进行部分读取和forward seeks。 如果用户空间seeks back到0或者使用偏移量为“0”的pread(2),将再次
调用show()方法,重新启动以填充缓冲区。

- 在write(2)时,sysfs期望在第一次写入期间传递整个缓冲区。 然后,Sysfs将整个缓冲区传递给store()方法。 在数据传到store()之后
应添加终止NULL。 这使得sysfs_streq()等函数可以安全使用。
在写sysfs文件时,用户空间进程应首先读取整个文件,修改它希望更改的值,然后再写回整个缓冲区。
在读取和写入值时,属性方法实现应在相同的缓冲区上运行。

7.其他说明:
- 无论当前文件位置如何,写入都会使show()方法重置。这个普通的文件偏移方法不同!!
- 缓冲区的长度始终为PAGE_SIZE个字节。 在i386上,这是4096。
- show()方法应该返回打印到缓冲区中的字节数。 这是scnprintf()的返回值。
- 格式化要返回给用户空间的值时,show()不得使用snprintf()。 如果你能保证永远不会发生溢出,你可以使用sprintf(),否则你必须使用scnprintf()
- store()应返回缓冲区使用的字节数。 如果已使用整个缓冲区,则只返回count参数。
- show()或store()总是可以返回错误。 如果出现错误值,请务必返回错误。

- 传递给方法的object将通过引用计数其嵌入对象的sysfs固定在内存中。但是,对象所代表的物理实体(例如设备)可能不存在。 如有必要,请务必检查此方法。

8.设备属性的一个非常简单(和天真)的实现是:

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);


(请注意,实际实现不允许用户空间设置设备的名称。)

9.上层目录结构
sysfs目录暴露了内核数据结构的关系。顶级sysfs目录如下所示:
block/ bus/ class/ dev/ devices/ firmware/ net/ fs/

devices/ 包含设备树的文件系统表示。它直接映射到内部内核设备树,这是struct device的层次结构。
bus/ 包含内核中各种总线类型的目录布局。每个总线的目录包含两个子目录:
       devices/
       drivers/
devices/ 包含系统中发现的每个设备的符号链接,指向root/ 下的设备目录。
drivers/ 包含为该特定总线上的设备加载的每个设备驱动程序的目录(假设驱动程序不跨越多种总线类型)。
fs/ 包含某些文件系统的目录。目前,每个想要导出属性的文件系统必须在fs/ 下创建自己的层次结构(例如,参见./fuse.txt)。
dev/ 包含两个目录char/ 和block/。在这两个目录中有一些名为<major>:<minor>的符号链接。这些符号链接指向给定设备的sysfs目录。 /sys/dev 提供了一种从stat(2)操作的结果中查找设备的sysfs接口的快速方法。

更多信息可以在Documentation/driver-model/中找到驱动程序模型特定功能。

10.目前的接口
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);
};
声明:
DEVICE_ATTR(_name, _mode, _show, _store);
创建/移除:
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);
};
声明:
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, size_t count);
};
声明:
DRIVER_ATTR_RO(_name)
DRIVER_ATTR_RW(_name)
创建/移除:
int driver_create_file(struct device_driver *, const struct driver_attribute *);
void driver_remove_file(struct device_driver *, const struct driver_attribute *);

 

11.文档
sysfs目录结构和每个目录中的属性定义了内核和用户空间之间的ABI。至于任何ABI,重要的是这个ABI是稳定的并且有适当的记录。 必须在
Documentation/ABI中记录所有新的sysfs属性。 有关更多信息,另请参见Documentation/ABI/README

 

12. struct my_attribute val_attribute = __ATTR(val, 0666, val_show, val_store);

报错:“error: negative width in bit-field”,是__ATTR宏的权限问题,将上述的0666改为0664即可修复。
参考:https://blog.csdn.net/Q1302182594/article/details/53558192

 

posted on 2018-09-08 23:10  Hello-World3  阅读(384)  评论(0编辑  收藏  举报

导航