一、重要知识点
1.Sysfs文件体系
Sysfs文件体系是一种类似于proc文件体系的特别文件体系,它存在于内存傍边,当体系启动时由内核挂载于内存傍边。用于将体系中的设备组织成层次结构,并向用户形式程序供给具体的数据结构信息。
2.Linux设备底层模型
1)为什么要运用设备模型
跟着体系的拓扑结构越来越杂乱,以及要支撑比如电源办理等新特性的要求,所以在2.6的内核中呈现了设备模型。设备模型其实便是一套数据结构树立起来的模型。内核运用该模型支撑了多种不同的使命,包含:
a.电源办理和体系关机
设备模型使操作体系能够以正确的次序遍历体系硬件。
b.与用户空间通信
Sysfs文件体系向用户空间供给体系信息以及改动操作参数的结构。
c.热插拔事情
d.设备类型
体系中许多部分对设备怎么衔接不感兴趣,可是他们需求知道哪些类型设备时可用的。设备模型供给了将设备分类的机制。
e.目标的生命周期
上述的许多功用,包含热插拔支撑和sysfs,使得内核中办理目标的作业更为杂乱。设备模型需求发明一套机制办理目标的生命周期。
2)Kobject
假如说设备模型是一套房子的话,Kobject便是结构房子的砖块。每个注册的Kobject的都对应与Sysfs文件体系中的一个目录。Kobject是组成设备模型的根本结构。类似于C++的基类,它潜入于更大的目标中——所谓的容器,用来描绘设备模型的组件。如bus,device,drivers都是典型的容器。这些容器便是经过kobject衔接起来,构成一个树状结构。这个树状结构就与/sys文件体系对应。不过kobject只能树立单层结构,也便是只能树立一级目录,要树立多级目录,还要运用后边要介绍的Kset。
Kobject结构界说为:
struct kobject {
char * k name; 指向设备称号的指针
char name[KOBJ NAME LEN]; 设备称号
struct kref kref; 目标引证计数
struct list head entry; 挂接到地点kset中去的单元
struct kobject * parent; 指向父目标的指针
struct kset * kset; 所属kset的指针
struct kobj type * ktype; 指向其目标类型描绘符的指针
struct dentry * dentry; sysfs文件体系中与该目标对应的文件节点途径指针
};
相关操作函数:
void kobjet_init(struct kobject*kobj)
初始化Kobject
int kobject_add(struct kobject*kobj)
将Kobject目标注册到linux体系,假如失利则回来一个错误码.
int kobject_init_and_add(structkobject *kobj, kobj_type *ktype, struct kobject *parent, const *fmt…)
初始化并注册kobject,kobject传入要初始化的Kobject目标,ktype将在后边介绍到,parent指向上级的kobject目标,假如指定位NULL,将在/sys的顶层创立一个目录。*fmt为kobject目标的姓名。
kobject的ktype目标是一个指向kobject_type结构的指针,该结构记录了kobject目标的一些特点。每个kobject都需求对应一个相应的kobject结构。
struct kobj_type{
void (*release)(struct kobject *kobj);
structsysfs_ops *sysfs_ops;
structattribute **default_attrs;
};
release办法用于开释kobject占用的资源,当kobject引证计数为0时被调用。
kobje_type的attribute成员:
struct attribute{
char*name;//特点文件名
structmodule *owner;
mode_tmode;
}
struct attribute(特点):对应于kobject的目录下一个文件,name便是文件名。
kobje_type的struct sysfs_ops成员:
struct sysfs_ops
{
ssize_t (*show)(structkobejct *, struct attribute *, char *name);
ssize_t (*store)(structkobejct *, struct attribute *, char *name);
}
show:当用户读特点文件时,该函数被调用,该函数将特点值存入buffer中回来给用户态;
store:当用户写特点文件时,该函数被调用,用于存储用户存入的特点值。
Kobject测验模块:
#include
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR(“David Xie”);
MODULE_LICENSE(“Dual BSD/GPL”);
void obj_test_release(struct kobject *kobject);
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
struct attribute test_attr = {
.name = “kobj_config”,
.mode = S_IRWXUGO,
};
static struct attribute *def_attrs[] = {
&test_attr,
NULL,
};
struct sysfs_ops obj_test_sysops =
{
.show = kobj_test_show,
.store = kobj_test_store,
};
struct kobj_type ktype =
{
.release = obj_test_release,
.sysfs_ops=&obj_test_sysops,
.default_attrs=def_attrs,
};
void obj_test_release(struct kobject *kobject)
{
printk(“eric_test: release .\n”);
}
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
{
printk(“have show.\n”);
printk(“attrname:%s.\n”, attr->name);
sprintf(buf,”%s\n”,attr->name);
return strlen(attr->name)+2;
}
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
{
printk(“havestore\n”);
printk(“write: %s\n”,buf);
return count;
}
struct kobject kobj;
staTIc int kobj_test_init()
{
printk(“kboject test init.\n”);
kobject_init_and_add(&kobj,&ktype,NULL,”kobject_test”);
return 0;
}
staTIc int kobj_test_exit()
{
printk(“kobject test exit.\n”);
kobject_del(&kobj);
return 0;
}
module_init(kobj_test_init);
module_exit(kobj_test_exit);
#include #include #include #include #include #include #include MODULE_AUTHOR(“David Xie”);MODULE_LICENSE(“Dual BSD/GPL”);void obj_test_release(struct kobject *kobject);ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);struct attribute test_attr = {.name = “kobj_config”,.mode = S_IRWXUGO,};static struct attribute *def_attrs[] = {&test_attr,NULL,};struct sysfs_ops obj_test_sysops ={.show = kobj_test_show,.store = kobj_test_store,};struct kobj_type ktype ={.release = obj_test_release,.sysfs_ops=&obj_test_sysops,.default_attrs=def_attrs,};void obj_test_release(struct kobject *kobject){printk(“eric_test: release .\n”);}ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf){printk(“have show.\n”);printk(“attrname:%s.\n”, attr->name);sprintf(buf,”%s\n”,attr->name);return strlen(attr->name)+2;}ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count){printk(“havestore\n”);printk(“write: %s\n”,buf);return count;}struct kobject kobj;staTIc int kobj_test_init(){printk(“kboject test init.\n”);kobject_init_and_add(&kobj,&ktype,NULL,”kobject_test”);return 0;}staTIc int kobj_test_exit(){printk(“kobject test exit.\n”);kobject_del(&kobj);return 0;}module_init(kobj_test_init);module_exit(kobj_test_exit);
测验成果:
在/sys目录下创立了kobject_test目录
在kobject_test目录下有kobj_config文件
读kobject_config文件则调用了show函数。并在用户空间显现了show回来的kobject目标姓名。
写kobject_config文件调用了store函数。
3)Kset
kset的主要功用是容纳;咱们能够认为他他是kobject的顶层容器。实践上,在每个kset目标的内部,包含了自己的kobject,而且能够用多种处理kobject的办法处理kset。假如说kobject是基类的话,那么kset便是派送类。kobject经过kset组织成层次化的结构,kset是相同类型的组合。浅显的讲,kobject树立一级的子目录,kset能够为kobject树立多级的层次性的父目录。
struct kset {
struct subsystem * subsys; 地点的subsystem的指针
struct kobj type * ktype; 指向该kset目标类型描绘符的指针
struct list head list; 用于衔接该kset中一切kobject的链表头
struct kobject kobj; 嵌入的kobject
struct kset_uevent_ops * uevent_ops; 指向热插拔操作表的指针
};
包含在kset中的一切kobject被组织成一个双向循环链表,list域正是该链表的头。Ktype域指向一个kobj type结构,被该kset中的一切kobject同享,表明这些目标的类型。Kset数据结构还内嵌了一个kobject目标(由kobj域表明),一切归于这个kset 的kobject目标的parent域均指向这个内嵌的目标。此外,kset还依赖于kobj保护引证计数:kset的引证计数实践上便是内嵌的kobject目标的引证计数。
kset与kobject的联系图
Kset操作:
int kset_register(struct kset*kset)
注册kset
void kset_unregister(struct kset*kset)
刊出kset
热插拔事情:在linux体系中,当体系配置发生变化时,如增加kset到体系或移动kobject,一个通知会从内核空间发送到用户空间,这便是热插拔事情。热插拔事情会导致用户空间中的处理程序(如udev,mdev)被调用,这些处理程序会经过加载驱动程序,创立设备节点等来呼应热插拔事情。
对热插拔事情的实践操控是由struct kset_uevent_ops结构中的函数完结的。
struct kset_uevnt_ops{
int (*filter)(struct kset *kset,struct kobject *kobj);
const char *(*name)(struct kset *kset, struct kobject *kobj );
int (*uevent)(struct kset *kset,struct kobject *kobj,struct kobj_uevent *env);
}
filter决议是否发生事情,假如回来0,将不发生事情。
name向用户空间传递一个适宜的字符串
uevent经过环境变量传递任何热插拔脚本需求的信息,他会在(udev或mdev)调用之前,供给增加环境变量的时机。
kset测验模块:
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR(“David Xie”);
MODULE_LICENSE(“Dual BSD/GPL”);
struct kset kset_p;
struct kset kset_c;
int kset_filter(struct kset *kset, struct kobject *kobj)
{
printk(“Filter: kobj %s.\n”,kobj->name);
return 1;
}
const char *kset_name(struct kset *kset, struct kobject *kobj)
{
static char buf[20];
printk(“Name: kobj %s.\n”,kobj->name);
sprintf(buf,”%s”,”kset_name”);
return buf;
}
int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env)
{
int i = 0;
printk(“uevent: kobj %s.\n”,kobj->name);
while( i < env->envp_idx){
printk(“%s.\n”,env->envp[i]);
i++;
}
return 0;
}
struct kset_uevent_ops uevent_ops =
{
.filter = kset_filter,
.name = kset_name,
.uevent = kset_uevent,
};
int kset_test_init()
{
printk(“kset test init.\n”);
kobject_set_name(&kset_p.kobj,”kset_p”);
kset_p.uevent_ops = &uevent_ops;
kset_register(&kset_p);
kobject_set_name(&kset_c.kobj,”kset_c”);
kset_c.kobj.kset = &kset_p;
kset_register(&kset_c);
return 0;
}
int kset_test_exit()
{
printk(“kset test exit.\n”);
kset_unregister(&kset_p);
kset_unregister(&kset_c);
return 0;
}
module_init(kset_test_init);
module_exit(kset_test_exit);
#include #include #include #include #include #include #include #include MODULE_AUTHOR(“David Xie”);MODULE_LICENSE(“Dual BSD/GPL”);struct kset kset_p;struct kset kset_c;int kset_filter(struct kset *kset, struct kobject *kobj){printk(“Filter: kobj %s.\n”,kobj->name);return 1;}const char *kset_name(struct kset *kset, struct kobject *kobj){static char buf[20];printk(“Name: kobj %s.\n”,kobj->name);sprintf(buf,”%s”,”kset_name”);return buf;}int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env){int i = 0;printk(“uevent: kobj %s.\n”,kobj->name);while( i < env->envp_idx){printk(“%s.\n”,env->envp[i]);i++;}return 0;}struct kset_uevent_ops uevent_ops ={.filter = kset_filter,.name = kset_name,.uevent = kset_uevent,};int kset_test_init(){printk(“kset test init.\n”);kobject_set_name(&kset_p.kobj,”kset_p”);kset_p.uevent_ops = &uevent_ops;kset_register(&kset_p);kobject_set_name(&kset_c.kobj,”kset_c”);kset_c.kobj.kset = &kset_p;kset_register(&kset_c);return 0;}int kset_test_exit(){printk(“kset test exit.\n”);kset_unregister(&kset_p);kset_unregister(&kset_c);return 0;}module_init(kset_test_init);module_exit(kset_test_exit);
测验成果:
能够看出当kset加载时,在/sys下创立了一个kset_p,在kset_p下面创立了kset_c,当kset模块被加载和卸载时都发生了热插拔事情。