linux内核kobject的一些信息

1. kobject定义的头文件

    #include

2. kobject所能处理的任务和它所支持的代码

    a. 对象的引用记数。

    b. sysfs表述

    c. 数据结构关联

    d. 热插拔事件处理

3. 如何通过一个kobject指针得到包函它的结构体指针

   struct cdev

   {

            struct kobject    kobj;

            struct module    *owner;

            struct file_operations    *ops;

            struct list_head    list;

            dev_t    dev;

            unsigned int    count;

   }

   可以使用 container_of()宏定义将包含在cdev结构体中的、名为kp的kobject结构体指针经过转换得到

   包含kp的结构体指针。如下:

   struct cdev *device  =  container_of( kp,  struct cdev,  kobj );

4. kobject的初始化

    a. 使用memset()将kobject清零

    b. 调用kobject_init(),设置结构体内的一些成员

         void kobject_init(struct kobject  *kobj);

    c. 设置kobject的名字

        int kobject_set_name(struct kobject *kobj, const char *format, ...);

    d. 其它成员:ktype, kset, parent.

5. 为包含kobject的结构体进行引用记数

     kobject的一个重要函数是为包含它结构体设置引用记数。只要对象的引用记数存在,对象(以及支持它的代码)就必须继续存在。底层控制kobject的引用计数函数有:

     struct kobject *kobject_get(struct kobject *kobj); // 增加引用计数

     struct kobject *kobject_put(struct kobject *kobj); // 减少引用计数

6. kobject引用计数为零时的异步通知

    当kobject的引用计数为零时,要只能异步地通知系统将其释放。通知是使用kobject的release方法实现的。

    该方法通常的原型如下:

    void my_object_release(struct kobject *kobj)

    {

              struct my_object  *mine = container_of(kobj, struct my_object, kobj);

              /********    对该对象执行其它的清理工作,然后....     ********/

              kfree(mine);

    }

 

    kobject的release()方法并未包含在kobject自身内,而在包含在与kobject相关联的一种称为ktype的kobj_type数据结构中。

    如下:

    struct kobj_type

    {

           void (*release)(struct kobject *);

          struct sysfs_ops *sysfs_ops;

          struct attribute **default_attrs;

    }

    每个kobject都需要一个与之对应的kobj_type结构。而这个结构体的指针可以通过如下宏得到。

    struct kobj_type *get_ktype(struct kobject *kobj);

7. kobject的层次结构、kset和子系统

    7.1 层次结构

           通常,内核用kobjet将各个对象连接起来组成一个分层的结构体系,从而与模型化的子系统相匹配。

    有两种独立的机制用于连接:parent指针和kset

           在kobject结构的成员parent中,保存了另外一个kobject结构的指针,这个结构表示了分成层结构中的上一层节点。

    比如一个kobject结构中表示了一个USB设备,它的parent指针可能指向了表示USB集线器的对象,而USB对象是

   插在USB集线器上的。

           对parent指针最重要的用途是在sysfs分层结构中定位对象。

    7.2 kset

          kset是相同类型结构的kobject的集合。因此kset的主要功能是包容。我们可以认为它是kobject的顶层容器类。在每个kset内

    部包含了自己的kobject.

         kset总是在sysfs中出现。一旦设置了kset并将它添加到系统中,将在sysfs中创建一个目录。而kobject不必在sysfs中表示,

    但kset中的每个kobject成员都将在sysfs中得到表述。

         kset还包含了一个子系统指针(称之为subsys).

         a.将kobject添加到kset中

             创建一个对象时,通常要把kobject添加到kset中去。这个过程分成两部。先把kobject的kset成员指向目的kset,然后将

         kobject传递给下面的函数。

             int kobject_add(struct kobject *kobj);

         也可以使用如下函数,它是kobject_init()和kobjdect_add()的简单组合

             extern int kobject_register(struct kobject *kobj);

         b.从kset中删除kobject

            在某些时候,可能不得不把kobject从kset中删除,以清除引用计数。可使用如下函数。

            void kobject_del(struct kobject *kobj);

            也可以使用kobject_unregister()函数,它是kobject_del()和kobjdect_put()的组合

         c.kset上的操作

            kset和kobject类似,它拥有初如化和设置接口。下面是这些函数

            void kset_init(struct kset *kset);

            int  kset_add(struct kset *kset);

            int  kset_register(struct kset *kset);

            void kset_unregister(struct kset *kset);

         d.kset 引用计数

            struct kset *kset_get(struct kset *kset);

            void kset_put(struct kset *kset);

         e.设置kset 的名字

            一个kset也拥有名字,它保存在内嵌的kobject中.因此,如果我们有一个名为my_kset的kset,可以使用下面的函数设置名字

            kobject_set_name(&my_kset->kobj, "The name");

    7.3 子系统

           子系统通常显示在sysfs分层结构中的顶层.内核中的子系统包括block_subsys(对块设备来说是/sys/block)、devices_subsys(/sys/devices,设备分层结构的核心)以及内核所知晓的用于各种总线的子系统。下面的简单结构表示了一个子系统。

            struct subsystem

            {

                      struct kset kset;

                      struct rw_semaphore rwsem;

            }

           一个子系统其实是对kset和一个信号量的封装。每一个kset都必须属于一个子系统。子系统的成员帮助内核在分层结构中定位kset。在kset结构体中包含了subsys指针,因此通过kset结构,可以找到包含kset的每一个子系统。但我们无法直接从subsystem结构中找到子系统包含的多个kset。

           通常使用下面的宏申明subsystem.该宏用name追加_subsys作为结构名而创建subsystem结构

           decl_subsys(name,  struct kobj_type *type,  struct kset_hotplug_ops  *hotplug_ops);

           子系统拥有一个设置和销毁的函数列表:

            void subsystem_init(struct subsystem *subsys);

            int subsystem_register(struct subsystem *subsys);

            void subsystem_unregister(struct subsystem *subsys);

            struct subsystem *subsys_get(struct subsystem *subsys);

            void subsys_put(struct subsystem *subsys);

8.低层sysfs操作

   kobject是隐藏在sysfs虚拟文件系统后机制,对于sysfs中的每个目录,内核中都会存在一个对应的kobject.每个kobject都输出一个或者多个属性,它们在kobject的sysfs目录中表线为文件,其中的内容由内核生成.只要调用kobject_add()函数,就能在sysfs中显示kobject.

   kobject在sysfs中入口始终是一个目录.分配给kboject的名字(使用kobjcet_set_name()函数)是sysfs中的目录名.这样,处于sysfs分层结构中相同部分的kobject必须有唯一的名字.sysfs入口在目录中 的位置对应kobject的parent指针.

  8.1. kobject的默认属性

          当创建kobject的时候,都会给kobject一系列默认属性.这些属性保存在kobj_type结构体中.下面是该结构体成员.

                        struct kobj_type

                        {

                                     void (*release)(struct kobject *);

                                     struct sysfs_ops *sysfs_ops;

                                     struct attribute **default_attrs;

                        }

          default_attrs成员保存了属性列表,用于创建该类型的每一个kobject,sysfs_ops提供了实现这些属性的方法.default_attrs指向了一个包函attribute结构数组的指针:

                        struct attribute

                        {

                                     char *name; // 属性的名字(在kobject的sysfs目录中显示)

                                     struct module *owner; // 指向模块的指针

                                     mode_t mode; // 属性保护位,通常为S_IRUGO

                        }

          default_attrs数组说明了kobject都有些什么属性,但是没有告诉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, char *buffer, size_t size);

                        }

          当用户空间读取一个属性时,内核会使用指向kobject的指针和正确的属性结构来调用SHOW方法.该方法会将指定的值编码后放入缓冲区.

  8.2. kobject非默认属性

          我们可以根据需要对kobject内的属性进行添加和删除.往kobject中添加属性的函数:

          int sysfs_create_file(struct kobject *kobj, struct attribute *attr);

          删除kobject中的属性的函数:

          int sysfs_remove_file(struct kobject *kobj, struct attribute *attr);

  8.3. kobject的二进制属性

         当在用户空间和设备之间传输不可改变的数据时,可能需要用到二进制属性.用于描述二进制属性的结构体如下:

                        struct bin_attribute

                        {

                                     struct attribute attr;

                                     size_t size;

                                     ssize_t (*read)(struct kobject *kobj, char *buffer, loff_t pos, size_t size);

                                     ssize_t (*store)(struct kobject *kobj,  char *buffer, loff_t pos, size_t size);

                        }

         创建二进制属性的函数:

          int sysfs_create_bin_file(struct kobject *kobj, struct attribute *attr);

         删除二进制属性的函数:

          int sysfs_remove_bin_file(struct kobject *kobj, struct attribute *attr);

9.热插拔事件的产生

   一个热插拔事件是从内核空间发送到用户空间的通知,它表明系统配置出现了变化.无论kobject是被创建还是被删除都会产生这种事件.热插拔事件会导致对/sbin/hotplug程序的调用.该程序通过加载驱动程序,创建设备节点,挂载分区,或者其它正确的动作来响应事件.当我们把kobject传递给kobject_add()或者kobject_del()时,才会真正产生这些事件.

   对热插拔的实际控制,是由保存在kset_hotplug_ops结构中的函数完成的:

                        struct kset_hotplug_ops

                        {

                                     int (*filter)(struct kset *kset, struct kobject *kobj);

                                     char *(*name)(struct kset *kset, struct kobject *kobj);

                                     int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp, int num_envp, char *buffer, int buffer_size);

                        }

   我们可以在kset结构的hotplug_ops成员中发现指向这个结构的结构体指针.

   无论什么时候,当内核要为指定的kobject产生事件时,都要调用filter函数.如果filter返回0,则不产生事件.因此该函数给kset一个机会,用于决定是否向用户空间传递特定的事件.

   使用该函数的一个例子是块设备子系统.在该子系统中,至少使用了3种类型的kobject,它们是磁盘,分区和请求队列.用户空间将向磁盘或者分区的添加产生响应,但通常响应请求队列的变化.因此filter()函数只允许为kobject产生磁盘和分区的事件.请看下面代码:

   static int block_hotplug_filter(struct kset *kset, struct kobject *kobj)  

   {

           struct kobj_type *ktype = get_ktype(kboj);

           return( (ktype==&ktype_block)||(ktype==&ktype_part) );

   }

你可能感兴趣的:(linux学习)