kobject和uevent的一点想法--待续
来源:互联网 发布:淘宝网上海故事 编辑:程序博客网 时间:2024/04/27 17:09
文件路径:
include/linux/kobject.h
lib/kobject_uevent.c
lib/kobject.c
在我的理解中uevent事件和kobject绑定在一起的
几种kobject能够产生的事件属性
enumkobject_action {
KOBJ_ADD,//添加
KOBJ_REMOVE,//移除
KOBJ_CHANGE,//发生了变化
KOBJ_MOVE,//移动
KOBJ_ONLINE,//存在
KOBJ_OFFLINE,//不在
KOBJ_MAX//最大
};
structkobject {
constchar *name; //本目录的名字
structlist_head entry; //链表
structkobject *parent; //父目录吧。。父亲,可以使用kobj,kset或者sys root
structkset *kset;//顶层
structkobj_type *ktype; //相应的操作
structsysfs_dirent *sd;//sysfs下的目录名,根据parent设置或者会设置位sysroot下
structkref kref;//引用计数当用kobject_put设置为0时,则调用kobject_cleanup完全释放内存
unsignedint state_initialized:1; //释放被初始化,我的理解是当申请了kobject后记得设为0阿
unsignedint state_in_sysfs:1;//是否在sys下
unsignedint state_add_uevent_sent:1;//是否为增加的action
unsignedint state_remove_uevent_sent:1;//是否为remove的acton
unsignedint uevent_suppress:1;//不发送uevent事件
};
structkobj_type {
void(*release)(struct kobject *kobj);
conststruct sysfs_ops *sysfs_ops;
structattribute **default_attrs;
conststruct kobj_ns_type_operations *(*child_ns_type)(struct kobject*kobj);
constvoid *(*namespace)(struct kobject *kobj);
};
以上是kobject的结构体,那么接下来我来分析下kobject,然后穿插着说一下这个结构体,
那么一开始当然是从kobject_init开始
kobject_init
*This function will properly initialize a kobject such that it canthen
*be passed to the kobject_add() call.
*
*After this function is called, the kobject MUST be cleaned up by acall
*to kobject_put(), not by a call to kfree directly to ensure that allof
*the memory is cleaned up properly.
根据kobject_init的解释,最后释放的时候要掉用kobject_put能够释放所有的内存,然而接下来要掉用的是kobject_add
kobject_add
/**
*kobject_add - the main kobject add function
*@kobj: the kobject to add
*@parent: pointer to the parent of the kobject.
*@fmt: format to name the kobject with.
*
*The kobject name is set and added to the kobject hierarchy in this
*function.
*
*If @parent is set, then the parent of the @kobj will be set to it.
*If @parent is NULL, then the parent of the @kobj will be set to the
*kobject associted with the kset assigned to this kobject. If nokset
*is assigned to the kobject, then the kobject will be located in the
*root of the sysfs tree.
*
*If this function returns an error, kobject_put() must be called to
*properly clean up the memory associated with the object.
*Under no instance should the kobject that is passed to this function
*be directly freed with a call to kfree(), that can leak memory.
*
*Note, no "add" uevent will be created with this call, thecaller should set
*up all of the necessary sysfs files for the object and then call
*kobject_uevent() with the UEVENT_ADD parameter to ensure that
*userspace is properly notified of this kobject's creation.
*/
关于这个函数重要的由以下几点
一:你现在设置的这个name将会添加到kobject的层次结构中也就是添加一个文件目录
二:如果设置了parent,那么kobj就会设置到parent下
如果parent==NULL,首先呢kobj就会设置到他的kset上,如果kset还没有,就会设置到sys下,
代码确实是这样写的
关于kobject的初始化最后说一句就是释放记得用kobject_put,根据这么多的函数说明来看只有他才会释放所有的内存
接下来我们来了解下所谓的uevent事件,我们从上报开始
/**
*kobject_uevent - notify userspace by sending an uevent
*
*@action: action that is happening
*@kobj: struct kobject that the action is happening to
*
*Returns 0 if kobject_uevent() is completed with success or the
*corresponding error when it fails.
*/
intkobject_uevent(struct kobject *kobj, enum kobject_action action)
{
returnkobject_uevent_env(kobj, action, NULL);
}
通过uevent时间上报到用户空间
接下来调用kobject_uevent_env
kobject_uevent_env
/**
*kobject_uevent_env - send an uevent with environmental data
*
*@action: action that is happening
*@kobj: struct kobject that the action is happening to
*@envp_ext: pointer to environmental data
*
*Returns 0 if kobject_uevent_env() is completed with success or the
*corresponding error when it fails.
*/
intkobject_uevent_env(struct kobject *kobj, enum kobject_action action,
char *envp_ext[])
{
structkobj_uevent_env *env;
constchar *action_string = kobject_actions[action];
constchar *devpath = NULL;
constchar *subsystem;
structkobject *top_kobj;
structkset *kset;
conststruct kset_uevent_ops *uevent_ops;
u64seq;
inti = 0;
intretval = 0;
#ifdefCONFIG_NET
structuevent_sock *ue_sk;
#endif
pr_debug("kobject:'%s' (%p): %s\n",
kobject_name(kobj), kobj, __func__);
/*search the kset we belong to */
top_kobj= kobj;
while(!top_kobj->kset && top_kobj->parent) //寻找最近的kset
top_kobj= top_kobj->parent;
if(!top_kobj->kset) { //没有kset不能发送uevent事件
pr_debug("kobject:'%s' (%p): %s: attempted to send uevent "
"without kset!\n", kobject_name(kobj), kobj,
__func__);
return-EINVAL;
}
kset= top_kobj->kset; //get the closest kset
uevent_ops= kset->uevent_ops;//get the kset's ops
/*skip the event, if uevent_suppress is set*/
if(kobj->uevent_suppress) {//拒绝发送uevent事件
pr_debug("kobject:'%s' (%p): %s: uevent_suppress "
"caused the event to drop!\n",
kobject_name(kobj), kobj, __func__);
return0;
}
/*skip the event, if the filter returns zero. */
if(uevent_ops && uevent_ops->filter)
if(!uevent_ops->filter(kset, kobj)) {//在set的filter里会去设置屏蔽掉一些uevent事件不能发送
pr_debug("kobject:'%s' (%p): %s: filter function "
"caused the event to drop!\n",
kobject_name(kobj), kobj, __func__);
return0;
}
/*originating subsystem */
if(uevent_ops && uevent_ops->name) //返回子系统的名字
subsystem= uevent_ops->name(kset, kobj);
else
subsystem= kobject_name(&kset->kobj);
if(!subsystem) {
pr_debug("kobject:'%s' (%p): %s: unset subsystem caused the "
"event to drop!\n", kobject_name(kobj), kobj,
__func__);
return0;
}
/*environment buffer */
env= kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);//申请要发送的buffer
if(!env)
return-ENOMEM;
/*complete object path */
devpath= kobject_get_path(kobj, GFP_KERNEL); //获取该kobj所有的路径(sys下)
if(!devpath) {
retval= -ENOENT;
gotoexit;
}
/*default keys */
retval= add_uevent_var(env, "ACTION=%s",action_string);//当前该kobj发生的动作
if(retval)
gotoexit;
retval= add_uevent_var(env, "DEVPATH=%s",devpath);//当前该kobj的完整路径
if(retval)
gotoexit;
retval= add_uevent_var(env, "SUBSYSTEM=%s",subsystem);//当前的kobj所代表的子系统即kobj->name
if(retval)
gotoexit;
/*keys passed in from the caller */
if(envp_ext) {
for(i = 0; envp_ext[i]; i++) {
retval= add_uevent_var(env, "%s",envp_ext[i]);//把环境变量挨个的放到env中,所有的长度最大为2048,数据最多位32个
if(retval)
gotoexit;
}
}
/*let the kset specific function add its stuff */
if(uevent_ops && uevent_ops->uevent) {
retval= uevent_ops->uevent(kset, kobj, env);//检查以下有没有不让带的env参数
if(retval) {
pr_debug("kobject:'%s' (%p): %s: uevent() returned "
"%d\n", kobject_name(kobj), kobj,
__func__, retval);
gotoexit;
}
}
/*
* Mark "add" and "remove" events in the object toensure proper
* events to userspace during automatic cleanup. If the object did
* send an "add" event, "remove" willautomatically generated by
* the core, if not already done by the caller.
*/
if(action == KOBJ_ADD)
kobj->state_add_uevent_sent= 1;
elseif (action == KOBJ_REMOVE)
kobj->state_remove_uevent_sent= 1;
/*we will send an event, so request a new sequence number */
spin_lock(&sequence_lock);
seq= ++uevent_seqnum;//发送的uevent队列编号可以检查一共发送了多少个uevent事件
spin_unlock(&sequence_lock);
retval= add_uevent_var(env, "SEQNUM=%llu", (unsigned longlong)seq);//增加最后一个env也意味着我们能带的参数最多只有31个
if(retval)
gotoexit;
#ifdefined(CONFIG_NET)
/*send netlink message */
mutex_lock(&uevent_sock_mutex);
list_for_each_entry(ue_sk,&uevent_sock_list, list) {
structsock *uevent_sock = ue_sk->sk;
structsk_buff *skb;
size_tlen;
/*allocate message with the maximum possible size */
len= strlen(action_string) + strlen(devpath) + 2;
skb= alloc_skb(len + env->buflen, GFP_KERNEL);
if(skb) {
char*scratch;
/*add header */
scratch= skb_put(skb, len);
sprintf(scratch,"%s@%s", action_string, devpath);
/*copy keys to our continuous event payload buffer */
for(i = 0; i < env->envp_idx; i++) {
len= strlen(env->envp[i]) + 1;
scratch= skb_put(skb, len);
strcpy(scratch,env->envp[i]);
}
NETLINK_CB(skb).dst_group= 1;
retval= netlink_broadcast_filtered(uevent_sock, skb,
0, 1, GFP_KERNEL,
kobj_bcast_filter,
kobj);
/*ENOBUFS should be handled in userspace */
if(retval == -ENOBUFS)
retval= 0;
}else
retval= -ENOMEM;
}
mutex_unlock(&uevent_sock_mutex);
#endif
/*call uevent_helper, usually only enabled during early boot */
if(uevent_helper[0] && !kobj_usermode_filter(kobj)){//如果设置了uevent_helper的路径才会有可能调用
char*argv [3];
argv[0] = uevent_helper;
argv[1] = (char *)subsystem;
argv[2] = NULL;
retval= add_uevent_var(env, "HOME=/");
if(retval)
gotoexit;
retval= add_uevent_var(env,
"PATH=/sbin:/bin:/usr/sbin:/usr/bin");
if(retval)
gotoexit;
retval= call_usermodehelper(argv[0], argv,
env->envp, UMH_WAIT_EXEC);
}
exit:
kfree(devpath);
kfree(env);
returnretval;
}
现在我们知道了什么情况下会发送uevent事件和那些条件不能发送,那么接下来讨论的是如何发送的,
由我们分析的kobject_uevent_env可知,有两种uevent的上报机制,一种是直接调用user空间的程序,(需要设置相应的CONFIG_UEVENT_HELPER_PATH才有可能会调用)
但我们这里着重的理解一下netlink的机制
明天再去搞一搞,然后通过netlink接口获取所有的uevent事件
- kobject和uevent的一点想法--待续
- 多关键字模糊搜索的一点想法(待续)
- 困境和出路的一点想法!
- 针对抄袭和盗版的一点想法
- 玩萨尔达的一点想法
- MVC的一点想法
- svn 的一点想法
- 最近的一点想法
- 缓存的一点想法
- 一点零星的想法
- 最近的一点想法
- 自下而上的一点想法
- 最近的一点想法
- 职业生涯规划的一点想法
- 老码农的一点想法
- Fragment的一点想法
- 最近的一点想法
- 管理的一点想法
- github基础命令
- Java poi Excel 文字缩进处理
- Android中网络通信方式的简单汇总(HttpURLConnection、HttpClient、Socket等)
- UpnpDemo_定义服务
- python_lambda函数
- kobject和uevent的一点想法--待续
- UpnpDemo_发布设备和服务
- (解题报告)HDU2020---绝对值排序
- 常用的机器学习&数据挖掘知识(点)总结
- UpnpDemo_搜索设备和服务
- 获取网络图片之---三种方式
- UpnpDemo_调用服务
- leetcode之Binary Tree Level Order Traversal II
- (解题报告)HDU2021---发工资咯:)