sysfs实现的功能
- 为用户空间提供一个层级视图结构。
- 提供统一的引用计数。
- 分别用show和store来提供属性数据的导出导入。
- 可向用户空间发送信号。
ps:实现的诀窍就是将kobject和文件目录(directory entries)联系起来。
相关的结构体
struct kobject {
const char *name; //kobject 的名称
struct list_head entry; //连接下一个kobject结构
struct kobject *parent; //指向父kobject结构
struct kset *kset; //指向kset集合
struct kobj_type *ktype; //指向kobject的类型描述
struct sysfs_dirent *sd; //对应sysfs的文件目录
struct kref kref; //kobject引用计数
unsigned int state_initialized:1; //kobject初始化标志位
unsigned int state_in_sysfs:1; //是否加入sysfs中
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
struct kobj_type {
void (*release)(struct kobject *kobj); //kobject对象释放函数
const struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};
struct attribute {
const char *name; //属性名称
umode_t mode; //属性读写权限
#ifdef CONFIG_DEBUG_LOCK_ALLOC
bool ignore_lockdep:1;
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *); //读
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); //写
const void *(*namespace)(struct kobject *, const struct attribute *);
};
结构体之间的关系
kobject是整个文件系统的核心、基础,它类似于c++中的基类的作用。其中通过*parent的指针来构建了整个文件系统的视图。而在实际的使用中将它嵌入到其它的字符设备、平台设备等的结构,这样就将他们关联起来了。这种技巧在linux很多地方都有使用,比如container_of()。
kset实际上就是很多类型相同的kobject的合集。
kobj_type 对应不同的类型。
下面这个图很好的展示了它们的关系:
源码分析
常用函数
kobject相关操作函数
#include <linux/kobject.h>
void kobject_init(struct kobject *kobj);
int kobject_add(struct kobject *kobj);
extern int kobject_register(struct kobject *kobj);
void kobject_del(struct kobject *kobj);
void kobject_unregister(struct kobject *kobj);
kset相关的操作函数
#include <linux/kobject.h>
void kset_init(struct kset *kset);
int kset_add(struct kset *kset);
int kset_register(struct kset *kset);
void kset_unregister(struct kset *kset);
文件相关的操作函数
#include <linux/sysfs.h>
int sysfs_create_file(struct kobject *kobj, struct attribute *attr);
int sysfs_remove_file(struct kobject *kobj, struct attribute *attr);
int sysfs_create_bin_file(struct kobject *kobj, struct bin_attribute *attr);
int sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
int sysfs_create_link(struct kobject *kobj, struct kobject *target, char
*name);
void sysfs_remove_link(struct kobject *kobj, char *name);
文件系统
示例代码
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/stat.h>
void sysfs_test_release(struct kobject *kobj);
ssize_t sysfs_test_show(struct kobject *, struct attribute *,char *);
ssize_t sysfs_test_store(struct kobject *,struct attribute *,const char *, size_t);
struct attribute sysfs_test_attrs = {
.name = "sysfs_test_attrs",
.mode = S_IRWXUGO,
};
static struct attribute *def_attrs [] = {
&sysfs_test_attrs,
NULL,
};
struct sysfs_ops sysfs_test_ops = {
.show = sysfs_test_show, //read func
.store = sysfs_test_store, //write func
};
struct kobj_type ktype = {
.release = sysfs_test_release,
.sysfs_ops = &sysfs_test_ops,
.default_attrs = def_attrs,
};
void sysfs_test_release(struct kobject *kobj)
{
printk(KERN_WARNING"sysfs release test!\n");
}
/*when cat sysfs_test,show the attribute name*/
ssize_t sysfs_test_show(struct kobject *kobj, struct attribute *attr,char *buf)
{
printk(KERN_WARNING"call sysfs_test_show()\n");
printk(KERN_WARNING"attrname:%s\n",attr->name);
sprintf(buf,"%s\n",attr->name);
return strlen(attr->name)+2;
}
/*when echo xxx > sysfs_test,show it*/
ssize_t sysfs_test_store(struct kobject *kobj,struct attribute *attr,const char *buf, size_t count)
{
printk(KERN_WARNING"call sysfs_test_store()\n");
printk("count:%d,write:%s",count,buf);
return count;
}
struct kobject kobj; /*the kobject to be added*/
static int sysfs_test_init(void)
{
int ret = 0;
printk(KERN_WARNING"init the kobj in sysfs_test_init()\n");
/*init the kobj and add to kernel*/
ret = kobject_init_and_add(&kobj,&ktype,NULL,"sysfs_test");
if (ret !=0) {
printk("init kobj fail!\n");
return ret;
}
return ret;
}
void sysfs_test_exit(void)
{
printk(KERN_WARNING"sysfs test exit\n");
kobject_del(&kobj);
}
MODULE_LICENSE("GPL");
module_init(sysfs_test_init);
module_exit(sysfs_test_exit);