sysfs是用于表现设备驱动模型的文件系统,它基于ramfs。要学习linux的设备驱动模型,就要先做好底层工作,总结sysfs提供给外界的API就是其中之一。sysfs文件系统中提供了四类文件的创建与管理,分别是目录、普通文件、软链接文件、二进制文件。目录层次往往代表着设备驱动模型的结构,软链接文件则代表着不同部分间的关系。比如某个设备的目录只出现在/sys/devices下,其它地方涉及到它时只好用软链接文件链接过去,保持了设备唯一的实例。而普通文件和二进制文件往往代表了设备的属性,读写这些文件需要调用相应的属性读写。
sysfs是表现设备驱动模型的文件系统,它的目录层次实际反映的是对象的层次。为了配合这种目录,linux专门提供了两个结构作为sysfs的骨架,它们就是struct kobject和struct kset。我们知道,sysfs是完全虚拟的,它的每个目录其实都对应着一个kobject,要想知道这个目录下有哪些子目录,就要用到kset。从面向对象的角度来讲,kset继承了kobject的功能,既可以表示sysfs中的一个目录,还可以包含下层目录。对于kobject和kset,会在其它文章中专门分析到,这里简单描述只是为了更好地介绍sysfs提供的API。
sysfs模块提供给外界的接口完全展现在include/linux/sysfs.h中。
- struct attribute {
- const char *name;
- struct module *owner;
- mode_t mode;
- };
- struct attribute_group {
- const char *name;
- mode_t (*is_visible)(struct kobject *,
- struct attribute *, int);
- struct attribute **attrs;
- };
struct attribute {
const char *name;
struct module *owner;
mode_t mode;
};
struct attribute_group {
const char *name;
mode_t (*is_visible)(struct kobject *,
struct attribute *, int);
struct attribute **attrs;
};
之前说过普通文件是kobject目录的属性展现。struct attribute就是属性的通用结构,其它部分在使用时还可以把struct attribute内嵌到更大的属性结构中。struct attribute_group是提供一组属性的集合,这样集中的管理更为方便。
- #define __ATTR(_name,_mode,_show,_store) { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
- }
- #define __ATTR_RO(_name) { \
- .attr = { .name = __stringify(_name), .mode = 0444 }, \
- .show = _name##_show, \
- }
- #define __ATTR_NULL { .attr = { .name = NULL } }
- #define attr_name(_attr) (_attr).attr.name
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
#define __ATTR_RO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0444 }, \
.show = _name##_show, \
}
#define __ATTR_NULL { .attr = { .name = NULL } }
#define attr_name(_attr) (_attr).attr.name
以上的宏是为了静态初始化属性时更为方便,我们简单将其忽略。
- struct bin_attribute {
- struct attribute attr;
- size_t size;
- void *private;
- ssize_t (*read)(struct kobject *, struct bin_attribute *,
- char *, loff_t, size_t);
- ssize_t (*write)(struct kobject *, struct bin_attribute *,
- char *, loff_t, size_t);
- int (*mmap)(struct kobject *, struct bin_attribute *attr,
- struct vm_area_struct *vma);
- };
struct bin_attribute {
struct attribute attr;
size_t size;
void *private;
ssize_t (*read)(struct kobject *, struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*write)(struct kobject *, struct bin_attribute *,
char *, loff_t, size_t);
int (*mmap)(struct kobject *, struct bin_attribute *attr,
struct vm_area_struct *vma);
};
struct attribute是通用的属性结构,而struct bin_attribute就是为二进制属性专门设计的,它在sysfs中表现为二进制文件,大多数是设备配置参数的映射。struct bin_attribute恰恰就是把struct attribute内嵌到更大结构的样例。
- struct sysfs_ops {
- ssize_t (*show)(struct kobject *, struct attribute *,char *);
- ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
- };
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
struct sysfs_ops中包含show和store两个函数指针,它们分别在sysfs文件读和文件写时调用。
- int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
- void *data, struct module *owner);
int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
void *data, struct module *owner);
sysfs_schedule_callback()会创建一个工作队列,稍后调用func(data)。本来sysfs中的属性读写函数是无法删除属性文件或者kobject目录的,因为调用函数时是加锁的,要删除也需要加锁。但这里可以通过工作队列回调的方式实现。
- int __must_check sysfs_create_dir(struct kobject *kobj);
- void sysfs_remove_dir(struct kobject *kobj);
- int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name);
- int __must_check sysfs_move_dir(struct kobject *kobj,
- struct kobject *new_parent_kobj);
int __must_check sysfs_create_dir(struct kobject *kobj);
void sysfs_remove_dir(struct kobject *kobj);
int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name);
int __must_check sysfs_move_dir(struct kobject *kobj,
struct kobject *new_parent_kobj);
sysfs_create_dir()创建一个kobject对应的目录,目录名就是kobj->name。
sysfs_remove_dir()删除kobj对应的目录。删除一个目录也会相应地删除目录下的文件及子目录。
sysfs_rename_dir()修改kobj对应目录的名称。
sysfs_move_dir()将kobj对应的目录移到new_parent_kobj对应的目录下。
- int __must_check sysfs_create_file(struct kobject *kobj,
- const struct attribute *attr);
- int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr,
- mode_t mode);
- void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
int __must_check sysfs_create_file(struct kobject *kobj,
const struct attribute *attr);
int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr,
mode_t mode);
void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
sysfs_create_file()在kobj对应的目录下创建attr对应的属性文件。
sysfs_chmod_file()修改attr对应的属性文件的读写权限。
sysfs_remove_file()在kobj对应的目录下删除attr对应的属性文件。
- int __must_check sysfs_create_bin_file(struct kobject *kobj,
- struct bin_attribute *attr);
- void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
int __must_check sysfs_create_bin_file(struct kobject *kobj,
struct bin_attribute *attr);
void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
sysfs_create_bin_file()在kobj目录下创建attr对应的二进制属性文件。
sysfs_remove_bin_file()在kobj目录下删除attr对应的二进制属性文件。
- int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target,
- const char *name);
- int __must_check sysfs_create_link_nowarn(struct kobject *kobj,
- struct kobject *target,
- const char *name);
- void sysfs_remove_link(struct kobject *kobj, const char *name);
int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target,
const char *name);
int __must_check sysfs_create_link_nowarn(struct kobject *kobj,
struct kobject *target,
const char *name);
void sysfs_remove_link(struct kobject *kobj, const char *name);
sysfs_create_link()在kobj目录下创建指向target目录的软链接,name为软链接文件名称。
sysfs_create_link_nowarn()与sysfs_create_link()功能相同,只是在软链接文件已存在时不会出现警告。
sysfs_remove_link()删除kobj目录下名为name的软链接文件。
- int __must_check sysfs_create_group(struct kobject *kobj,
- const struct attribute_group *grp);
- int sysfs_update_group(struct kobject *kobj,
- const struct attribute_group *grp);
- void sysfs_remove_group(struct kobject *kobj,
- const struct attribute_group *grp);
- int sysfs_add_file_to_group(struct kobject *kobj,
- const struct attribute *attr, const char *group);
- void sysfs_remove_file_from_group(struct kobject *kobj,
- const struct attribute *attr, const char *group);
int __must_check sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp);
int sysfs_update_group(struct kobject *kobj,
const struct attribute_group *grp);
void sysfs_remove_group(struct kobject *kobj,
const struct attribute_group *grp);
int sysfs_add_file_to_group(struct kobject *kobj,
const struct attribute *attr, const char *group);
void sysfs_remove_file_from_group(struct kobject *kobj,
const struct attribute *attr, const char *group);
sysfs_create_group()在kobj目录下创建一个属性集合,并显示集合中的属性文件。如果文件已存在,会报错。
sysfs_update_group()在kobj目录下创建一个属性集合,并显示集合中的属性文件。文件已存在也不会报错。sysfs_update_group()也用于group改动影响到文件显示时调用。
sysfs_remove_group()在kobj目录下删除一个属性集合,并删除集合中的属性文件。
sysfs_add_file_to_group()将一个属性attr加入kobj目录下已存在的的属性集合group。
sysfs_remove_file_from_group()将属性attr从kobj目录下的属性集合group中删除。
- void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
- void sysfs_notify_dirent(struct sysfs_dirent *sd);
void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
void sysfs_notify_dirent(struct sysfs_dirent *sd);
sysfs_notify()和sysfs_notify_dirent()都是用来唤醒在属性文件上调用select()或poll()而阻塞的用户进程。
- struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
- const unsigned char *name);
- struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd);
- void sysfs_put(struct sysfs_dirent *sd);
struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
const unsigned char *name);
struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd);
void sysfs_put(struct sysfs_dirent *sd);
sysfs_get()增加目录或文件的引用计数。
sysfs_put()减少目录或文件的引用计数,并在降为零时删除相应的文件或目录,这种删除又会减少上层目录的引用计数。
sysfs_get_dirent()是增加目录parent_sd中名为name的目录或文件的引用计数。
虽然同样是引用计数,同样在降为零时有删除动作,但却并非使用kref。这种操作更多地继承了文件系统管理时的传统。
- void sysfs_printk_last_file(void);
- int __must_check sysfs_init(void);
void sysfs_printk_last_file(void);
int __must_check sysfs_init(void);
sysfs_printk_last_file()是在sysfs崩溃时打印最后一个访问到的文件路径。
sysfs_init()是在sysfs模块初始化时调用的。
这两个函数都与我们没有什么关系。