1/*
2 * kobject.h - generic kernel object infrastructure.
3 *
4 * Copyright (c) 2002-2003 Patrick Mochel
5 * Copyright (c) 2002-2003 Open Source Development Labs
6 *
7 * This file is released under the GPLv2.
8 *
9 *
10 * Please read Documentation/kobject.txt before using the kobject
11 * interface, ESPECIALLY the parts about reference counts and object
12 * destructors.
13 */
/**
*http://blog.chinaunix.net/u1/55599/
*/
请结合:http://blog.chinaunix.net/u1/55599/showart_1091047.html 文章看,
我相信效果会很好。
功能kobject结构功能说明:
Kobject 是组成设备模型的基本结构。它嵌入于更大的对象的对象中--所谓的容器--用来描述设备模型的组件。如bus, devices, drivers 都是典型的容器。对于内核代码它很少创建一个孤立的 kobject; 相反, kobject 被用来控制存取更大的, 特定域的对象. 为此,
kobject 被嵌入到其他结构中. 如果你习惯以面向对象的术语考虑事情, kobject 可被看作一个顶级的, 抽象类, 其他的类自它而来.
一个 kobject 实现一系列功能, 这些功能对自己不是特别有用而对其他对象是好的. C 语言不允许直接表达继承。 容器有了kobject之后,允许内核:
a) 保存对容器的引用计数
b) 保存容器之间的层次关系
c) 为每个容器的属性提供一个用户视图
14
15#ifndef _KOBJECT_H_
16#define _KOBJECT_H_
18#ifdef __KERNEL__
20#include
21#include
22#include
23#include
24#include
25#include
26#include
27#include
28#include
29
30#define KOBJ_NAME_LEN 20
/**
*在定义kobject数据结构指针*k_name,作为判断,长度小于KOBJ_NAME_LEN ,那么
*kobject名称存在name数组中,*k_name指向组头;如果长度大于KOBJ_NAME_LEN。
*就动态分配一个足够大的缓冲区来存放kobject的名称,这时*k_name指向缓冲区
*/
31#define UEVENT_HELPER_PATH_LEN 256
33/* path to the userspace helper executed on an event */
34extern char uevent_helper[];
36/* counter to tag the uevent, read only except for the kobject core */
37extern u64 uevent_seqnum;
39/*
40 * The actions here must match the index to the string array
41 * in lib/kobject_uevent.c
42 *
43 * Do not add new actions here without checking with the driver-core
44 * maintainers. Action strings are not meant to express subsystem
45 * or device specific properties. In most cases you want to send a
46 * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
47 * specific variables added to the event environment.
48 */
49enum kobject_action {
50 KOBJ_ADD,
51 KOBJ_REMOVE,
52 KOBJ_CHANGE,
53 KOBJ_MOVE,
54 KOBJ_ONLINE,
55 KOBJ_OFFLINE,
56 KOBJ_MAX
57};
59/* The list of strings defining the valid kobject actions as specified above */
60extern const char *kobject_actions[];
63struct kobject {
64 const char * k_name;
65 char name[KOBJ_NAME_LEN];
66 struct kref kref;
67 struct list_head entry;
68 struct kobject * parent;
69 struct kset * kset;
70 struct kobj_type * ktype;
71 struct dentry * dentry;
72};
/**
*在定义kobject数据结构指针*k_name,作为判断,长度小于KOBJ_NAME_LEN ,那么
kobject名称存在name数组中,*k_name指向组头;如果长度大于KOBJ_NAME_LEN。
就动态分配一个足够大的缓冲区来存放kobject的名称,这时*k_name指向缓冲区
*kref成员实现对象的计数,且提供两个函数kobject_get(),kobject_put分别用于增加
和减少引用计数。
*entry用于挂载kobject到kset链表
* * parent指针用于指向kobject的父对象。可以把多个对象间的关系表现出来。
这也是sysfs的真正面目:一个用户空间的文件系统,用来表现kobject对象的层次关系。
* * ktype,* kset指向kobject所需其他结构体,下面详细解释。
* * dentry指针指向dentry结构体。
*/
74extern int kobject_set_name(struct kobject *, const char *, ...)
75 __attribute__((format(printf,2,3)));
/**
*该函数的作用设置指定kobject的名称。
*其中__attribute__()是gcc格式对编译过程的处理,具体参见本博客C编程中详细介绍。
*/
76
77static inline const char * kobject_name(const struct kobject * kobj)
78{
79 return kobj->k_name;
80}
/**
*可以取得当前kobj对象的名称
*/
82extern void kobject_init(struct kobject *);
83extern void kobject_cleanup(struct kobject *);
/**
*kobject_init()用于初始化kobject,它设置kobject引用计数为1。
*kobject_cleanup()
在/linux/lib/kobject.c中定义如下
492static void kobject_release(struct kref *kref)
493{
494 kobject_cleanup(container_of(kref, struct kobject, kref));
495}
kobject清除函数。当其引用计数为0时,释放对象占用的资源。
*其中container_of()是宏,可以获得kobject的首地址。调用kobject_cleanup释放
资源。
*/
85extern int __must_check kobject_add(struct kobject *);
86extern int __must_check kobject_shadow_add(struct kobject *kobj,
struct sysfs_dirent *shadow_parent);
/**
*在/linux/lib/kobject.c中定义如下
222int kobject_add(struct kobject * kobj)
223{
224 return kobject_shadow_add(kobj, NULL);
225}
将kobj对象加入Linux设备层次。挂接该kobject对象到kset的list链中,增加父目录各级kobject的引用计数,
在其parent指向的 目录下创建文件节点,并启动该类型内核对象的hotplug函数。
在 sysfs 中创建kobject的目录入口是kobject_shadow_add的工作的一部分,有些知识值得记住:
(1)kobjects 的 sysfs 入口始终为目录, kobject_add 的调用将在sysfs 中创建一个目录,这个目录包含一个或多个属性(文件);
(2)
分配给 kobject 的名字( 用 kobject_set_name ) 是 sysfs 中的目录名,出现在 sysfs 层次的相同部分的
kobjects 必须有唯一的名字. 分配给 kobjects 的名字也应当是合法的文件名字:
它们不能包含非法字符(如:斜线)且不推荐使用空白。
(3)sysfs 入口位置对应 kobject 的 parent 指针。若
parent 是 NULL ,则它被设置为嵌入到新 kobject 的 kset 中的 kobject;若 parent 和 kset 都是
NULL, 则sysfs 入口目录在顶层目录,通常不推荐。 (4)实际创建目录是, 函数实现的。
*其中__must_check也是宏,实现__attribute_()作用
*/
88extern void kobject_del(struct kobject *);
/**
*从Linux设备层次(hierarchy)中删除kobj对象。
(); 删除相应的目录
*/
90extern int __must_check kobject_rename(struct kobject *, const
char *new_name);
91extern int __must_check kobject_shadow_rename(struct kobject *kobj,
struct sysfs_dirent *new_parent,
const char *new_name);
/**
* kobject_rename()改变kobject结构对象名称
* kobject_shadow_rename()改变kobject结构对象的名称,
还有其parent的名称(目录的名称),相当于创建新目录
*具体参考linux/fs/sysfs/dir.c
*/
94extern int __must_check kobject_move(struct kobject *, struct kobject *);
/**
*kobject赋给一个新parent对象
*/
96extern int __must_check kobject_register(struct kobject *);
97extern void kobject_unregister(struct kobject *);
/**
*kobject_register注册函数。通过调用kobject_get(),
再调用kobject_add()完成该内核对象的注册。上面有介绍,还没有
忘记吧
*kobject_unregister注销函数。与kobject_register()相反,它首先调用
kobject_del 从设备层次中删除该对象,再调用
kobject_put()减少该对象的引用计数,如果引用计数降为0,则释放该kobject对象。
*/
99extern struct kobject * kobject_get(struct kobject *);
100extern void kobject_put(struct kobject *);
/**
*kobject_get 对象的引用计数加1,同时返回该对象的指针。
*将kobject_put对象的引用计数减1,如果引用计数降为0,
则调用kobject_release()释放该kobject对象。
*/
102extern struct kobject *kobject_kset_add_dir(struct kset *kset,
struct kobject *, const char *);
104extern struct kobject *kobject_add_dir(struct kobject *, const char *);
/**
*在kobject数据parent对象中创建目录,目录名称为const char *指向的名称
*在/linux/lib/kobject.c中说明如下
564struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
565{
566 return kobject_kset_add_dir(NULL, parent, name);
567}
而kobject_kset_add_dir()会调用(); 呵呵,又回到这个函数了。
看了这篇文章得把kobject_add()调用关系层次好好的看下了。
*/
106extern char * kobject_get_path(struct kobject *, gfp_t)
/**
*这个函数比较有趣,先调用get_kobj_path_length()函数,获得其
父结点的个数代码如下 do {
if (() == )
return 0;
+= (()) + 1;
= ->;
} while ();
return ;
*然后调用fill_kobj_paht()函数,获得路径
*获得当前kobj对象的路径
*/
107
108struct kobj_type {
109 void (*release)(struct kobject *);
110 struct sysfs_ops * sysfs_ops;
111 struct attribute ** default_attrs;
112};
/**
*当被创建时, 每个 kobject 被给定一套缺省属性. 这些属性通过
kobj_type 结构来指定. 这个结构
*default_attr 成员列举了对每个这样类型的 kobject 被创建的属性,
并且 sysfs_ops 提供方法来实现这些属性.
我们从 default_attrs 开始, 它指向一个指向属性结构的指针数组:
struct attribute
{
char *name;
struct module *owner;
mode_t mode;
};
在这个结构中, name 是属性的名字, owner 是一个指向模块的指针,
模块负责这个属性的实现, 并且 mode 是应用到这个属性的保护位.
mode 常常是 S_IRUGO 对于只读属性;
如果这个属性是可写的, 你可以扔出 S_IWUSR 来只给 root
写权限( modes 的宏定义在 中).
default_attrs 列表中的最后一个入口必须用 0 填充.
default_attr 数组说明这些属性是什么, 但是没有告诉 sysfs 如何真正实现这些属性.
这个任务落到 kobj_type->sysfs_ops 成员,
它指向一个结构, 定义为:
struct sysfs_ops
{
ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buffer);
ssize_t (*store)(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);
};
*store()方法在写操作时调用它会从buffer中读取size大小字节。
并将其存入attr表示属性的结构变量。
*show()方法在读操作时调用,它会拷贝由attr提供的属性值到buffer指定的缓冲区,
缓冲区的大小为PAGE_SIZE字节。
* 注:默认的文件的集合是通过kobject和kset中的ktype字段实现的。
因此所有具有相同类型的kobject在它们
对应的sysfs目录下都拥有相同的默认文件集合。所以也具有相同的默认属性也相同。
内核提供如下函数:
int sysfs_create_file(struct kobject *kobj,const struct attribute *attr); //添加属性
int sysfs_remove_file(struct kobject *kobj,const struct attribute *attr); //删除属性
*/
114struct kset_uevent_ops {
115 int (*filter)(struct kset *kset, struct kobject *kobj);
116 const char *(*name)(struct kset *kset, struct kobject *kobj);
117 int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp,
118 int num_envp, char *buffer, int buffer_size);
119};
/**
*filter()用于过滤掉不需要用户空间的事件,
*uevent()函数用于导出一些环境变量给热插拨程序。
根据导出不同的环境变量采取相应的行动。
*
*/
121/*
122 * struct kset - a set of kobjects of a specific type, belonging
123 * to a specific subsystem.
124 *
125 * All kobjects of a kset should be embedded in an identical
126 * type. This type may have a descriptor, which the kset points
127 * to. This allows there to exist sets of objects of the same
128 * type in different subsystems.
129 *
130 * A subsystem does not have to be a list of only one type
131 * of object; multiple ksets can belong to one subsystem. All
132 * ksets of a subsystem share the subsystem's lock.
133 *
134 * Each kset can support specific event variables; it can
135 * supress the event generation or add subsystem specific
136 * variables carried with the event.
137 */
注:有上面kobject结构调用的层次关系,下面就会调用关系简略写下。
138struct kset {
139 struct kobj_type * ktype;
140 struct list_head list;
141 spinlock_t list_lock;
142 struct kobject kobj;
143 struct kset_uevent_ops * uevent_ops;
144};
/**
* * ktype指向kset对象类型描述符的指针
*list用于链接所有kset中所有kobject的链表头
*list_lock避免竞态的自旋琐
*kobj嵌入的kobject
* * uevent_ops指向kset_uevent_ops
*/
147extern void kset_init(struct kset * k);
/**
*kset_init完成指定的kset的初始化
*/
148extern int __must_check kset_add(struct kset * k);
/**
*实现将指定的kset对象加入设备层次
*/
149extern int __must_check kset_register(struct kset * k);
150extern void kset_unregister(struct kset * k);
/**
*作用分别实现kset对象的注册和注销
*/
152static inline struct kset * to_kset(struct kobject * kobj)
153{
154 return kobj ? container_of(kobj,struct kset,kobj) : NULL;
155}
157static inline struct kset * kset_get(struct kset * k)
158{
159 return k ? to_kset(kobject_get(&k->kobj)) : NULL;
160}
/**
*如果参数不为空,就返回kobj所嵌入的kset
*/
162static inline void kset_put(struct kset * k)
163{
164 kobject_put(&k->kobj);
165}
/**
*kset_get()实现增加kset对象引用计数
*kset_put()实现减少kset对象引用计数
*/
167static inline struct kobj_type * get_ktype(struct kobject * k)
168{
169 if (k->kset && k->kset->ktype)
170 return k->kset->ktype;
171 else
172 return k->ktype;
173}
/**
*以查找指定kobject的kobj_type 指针
*/
175extern struct kobject * kset_find_obj(struct kset *, const char *);
/**
*通过kset对象查找kobject对象
*/
178/*
179 * Use this when initializing an embedded kset with no other
180 * fields to initialize.
181 */
182#define set_kset_name(str) .kset = { .kobj = { .name = str } }
/**
*用于设置kset对象的名称
*/
185#define decl_subsys(_name,_type,_uevent_ops) \
186struct kset _name##_subsys = { \
187 .kobj = { .name = __stringify(_name) }, \
188 .ktype = _type, \
189 .uevent_ops =_uevent_ops, \
190}
191#define decl_subsys_name(_varname,_name,_type,_uevent_ops) \
192struct kset _varname##_subsys = { \
193 .kobj = { .name = __stringify(_name) }, \
194 .ktype = _type, \
195 .uevent_ops =_uevent_ops, \
196}
/**
*通过define decl_subsys(_name,_type,_uevent_ops),decl_subsys_name(_varname,_name,_type,_uevent_ops)
*ksets可以通过其指针指向subsys指针指向一个subsystem。
*而其中__stringify(_name)是一个宏,
#ifndef
#define
/* Indirect stringification. Doing two levels allows the parameter to be a
* macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
* converts to "bar".
*/
#define () #x
#define () ()
#endif
/* !__LINUX_STRINGIFY_H */
*该宏的作用把#后的x转换成字符串类型的
*其中define decl_subsys(_name,_type,_uevent_ops)对kset对象的初始化
*decl_subsys_name(_varname,_name,_type,_uevent_ops)对kset对象的初始化
*/
198/* The global /sys/kernel/ subsystem for people to chain off of */
199extern struct kset kernel_subsys;
200/* The global /sys/hypervisor/ subsystem */
201extern struct kset hypervisor_subsys;
/**
*引用kset结构 hypervisor_subsys,kset kernel_subsys全局变量
*/
203/*
204 * Helpers for setting the kset of registered objects.
205 * Often, a registered object belongs to a kset embedded in a
206 * subsystem. These do no magic, just make the resulting code
207 * easier to follow.
208 */
210/**
211 * kobj_set_kset_s(obj,subsys) - set kset for embedded kobject.
212 * @obj: ptr to some object type.
213 * @subsys: a subsystem object (not a ptr).
214 *
215 * Can be used for any object type with an embedded ->kobj.
216 */
218#define kobj_set_kset_s(obj,subsys) \
(obj)->kobj.kset = &(subsys)
/**
*设置kset对象嵌入kobject对象
*/
221/**
222 * kset_set_kset_s(obj,subsys) - set kset for embedded kset.
223 * @obj: ptr to some object type.
224 * @subsys: a subsystem object (not a ptr).
225 *
226 * Can be used for any object type with an embedded ->kset.
227 * Sets the kset of @obj's embedded kobject (via its embedded
228 * kset) to @subsys.kset. This makes @obj a member of that
229 * kset.
230 */
231
232#define kset_set_kset_s(obj,subsys) \
233 (obj)->kset.kobj.kset = &(subsys)
/**
*设置kset对象嵌入kset对象
*/
235/**
236 * subsys_set_kset(obj,subsys) - set kset for subsystem
237 * @obj: ptr to some object type.
238 * @_subsys: a subsystem object (not a ptr).
239 *
240 * Can be used for any object type with an embedded ->subsys.
241 * Sets the kset of @obj's kobject to @subsys.kset. This makes
242 * the object a member of that kset.
243 */
245#define subsys_set_kset(obj,_subsys) \
246 (obj)->subsys.kobj.kset = &(_subsys)
/**
*设置kset对象插入subsystem链表中 */
248extern void subsystem_init(struct kset *);
/**
*subsystem_init,subsystem的初始化
*/
249extern int __must_check subsystem_register(struct kset *);
250extern void subsystem_unregister(struct kset *);
/**
*subsystem_register函数,subsystem的注册
*subsystem_unregister ,subsystem的注销
*/
252static inline struct kset *subsys_get(struct kset *s)
253{
254 if (s)
255 return kset_get(s);
256 return NULL;
257}
258
259static inline void subsys_put(struct kset *s)
260{
261 kset_put(s);
262}
/**
*subsys_get函数为subsystem增加的引用计数
*subsys_put函数为subsystem减少的引用计数
*/
264struct subsys_attribute {
265 struct attribute attr;
266 ssize_t (*show)(struct kset *, char *);
267 ssize_t (*store)(struct kset *, const char *, size_t);
268};
270extern int __must_check subsys_create_file(struct kset *,
struct subsys_attribute *);
/**
*前面已经讲过,为默认集合添加新属性
*/
272
273#if defined(CONFIG_HOTPLUG)
274int kobject_uevent(struct kobject *kobj, enum kobject_action action);
275int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
276 char *envp[]);
/**
*在在/linux/lib/kobject.c中定义如下
232int kobject_uevent(struct kobject *kobj, enum kobject_action action)
233{
234 return kobject_uevent_env(kobj, action, NULL);
235}
*kobject_uevent_env函数发送message给用户空间,其中message在
enum kobject_action{}结构定义
*action 发送的消息
*kobj发生消息动作的对象
*envp指向环境变量
*/
277
278int add_uevent_var(char **envp, int num_envp, int *cur_index,
279 char *buffer, int buffer_size, int *cur_len,
280 const char *format, ...)
281 __attribute__((format (printf, 7, 8)));
/**
*add_uevent_var()添加指定的环境变量到变量中
*其中这个函数要理解va_start() va_end()等函数,本博客有详细介绍
*/
282#else
283static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action)
284{ return 0; }
285static inline int kobject_uevent_env(struct kobject *kobj,
286 enum kobject_action action,
287 char *envp[])
288{ return 0; }
289
290static inline int add_uevent_var(char **envp, int num_envp, int *cur_index,
291 char *buffer, int buffer_size, int *cur_len,
292 const char *format, ...)
293{ return 0; }
294#endif
295
296#endif /* __KERNEL__ */
297#endif /* _KOBJECT_H_ */
注:以上是本人自己分析的源代码,欢迎校正。禁止复制。
为方便阅读,里面源代码的注释保留。由于在文本写的,复制过来的,
代码不规范,见谅。
参考书:linux设备驱动开发 linux内核设计与实现
阅读(4087) | 评论(3) | 转发(0) |