sysfs文件系统之 Attribute

Attributes
属性

对于系统注册的每个kobject,都会在sysfs文件系统中创建一个对应的目录.
attributes以普通文件的形式为kobject导出属性到sysfs文件系统.
attribute 的结构体定义如下:

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

单独的attribute不包含读写属性值的方法.subsystem鼓励定义attribute自己的结构体和读写函数用来为kobject添加或删除属性.比如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,
	},
};

Subsystem相关的回调函数

subsystem定义新的attribute类型时,它必须定义自己的一组读写函数来调用.

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

[subsystem应该先定义一个kobj_type结构体,里面保存了sysfs_ops 指针]

读写文件的时候,sysfs调用相应的函数.这些函数转换kobject和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;
}

sysfs文件读写的调用流程

读写attribute数据

为了读写attribute数据,在定义attribute结构体的时候,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,attribute,buffer参数.
sysfs分配了一个大小为PAGE_SIZE的buffer并把它作为参数传给这些函数.sysfs每次读写的时候都会调用这些函数.这需要在这些函数里实现以下功能:

-读,show()函数应该填充整个buffer
回忆一下attribute应该导出一个值或为了高效导出一组类似的值.
这样方便用户空间可以部分读或随意搜索整个文件.如果用户空间搜索
到0或调用pread在偏移地址为0的位置,show()函数会被再次调用重新填充buffer.

-写,sysfs希望在首次写调用的时候传送完整的buffer.sysfs然后传送完整的buffer到store()函数.
在写sysfs文件时,用户空间程序应该先读取整个文件,修改,然后再写入完整的buffer.

attribute函数在读写的时候应该使用同一个buffer.

其它注意事项:

-写操作会调用show()函数重新载入,无论当前的文件位置在哪里

-buffer始终是PAGE_SIZE 字节.i386,这个值是4096.

-show()函数会返回输出到buffer的字节数.也就是scnprintf()函数的返回值

-show()必须使用scnprintf().

-store()返回buffer使用的字节数.如果整个buffer都被占用了,则返回count值

-show()或store()应该返回error.如果错的值出现,确保返回error.

-函数的参数object一直在内存通过内嵌的kobject sysfs的引用计数器.然而,
object表示的物理结构可能没有提供.如果必要确保有方式检测它.
(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. )

非常简单的device attribute实现如下:

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

(注意:实际的函数中不允许用户空间设置device的名字)

猜你喜欢

转载自blog.csdn.net/qq_36412526/article/details/84227465
今日推荐