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; //父目录吧。。父亲,可以使用kobjkset或者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)) {//setfilter里会去设置屏蔽掉一些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事件

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 蓝牙耳机听不了怎么办 路虎车门打不开怎么办 蓝牙连接声音小怎么办 手机丢在高铁上怎么办 电信卡注销欠费怎么办 手机和卡都丢了怎么办 老干妈打不开盖子怎么办 苹果键盘电池仓打不开怎么办 苏泊尔电压力锅打不开盖子怎么办 honorv9声音太小怎么办 异地手机卡丢了怎么办 中国移动卡丢了怎么办 mate8麦克风坏了怎么办 qq空间被禁赞了怎么办 苹果老耳机模式怎么办 华为手机无声音怎么办 华为手机声音不正常怎么办 带耳机不能说话怎么办 耳机说话没声音怎么办 手机耳机说话没声音怎么办 不接爸爸电话怎么办 耳机自动调高怎么办 手机扩音器坏了怎么办 耳机有电流麦怎么办 耳机自动调音量怎么办 耳机接口总是坏怎么办 漫步者耳机音量太大怎么办 华为录音声音小怎么办 耳机自己调音了怎么办 主驾驶升降失灵怎么办 蓝牙耳机音质差怎么办 苹果不兼容耳机怎么办 唱歌耳机声音小怎么办 耳机声音小是怎么办 手机出现耳机模式怎么办 荣耀8上网慢怎么办 空调满尘了怎么办 设置了耳机模式怎么办 头戴式耳机断了怎么办 销钉孔大了怎么办 孔大了0.2怎么办