Linux设备模型分析之kset

作者:刘昊昱 

博客:http://blog.csdn.net/liuhaoyutz

内核版本:2.6.36

 
上一篇博客我们分析了Linux设备模型中kobject的注册和使用,在这一篇文章中,我们来看一下kset的用法。
首先我们看一个使用kset的例子,代码如下:
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
 
MODULE_AUTHOR("haoyu");
MODULE_LICENSE("Dual BSD/GPL");
 
struct my_kobject
{
    int value;
    struct kobject kobj;
};
    
struct my_kobject my_kobj;
 
void kobject_release(struct kobject *kobject);
ssize_t kobject_attr_show(struct kobject *kobject, struct attribute *attr,char *buf);
ssize_t kobject_attr_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
 
struct attribute kobject_attr1 = {
    .name = "name",
    .mode = S_IRWXUGO,
};
 
struct attribute kobject_attr2 = {
    .name = "value",
    .mode = S_IRWXUGO,
};
 
static struct attribute *kobject_def_attrs[] = {
    &kobject_attr1,
    &kobject_attr2,
    NULL,
};
 
struct sysfs_ops kobject_sysfs_ops =
{
    .show = kobject_attr_show,
    .store = kobject_attr_store,
};
 
struct kobj_type ktype =
{
    .release = kobject_release,
    .sysfs_ops = &kobject_sysfs_ops,
    .default_attrs = kobject_def_attrs,
};
 
void kobject_release(struct kobject *kobject)
{
    printk("kobject release.\n");
}
 
ssize_t kobject_attr_show(struct kobject *kobject, struct attribute *attr,char *buf)
{
    int count = 0;
    struct my_kobject *my_kobj = container_of(kobject, struct my_kobject, kobj);
    printk("kobject attribute show.\n");
    if(strcmp(attr->name, "name") == 0)
        count = sprintf(buf, "%s\n", kobject->name);
    else if(strcmp(attr->name, "value") == 0)
        count = sprintf(buf, "%d\n", my_kobj->value);
    else
        printk("no this attribute.\n");
    
    return count;
}
 
ssize_t kobject_attr_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
{
    int val;
    struct my_kobject *my_kobj = container_of(kobject, struct my_kobject, kobj);
    printk("kobject attribute store.\n");
    if(strcmp(attr->name, "name") == 0)
        printk("Can not change name.\n");
    else if(strcmp(attr->name, "value") == 0)
    {
        val = buf[0] - '0';
        if(val == 0 || val == 1)
            my_kobj->value = val;
        else
            printk("value is '0' or '1'\n");
    }
    else
        printk("no this attribute.\n");
        
    return count;
}
 
int kset_filter(struct kset *kset, struct kobject *kobj)
{
    printk("UEVENT: filter. kobj %s.\n",kobj->name);
    return 1;
}
 
const char *kset_name(struct kset *kset, struct kobject *kobj)
{
    static char buf[20];
    printk("UEVENT: name. kobj %s.\n",kobj->name);
    sprintf(buf,"%s","kset_test");
    return buf;
}
 
int kset_uevent(struct kset *kset, struct kobject *kobj,
                struct kobj_uevent_env *env)
{
    int i = 0;
    printk("UEVENT: 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,
};
 
struct kset *kset_parent;
struct kset kset_child;
 
static int kset_test_init(void)
{
    printk("kboject test init.\n");
    kset_parent = kset_create_and_add("kset_parent", &uevent_ops, NULL);
    my_kobj.kobj.kset = kset_parent;
    kobject_init_and_add(&my_kobj.kobj,&ktype,NULL,"kobject_test");
 
    kobject_set_name(&kset_child.kobj,"kset_child");
    kset_child.kobj.kset = kset_parent;
    kset_register(&kset_child);
    
    return 0;
}
 
static void kset_test_exit(void)
{
    printk("kobject test exit.\n");
    kobject_del(&my_kobj.kobj);
    kset_unregister(kset_parent);
    kset_unregister(&kset_child);
}
 
module_init(kset_test_init);
module_exit(kset_test_exit);

该模块执行结果如下图所示:
 
kset的注册使用kset_create_and_add函数,该函数定义如下:
820/**
821 * kset_create_and_add - create a struct kset dynamically and add it to sysfs
822 *
823 * @name: the name for the kset
824 * @uevent_ops: a struct kset_uevent_ops for the kset
825 * @parent_kobj: the parent kobject of this kset, if any.
826 *
827 * This function creates a kset structure dynamically and registers it
828 * with sysfs.  When you are finished with this structure, call
829 * kset_unregister() and the structure will be dynamically freed when it
830 * is no longer being used.
831 *
832 * If the kset was not able to be created, NULL will be returned.
833 */
834struct kset *kset_create_and_add(const char *name,
835                 const struct kset_uevent_ops *uevent_ops,
836                 struct kobject *parent_kobj)
837{
838    struct kset *kset;
839    int error;
840
841    kset = kset_create(name, uevent_ops, parent_kobj);
842    if (!kset)
843        return NULL;
844    error = kset_register(kset);
845    if (error) {
846        kfree(kset);
847        return NULL;
848    }
849    return kset;
850}

该函数首先调用kset_create创建kset,然后调用kset_register将kset注册到系统中。
先来看kset_create函数是如何创建kset的,该函数定义如下:
776/**
777 * kset_create - create a struct kset dynamically
778 *
779 * @name: the name for the kset
780 * @uevent_ops: a struct kset_uevent_ops for the kset
781 * @parent_kobj: the parent kobject of this kset, if any.
782 *
783 * This function creates a kset structure dynamically.  This structure can
784 * then be registered with the system and show up in sysfs with a call to
785 * kset_register().  When you are finished with this structure, if
786 * kset_register() has been called, call kset_unregister() and the
787 * structure will be dynamically freed when it is no longer being used.
788 *
789 * If the kset was not able to be created, NULL will be returned.
790 */
791static struct kset *kset_create(const char *name,
792                const struct kset_uevent_ops *uevent_ops,
793                struct kobject *parent_kobj)
794{
795    struct kset *kset;
796    int retval;
797
798    kset = kzalloc(sizeof(*kset), GFP_KERNEL);
799    if (!kset)
800        return NULL;
801    retval = kobject_set_name(&kset->kobj, name);
802    if (retval) {
803        kfree(kset);
804        return NULL;
805    }
806    kset->uevent_ops = uevent_ops;
807    kset->kobj.parent = parent_kobj;
808
809    /*
810     * The kobject of this kset will have a type of kset_ktype and belong to
811     * no kset itself.  That way we can properly free it when it is
812     * finished being used.
813     */
814    kset->kobj.ktype = &kset_ktype;
815    kset->kobj.kset = NULL;
816
817    return kset;
818}

798行,为kset分配空间。
801行,设置kset->kobj的名字,代表该kset的名字。
806行,设置kset->uevent_ops。
807行,设置kset->kobj.parent。
814行,将kset->kobj.ktype设置为&kset_ktype。kset_ktype我们在下面介绍。
815行,将kset->kobj.kset设置为NULL,即该kset不属于任何kset。
kset_ktype的定义如下:
771static struct kobj_type kset_ktype = {
772    .sysfs_ops  = &kobj_sysfs_ops,
773    .release = kset_release,
774};

为了分析方便,我们先来看kset_release的定义:
763static void kset_release(struct kobject *kobj)
764{
765    struct kset *kset = container_of(kobj, struct kset, kobj);
766    pr_debug("kobject: '%s' (%p): %s\n",
767         kobject_name(kobj), kobj, __func__);
768    kfree(kset);
769}

这个函数取得kset空间指针并释放内存空间。
再来看kobj_sysfs_ops的定义,注意其作用,当用户读写kset->kobj的属性文件时,就会调用kset->kobj.ktype.sysfs_ops的show和store函数,即kobj_sysfs_ops的show和store函数:
703const struct sysfs_ops kobj_sysfs_ops = {
704    .show   = kobj_attr_show,
705    .store  = kobj_attr_store,
706};

kobj_attr_show函数定义如下:
678/* default kobject attribute operations */
679static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
680                  char *buf)
681{
682    struct kobj_attribute *kattr;
683    ssize_t ret = -EIO;
684
685    kattr = container_of(attr, struct kobj_attribute, attr);
686    if (kattr->show)
687        ret = kattr->show(kobj, kattr, buf);
688    return ret;
689}

该函数首先通过container_of宏取得包含指定attribute的kobj_attribute,然后调用kobj_attribute的show函数。
kobj_attr_store函数定义如下:
691static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
692                   const char *buf, size_t count)
693{
694    struct kobj_attribute *kattr;
695    ssize_t ret = -EIO;
696
697    kattr = container_of(attr, struct kobj_attribute, attr);
698    if (kattr->store)
699        ret = kattr->store(kobj, kattr, buf, count);
700    return ret;
701}

该函数首先通过container_of宏取得包含指定attribute的kobj_attribute,然后调用kobj_attribute的store函数。
至此,kset_create函数我们就分析完了,回到kset_create_and_add函数中,下面我们要分析的是kset_register函数,该函数定义如下:
708/**
709 * kset_register - initialize and add a kset.
710 * @k: kset.
711 */
712int kset_register(struct kset *k)
713{
714    int err;
715
716    if (!k)
717        return -EINVAL;
718
719    kset_init(k);
720    err = kobject_add_internal(&k->kobj);
721    if (err)
722        return err;
723    kobject_uevent(&k->kobj, KOBJ_ADD);
724    return 0;
725}

719行,调用kset_init初始化kset。
720行,调用kobject_add_internal将kobject注册到系统中,在/sys下建立目录结构和属性文件。该函数我们在前一篇博客<<Linux设备模型之kobject>>已经分析过,这里不再详细分析。
723行,调用kobject_uevent函数发送KOBJ_ADD事件。
667/**
668 * kset_init - initialize a kset for use
669 * @k: kset
670 */
671void kset_init(struct kset *k)
672{
673    kobject_init_internal(&k->kobj);
674    INIT_LIST_HEAD(&k->list);
675    spin_lock_init(&k->list_lock);
676}

673行,调用kobject_init_internal初始化kset->kobj。这个函数我们在上一篇博客<<Linux设备模型之kobject>>中已经分析过了。
kobject_uevent函数定义如下:
319/**
320 * kobject_uevent - notify userspace by sending an uevent
321 *
322 * @action: action that is happening
323 * @kobj: struct kobject that the action is happening to
324 *
325 * Returns 0 if kobject_uevent() is completed with success or the
326 * corresponding error when it fails.
327 */
328int kobject_uevent(struct kobject *kobj, enum kobject_action action)
329{
330    return kobject_uevent_env(kobj, action, NULL);
331}

这个函数直接调用了kobject_uevent_env函数,定义如下:
119/**
120 * kobject_uevent_env - send an uevent with environmental data
121 *
122 * @action: action that is happening
123 * @kobj: struct kobject that the action is happening to
124 * @envp_ext: pointer to environmental data
125 *
126 * Returns 0 if kobject_uevent_env() is completed with success or the
127 * corresponding error when it fails.
128 */
129int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
130               char *envp_ext[])
131{
132    struct kobj_uevent_env *env;
133    const char *action_string = kobject_actions[action];
134    const char *devpath = NULL;
135    const char *subsystem;
136    struct kobject *top_kobj;
137    struct kset *kset;
138    const struct kset_uevent_ops *uevent_ops;
139    u64 seq;
140    int i = 0;
141    int retval = 0;
142#ifdef CONFIG_NET
143    struct uevent_sock *ue_sk;
144#endif
145
146    pr_debug("kobject: '%s' (%p): %s\n",
147         kobject_name(kobj), kobj, __func__);
148
149    /* search the kset we belong to */
150    top_kobj = kobj;
151    while (!top_kobj->kset && top_kobj->parent)
152        top_kobj = top_kobj->parent;
153
154    if (!top_kobj->kset) {
155        pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
156             "without kset!\n", kobject_name(kobj), kobj,
157             __func__);
158        return -EINVAL;
159    }
160
161    kset = top_kobj->kset;
162    uevent_ops = kset->uevent_ops;
163
164    /* skip the event, if uevent_suppress is set*/
165    if (kobj->uevent_suppress) {
166        pr_debug("kobject: '%s' (%p): %s: uevent_suppress "
167                 "caused the event to drop!\n",
168                 kobject_name(kobj), kobj, __func__);
169        return 0;
170    }
171    /* skip the event, if the filter returns zero. */
172    if (uevent_ops && uevent_ops->filter)
173        if (!uevent_ops->filter(kset, kobj)) {
174            pr_debug("kobject: '%s' (%p): %s: filter function "
175                 "caused the event to drop!\n",
176                 kobject_name(kobj), kobj, __func__);
177            return 0;
178        }
179
180    /* originating subsystem */
181    if (uevent_ops && uevent_ops->name)
182        subsystem = uevent_ops->name(kset, kobj);
183    else
184        subsystem = kobject_name(&kset->kobj);
185    if (!subsystem) {
186        pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
187             "event to drop!\n", kobject_name(kobj), kobj,
188             __func__);
189        return 0;
190    }
191
192    /* environment buffer */
193    env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
194    if (!env)
195        return -ENOMEM;
196
197    /* complete object path */
198    devpath = kobject_get_path(kobj, GFP_KERNEL);
199    if (!devpath) {
200        retval = -ENOENT;
201        goto exit;
202    }
203
204    /* default keys */
205    retval = add_uevent_var(env, "ACTION=%s", action_string);
206    if (retval)
207        goto exit;
208    retval = add_uevent_var(env, "DEVPATH=%s", devpath);
209    if (retval)
210        goto exit;
211    retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
212    if (retval)
213        goto exit;
214
215    /* keys passed in from the caller */
216    if (envp_ext) {
217        for (i = 0; envp_ext[i]; i++) {
218            retval = add_uevent_var(env, "%s", envp_ext[i]);
219            if (retval)
220                goto exit;
221        }
222    }
223
224    /* let the kset specific function add its stuff */
225    if (uevent_ops && uevent_ops->uevent) {
226        retval = uevent_ops->uevent(kset, kobj, env);
227        if (retval) {
228            pr_debug("kobject: '%s' (%p): %s: uevent() returned "
229                 "%d\n", kobject_name(kobj), kobj,
230                 __func__, retval);
231            goto exit;
232        }
233    }
234
235    /*
236     * Mark "add" and "remove" events in the object to ensure proper
237     * events to userspace during automatic cleanup. If the object did
238     * send an "add" event, "remove" will automatically generated by
239     * the core, if not already done by the caller.
240     */
241    if (action == KOBJ_ADD)
242        kobj->state_add_uevent_sent = 1;
243    else if (action == KOBJ_REMOVE)
244        kobj->state_remove_uevent_sent = 1;
245
246    /* we will send an event, so request a new sequence number */
247    spin_lock(&sequence_lock);
248    seq = ++uevent_seqnum;
249    spin_unlock(&sequence_lock);
250    retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
251    if (retval)
252        goto exit;
253
254#if defined(CONFIG_NET)
255    /* send netlink message */
256    mutex_lock(&uevent_sock_mutex);
257    list_for_each_entry(ue_sk, &uevent_sock_list, list) {
258        struct sock *uevent_sock = ue_sk->sk;
259        struct sk_buff *skb;
260        size_t len;
261
262        /* allocate message with the maximum possible size */
263        len = strlen(action_string) + strlen(devpath) + 2;
264        skb = alloc_skb(len + env->buflen, GFP_KERNEL);
265        if (skb) {
266            char *scratch;
267
268            /* add header */
269            scratch = skb_put(skb, len);
270            sprintf(scratch, "%s@%s", action_string, devpath);
271
272            /* copy keys to our continuous event payload buffer */
273            for (i = 0; i < env->envp_idx; i++) {
274                len = strlen(env->envp[i]) + 1;
275                scratch = skb_put(skb, len);
276                strcpy(scratch, env->envp[i]);
277            }
278
279            NETLINK_CB(skb).dst_group = 1;
280            retval = netlink_broadcast_filtered(uevent_sock, skb,
281                                0, 1, GFP_KERNEL,
282                                kobj_bcast_filter,
283                                kobj);
284            /* ENOBUFS should be handled in userspace */
285            if (retval == -ENOBUFS)
286                retval = 0;
287        } else
288            retval = -ENOMEM;
289    }
290    mutex_unlock(&uevent_sock_mutex);
291#endif
292
293    /* call uevent_helper, usually only enabled during early boot */
294    if (uevent_helper[0] && !kobj_usermode_filter(kobj)) {
295        char *argv [3];
296
297        argv [0] = uevent_helper;
298        argv [1] = (char *)subsystem;
299        argv [2] = NULL;
300        retval = add_uevent_var(env, "HOME=/");
301        if (retval)
302            goto exit;
303        retval = add_uevent_var(env,
304                    "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
305        if (retval)
306            goto exit;
307
308        retval = call_usermodehelper(argv[0], argv,
309                         env->envp, UMH_WAIT_EXEC);
310    }
311
312exit:
313    kfree(devpath);
314    kfree(env);
315    return retval;
316}

133由参数action取得代表事件类型的字符串。kobject_actions定义如下:
40/*
41 * The actions here must match the index to the string array
42 * in lib/kobject_uevent.c
43 *
44 * Do not add new actions here without checking with the driver-core
45 * maintainers. Action strings are not meant to express subsystem
46 * or device specific properties. In most cases you want to send a
47 * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
48 * specific variables added to the event environment.
49 */
50enum kobject_action {
51    KOBJ_ADD,
52    KOBJ_REMOVE,
53    KOBJ_CHANGE,
54    KOBJ_MOVE,
55    KOBJ_ONLINE,
56    KOBJ_OFFLINE,
57    KOBJ_MAX
58};
42/* the strings here must match the enum in include/linux/kobject.h */
43static const char *kobject_actions[] = {
44    [KOBJ_ADD] =        "add",
45    [KOBJ_REMOVE] =     "remove",
46    [KOBJ_CHANGE] =     "change",
47    [KOBJ_MOVE] =       "move",
48    [KOBJ_ONLINE] =     "online",
49    [KOBJ_OFFLINE] =    "offline",
50};

149 - 162行,因为只有kset才包含处理uevent的函数,即kset.uevent_ops,所以这里查找kobj所属的kset,如果kobj->kset不存在,就沿着kobj->parent向上查找,直到找到一个不为空的kset为止。如果确实没有找到kset,则退出。
165 - 170行,如果kobj->uevent_suppress的值为1,表示禁止发出uevent事件,退出。
172 - 178行,如果uevent_ops不为空,并且实现了uevent_ops->filter,则执行uevent_ops->filter,如果uevent_ops->filter返回值为0,表示这个uevent被过滤了,退出。
181 - 190行,如果uevent_ops不为空,并且实现了uevent_ops->name,则通过uevent_ops->name获得子系统名,如果uevent_ops为空,或者没有实现uevent_ops->name,则以kset->kobj的名字作为子系统名。
193行,创建kobj_uevent_env结构体变量env,用来保存环境变量。
198行,通过调用kobject_get_path函数取得kobj在/sys系统中的路径,保存在devpath变量中。
205 - 213行,通过调用add_uevent_var函数将事件名,kobj路径和子系统名加入到环境变量env中。
216 - 222行,如果有通过参数传递的环境变量,也调用add_uevent_var函数加入到环境变量env中。
225 - 233行,如果uevent_ops不为空,并且实现了uevent_ops->uevent函数,则调用uevent_ops->uevent。
241 - 244行,如果要发送的事件是KOBJ_ADD或KOBJ_REMOVE,则相应将kobj->state_add_uevent_sent或kobj->state_remove_uevent_sent置为1。
247 - 252行,将发送事件序列数加1,添加到环境变量env中。
254 - 291行,条件编译部分我们不分析。
294行,先来看uevent_helper的定义:
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
#define UEVENT_HELPER_PATH_LEN      256
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
所以uevent_helper就是"/sbin/hotplug"。
300 - 306行,将HOME和PATH加入环境变量env中。
308 - 309行,执行用户空间的/sbin/hotplug程序,传递环境变量为env。
至此, kobject_uevent_env -> kobject_uevent -> kset_register -> kset_create_and_add函数就分析完了,kset被创建和注册到系统中。
 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值