• 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
    ", (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
    ", 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

  • 相关阅读:
    Java使用Apache Commons Exec运行本地命令行命令
    Win10安装PostgreSQL9.6
    软件工程学习笔记——软件工具
    软件工程学习笔记——软件过程模型
    软件工程学习笔记——软件过程
    软件工程学习笔记——软件生存周期
    软件工程学习笔记——软件工程基本原理
    MySQL学习笔记——MySQL5.7的启动过程(一)
    Windows下免费的屏幕录制软件——EV录屏——推荐
    SecureCRT 8.1破解方式
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/9610993.html
Copyright © 2020-2023  润新知