Documentation/filesystems/sysfs.txt译文

为什么翻译此文?

网络上关于sysfs的这篇译文有很多,为什么还要多此一举呢?
一来是觉得阅读原版的文档更加有助于理解,二来计划两个月后参加托业考试。英语已经放下好几年了,想要尽快的拾起来。

sysfs是什么:

sysfs是一个基于ram的文件系统,最早是基于ramfs的。sysfs提供了一种将内核数据结构、属性和他们之间的联系导出到用户空间的方法。
sysfs与kobject基础结构有着紧密的联系。想要获取更多有关kobjec接口的详细信息,请阅读Documentation/kobject.txt。

使用sysfs

通过定义CONFIG_SYSFS的宏,将sysfs编译进内核。你可以这样来访问它:
mount -t sysfs sysfs /sys

创建目录

对于系统中注册的每一个kobject,sysfs中都会创建一个相应的目录。这个目录是作为kboject's parent的子目录,向用户空间描述object层次的。
sysfs中的顶层目录表示object层次的共同祖先,即objects所属的子系统。
sysfs内部存有一个指向kobject的指针,(Sysfs internally stores a pointer to the kobject that implements adirectory in the sysfs_dirent object associated with the directory.)

过去,当文件开/关时,sysfs使用这个kobject指针来做对kobject的引用计数。现在,使用函数sysfs_schedule_callback()来修改kobject的引用计数。

属性(Attributes)

在文件系统中,将kobjects的属性导出为普通文件。sysfs将文件操作提升为属性规则,以此来读写内核属性。

属性必须是ASCII文本文件,最好每个文件只有一个值。每个文件只有一个值可能效率不高,所以现实中通常将同一类行的一组数据放在一个文件中。

不同类型,表示多行数据,奇怪的数据形式等做法都是不合适的。一旦这么做了,那么会被人鄙视,并且代码会被人重写。

定义一个属性是很简单的:

struct attribute {
        char                    * name;
        struct module           *owner;
        mode_t                  mode;
};
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
仅仅一个属性不包含读写属性值的方法。子系统定义自己的属性结构,并且封装函数来对特定的object类型增加和删除属性。

举个例子,驱动类型这样定义device属性:

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 *);
同时,定义了下面helper来定义设备属性:
#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,
        },
};

子系统特定的回调(Subsystem-Specific Callbacks)

当一个子系统定义一种属性类型,则它必须定义一组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);
};
[子系统必须已经定义了用来描述设备类型的结构体kobj_type,并用来存sysfs_ops的指针。]

当读/写文件时,sysfs调用该类型对应的函数(method)。该函数将通用的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;
}

读/写属性数据

为了读/写属性值,在声明属性时,需要指定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);
也就是说,函数应该只有三个参数:一个object,一个属性和一个buf。

sysfs分配一个page的buf,然后将它作为参数传递给函数。当有读/写操作时,sysfs会调用相应的show/store函数。这就造就了如下的读写规则:

- 读时,show()会写整个buf。回想之前所说的:一个属性只映射一个值或一个简单的数组值,所以这样的开销不大。

允许用户空间根据需要,读文件的任意部分内容。如果用户空间从头开始或者pread时offset为0,show()将再次被调用,重新填充buffer。

- 写时,sysfs期待第一次写时将整个buffer传进来。sysfs之后将整个buf传给store()函数。

写sysfs文件时,用户空间程序应该读整个文件,修改需要修改的值,然后写全部buffer。

属性函数操作时,读写时应该操作一个相同的buffer。

其他注意事项:

- 写操作会造成show()函数重建而忽略当前的文件位置。

- buffer大小总是PAGE_SIZE的byte大小。

- sysfs通过引用计算(referencing counting)其嵌入的object将show()和store()与内存相关联。

一个简单的设定设备属性的方法如下:

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);
注意:实际的设定方法不允许用户空间设定设备名。

顶级目录布局(Top Level Directory Layout)

sysfs的目录排列表明了内核数据结构的关系。顶级sysfs目录如下所示:

block/
bus/
class/
dev/
devices/
firmware/
net/
fs/
device/ 包含设备树的文件系统形式。它直接映射struct device层次的内核设备树。

bus/ 包含内核中的各种总线类型的平的目录布局(flat directory layout)。每个bus目录包含两个子目录:

 devices/
 drivers/
    devices/ 包含系统中发现的指向root/目录下各设备目录的符号链接。
    drivers/  每个在特定bus上为设备加载的设备驱动对应一个目录。

fs/ 包含一个各个文件系统的目录。当前,每个文件系统想要export属性,必须在fs/下创建一个自己的等级。

dev/ 包含char/和block/两个目录。这两个目录下都是以<major>:<minor>方式命名的符号链接。这些符号链接指向特定的sysfs目录。/sys/dev提供一种快速查询通过stat操作得到的设备接口。

当前的接口(Current Interfaces)

当前的sysfs中有如下的interface 层:

- 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(_name, _mode, _show, _store)

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)

sysfs目录结构和每个目录下的属性定义了内核与用户空间的一个ABI。对于所有ABI来说,ABI的稳定性与合适的文档化是很重要的。任何新的sysfs属性都必须记录在Documentation/ABI中。可以通过读Documentation/ABI/README来获取更多信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值