精华内容
下载资源
问答
  • 关于kset_create_and_add和kobject_init_and_add的流程图解释及关系总结。
  • kobject

    千次阅读 2016-05-26 22:57:42
     在linux的驱动表示中,主要有三个基本的结构,分别是kobject,kset,ktype.Kobject,kset,kypte这三个结构是设备模型中的下层架构。模型中的每一个元素都对应一个kobject.kset和ktype可以看成是kobje

    核心结论:

        1、sys 目录下的层次结构依赖于 kobject.parent ,未指定parent时,默认使用 kobject.kset.kobject 作为 parent,如果都没有,就出现在 /sys 目录下。

        2、该 kobject 目录下的属性文件依赖于 kobject.ktype


        在linux的驱动表示中,主要有三个基本的结构,分别是kobject,kset,ktype.Kobject,kset,kypte这三个结构是设备模型中的下层架构。模型中的每一个元素都对应一个kobject.kset和ktype可以看成是kobject在层次结构与属性结构方面的扩充。将三者之间的关系用图的方示描述如下:


        如上图所示:我们知道。在sysfs中每一个目录都对应一个kobject.这些kobject都有自己的parent。在没有指定parent的情况下,都会指向它所属的kset->object。其次,kset也内嵌了kobject.这个kobject又可以指它上一级的parent。就这样。构成了一个空间上面的层次关系。
        其实,每个对象都有属性。例如,电源管理,执插拨事性管理等等。因为大部份的同类设备都有相同的属性,因此将这个属性隔离开来,存放在ktype中。这样就可以灵活的管理了.记得在分析sysfs的时候。对于sysfs中的普通文件读写操作都是由kobject->ktype->sysfs_ops来完成的.

    kobject

    truct kobject {  
        const char      *name;         //名字  
        struct list_head    entry;         //连接到kset建立层次结构  
        struct kobject      *parent;       //指向父节点,面向对象的层次架构  
        struct kset     *kset;             //指向所属的kset  
        struct kobj_type    *ktype;        //属性文件  
        struct sysfs_dirent *sd;  
        struct kref     kref;          //引用计数  
        unsigned int state_initialized:1;      //初始化状态...  
        unsigned int state_in_sysfs:1;  
        unsigned int state_add_uevent_sent:1;  
        unsigned int state_remove_uevent_sent:1;  
        unsigned int uevent_suppress:1;  
    };

        在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录。从面向对象的角度来说,kobject可以看作是所有设备对象的基类,因为C语言并没有面向对象的语法,所以一般是把kobject内嵌到其他结构体里来实现类似的作用,这里的其他结构体可以看作是kobject的派生类。Kobject为Linux设备模型提供了很多有用的功能,比如引用计数,接口抽象,父子关系等等,所以,在内核中,没有用kobject直接定义的变量,kobject只是作为一个抽象的基类而存在。一般都是将kobject嵌入到另一个结构,这个结构就可以看做是kobject的一个子类。而kobject的子类会比较关心kobject的属性和方法。
        内核里的设备之间是以树状形式组织的,在这种组织架构里比较靠上层的节点可以看作是下层节点的父节点,反映到sysfs里就是上级目录和下级目录之间的关系,在内核里,正是kobject帮助我们实现这种父子关系。在kobject的定义里,name表示的是kobject在sysfs中的名字;指针parent用来指向kobject的父对象;Kref大家应该比较熟悉了,kobject通过它来实现引用计数;Kset指针用来指向这个kobject所属的kset;对于ktype,如果只是望文生义的话,应该是用来描述kobject的类型信息。

    struct kref//引用计数  
    {  
        atomic_t refcount;  
    }
    kobject的作用:

        1、sysfs 表述:在 sysfs 中出现的每个对象都对应一个 kobject, 它和内核交互来创建它的可见表述。
        2、数据结构关联:整体来看, 设备模型是一个极端复杂的数据结构,通过其间的大量链接而构成一个多层次的体系结构。kobject 实现了该结构并将其聚合在一起。
        3、热插拔事件处理 :kobject 子系统将产生的热插拔事件通知用户空间。

        一个kobject对自身并不感兴趣,它存在的意义在于把高级对象连接到设备模型上。因此内核代码很少(甚至不知道)创建一个单独的 kobject;而kobject 被用来控制对大型域(domain)相关对象的访问,所以kobject 被嵌入到其他结构中。kobject 可被看作一个最顶层的基类,其他类都它的派生产物。 kobject 实现了一系列方法,对自身并没有特殊作用,而对其他对象却非常有效。

        对于给定的kobject指针,可使用container_of宏得到包含它的结构体的指针

    kobject相关操作函数:

    1、初始化---kobject_init

    void kobject_init(struct kobject *kobj, struct kobj_type *ktype)  
    {  
        char *err_str;  
      
        if (!kobj) {  
            err_str = "invalid kobject pointer!";  
            goto error;  
        }  
        if (!ktype) {  
            err_str = "must have a ktype to be initialized properly!\n";  
            goto error;  
        }  
        if (kobj->state_initialized) {  
            /* do not error out as sometimes we can recover */  
            printk(KERN_ERR "kobject (%p): tried to init an initialized "  
                   "object, something is seriously wrong.\n", kobj);  
            dump_stack();  
        }  
      
        kobject_init_internal(kobj);//进行主要的成员变量初始化  
        kobj->ktype = ktype;  //<span style="color: rgb(0, 130, 0); font-family: Consolas, 'Courier New', Courier, mono, serif; line-height: 18px; text-align: left; background-color: rgb(248, 248, 248); ">关联</span>这个kobject类型  
        return;  
      
    error:  
        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);  
        dump_stack();  
    } 
    static void kobject_init_internal(struct kobject *kobj)  
    {  
        if (!kobj)  
            return;  
        kref_init(&kobj->kref);//初始化引用计数为1  
        INIT_LIST_HEAD(&kobj->entry);//prev和next都指向自己   
        kobj->state_in_sysfs = 0;  
        kobj->state_add_uevent_sent = 0;  
        kobj->state_remove_uevent_sent = 0;  
        kobj->state_initialized = 1;  
    } 
    2、将kobject加入到分层结构-----kobject_add
    int kobject_add(struct kobject *kobj, struct kobject *parent,  
        const char *fmt, ...)  
      
    va_list args;  
    int retval;  
      
    if (!kobj)  
        return -EINVAL;  
      
    if (!kobj->state_initialized) {  
        printk(KERN_ERR "kobject '%s' (%p): tried to add an "  
               "uninitialized object, something is seriously wrong.\n",  
               kobject_name(kobj), kobj);  
        dump_stack();  
        return -EINVAL;  
    }  
    va_start(args, fmt);  
    retval = kobject_add_varg(kobj, parent, fmt, args);//主要的add操作  
    va_end(args);  
      
    return retval; </span>
    kobject_add_varg():
    static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,  
                    const char *fmt, va_list vargs)  
    {  
        int retval;  
      
        retval = kobject_set_name_vargs(kobj, fmt, vargs);//设置kobject的名字。即kobject的name成员  
        if (retval) {  
            printk(KERN_ERR "kobject: can not set name properly!\n");  
            return retval;  
        }  
        kobj->parent = parent;  //设置kobject的parent  
        return kobject_add_internal(kobj);//在sysfs中添加kobjcet信息  
    }  </span>
    static int kobject_add_internal(struct kobject *kobj)  
    {  
        int error = 0;  
        struct kobject *parent;  
      
        if (!kobj)  
            return -ENOENT;  
      
        if (!kobj->name || !kobj->name[0]) { //如果kobject的名字为空.退出  
            WARN(1, "kobject: (%p): attempted to be registered with empty "  
                 "name!\n", kobj);  
            return -EINVAL;  
        }  
      
        parent = kobject_get(kobj->parent);//如果parent为真,则增加kobj->kref计数,也就是父节点的引用计数    
      
        /* join kset if set, use it as parent if we do not already have one */  
        if (kobj->kset) {   
            if (!parent)  
                parent = kobject_get(&kobj->kset->kobj);//如果kobj-parent父节点为NULL那么就用kobj->kset->kobj作其父节点,并增加其引用计数    
            kobj_kset_join(kobj);//把kobj的entry成员添加到kobj->kset>list的尾部,现在的层次就是/kobj->kset->list指向kobj->parent ->parent 指向kset->kobj   
            kobj->parent = parent;  
        }  
      
        pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",  
             kobject_name(kobj), kobj, __func__,  
             parent ? kobject_name(parent) : "<NULL>",  
             kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");  
      
        error = create_dir(kobj); //利用kobj创建目录和属性文件,其中会判断,如果parent为NULL那么就在sysfs_root下创建   
        if (error) {  //如果创建失败。减少相关的引用计数  
            kobj_kset_leave(kobj);  
            kobject_put(parent);  
            kobj->parent = NULL;  
      
            /* be noisy on error issues */  
            if (error == -EEXIST)  
                printk(KERN_ERR "%s failed for %s with "  
                       "-EEXIST, don't try to register things with "  
                       "the same name in the same directory.\n",  
                       __func__, kobject_name(kobj));  
            else  
                printk(KERN_ERR "%s failed for %s (%d)\n",  
                       __func__, kobject_name(kobj), error);  
            dump_stack();  
        } else  
            kobj->state_in_sysfs = 1; //如果创建成功。将state_in_sysfs建为1。表示该object已经在sysfs中了  
      
        return error;  
    } 
    static int create_dir(struct kobject *kobj)  
    {  
        int error = 0;  
        if (kobject_name(kobj)) {  
            error = sysfs_create_dir(kobj);//为kobject创建目录  
            if (!error) {  
                error = populate_dir(kobj);  //为kobject->ktype中的属性创建文件  
                if (error)  
                    sysfs_remove_dir(kobj);  
            }  
        }  
        return error;  
    }  </span>
    我们先看一下kobject所表示的目录创建过程。这是在sysfs_create_dir()中完成的
    int sysfs_create_dir(struct kobject * kobj)  
    {  
        enum kobj_ns_type type;  
        struct sysfs_dirent *parent_sd, *sd;  
        const void *ns = NULL;  
        int error = 0;  
      
        BUG_ON(!kobj);  
      
        /* 
        如果kobject的parnet存在。就在目录点的目录下创建这个目录。 
        如果没有父结点不存在,就在/sys下面创建结点 
        */  
        if (kobj->parent)  
            parent_sd = kobj->parent->sd;  
        else  
            parent_sd = &sysfs_root;  
      
        if (sysfs_ns_type(parent_sd))  
            ns = kobj->ktype->namespace(kobj);  
        type = sysfs_read_ns_type(kobj);  
      
         //在sysfs中创建目录  
        error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);  
        if (!error)  
            kobj->sd = sd;  
        return error;  
    } </span>
    接着看为kobject->ktype中的属性创建文件。这是在populate_dir()中完成的
    static int populate_dir(struct kobject *kobj)  
    {  
        struct kobj_type *t = get_ktype(kobj);  
        struct attribute *attr;  
        int error = 0;  
        int i;  
      
        if (t && t->default_attrs) {  
            for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {//遍历ktype中的属性,为其建立文  
                error = sysfs_create_file(kobj, attr); //注意:文件的操作最后都会回溯到ktype->sysfs_ops的show和store这两个函数中.   
                if (error)  
                    break;  
            }  
        }  
        return error;  
    }
    另外一个常用的函数就是kobject_init_and_add,直接初始化并进行添加操作

    int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,  
                 struct kobject *parent, const char *fmt, ...)  
    {  
        va_list args;  
        int retval;  
      
        kobject_init(kobj, ktype);  
      
        va_start(args, fmt);  
        retval = kobject_add_varg(kobj, parent, fmt, args);  
        va_end(args);  
      
        return retval;  
    }
    这里面调用的也就是init和add操作了。

    还有一个kobj的删除函数:

    void kobject_del(struct kobject *kobj)  
    {  
        if (!kobj)  
            return;  
      
        sysfs_remove_dir(kobj);//删除sys目录相关文件  
        kobj->state_in_sysfs = 0;  
        kobj_kset_leave(kobj);//kset链表中删除kobj成员  
        kobject_put(kobj->parent);//减少parent计数  
        kobj->parent = NULL;  
    } 


    基于 linux2.6.32.2 的驱动

    #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("David Xie"); 
    MODULE_LICENSE("Dual BSD/GPL");
    
    /*声明release、show、store函数*/
    
    void obj_test_release(struct kobject *kobject); 
    ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
    ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
    
    /*对应于kobject的目录下的一个文件,Name成员就是文件名*/  
    struct attribute test_attr = { 
    	.name = "kobj_config", 
    	.mode = S_IRWXUGO, 
    }; 
      
    static struct attribute *def_attrs[] = { 
    	&test_attr, 
    	NULL, 
    }; 
      
    //kobject对象的操作 
    struct sysfs_ops obj_test_sysops = 
    { 
    	.show = kobj_test_show, 
    	.store = kobj_test_store, 
    }; 
     
    /*定义kobject对象的一些属性及对应的操作*/ 
    struct kobj_type ktype =  
    { 
    	.release = obj_test_release, 
    	.sysfs_ops=&obj_test_sysops, 
    	.default_attrs=def_attrs, 
    };
    
    /*release方法释放该kobject对象*/  
    void obj_test_release(struct kobject *kobject) 
    { 
        printk("eric_test: release .\n"); 
    }
    
    /*当读文件时执行的操作*/ 
    ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
    { 
    	printk("have show.\n"); 
    	printk("attrname:%s.\n", attr->name); 
    	sprintf(buf,"%s\n",attr->name); 
    	return strlen(attr->name)+2; 
    }
    
    /*当写文件时执行的操作*/  
    ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
    { 
    	printk("havestore\n"); 
    	printk("write: %s\n",buf); 
    	return count; 
    } 
      
    struct kobject kobj;//声明kobject对象
     
    static int kobj_test_init(void) 
    { 
    	printk("kboject test init.\n"); 
    	kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");//初始化kobject对象kobj,并将其注册到linux系统
    	//kobject_init(&kobj);
    	//kobj.ktype = &ktype;
    	//kobj.parent = NULL;
    	//kobject_set_name(&kobj, "kobject_test");
    	//err = kobject_add(&kobj);
    	return 0; 
    } 
      
    static void kobj_test_exit(void) 
    { 
    	printk("kobject test exit.\n"); 
    	kobject_del(&kobj); 
    } 
      
    module_init(kobj_test_init);
    module_exit(kobj_test_exit);
    
    




        












    展开全文
  • Kobject

    2018-12-05 14:54:06
    1、Kobject  1、定义在linux/kobject.h下面。  2、里面包含各种对象的基本单元,会提供一些功能型服务:对象引用计数、维护对象链表,对象上锁,对用户空间的表示。(对象是指类、总线、设备、驱动等结构体定义...

    1、Kobject

           1、定义在linux/kobject.h下面。

           2、里面包含各种对象的基本单元,会提供一些功能型服务:对象引用计数、维护对象链表,对象上锁,对用户空间的表示。(对象是指类、总线、设备、驱动等结构体定义的变量)。在Linux内核里,kobject是组成Linux设备模型的基础,一个kobject对应sysfs里的一个目录。从面向对象的角度来说,kobject可以看作是所有设备对象的基类,因为C语言并没有面向对象的语法,所以一般是把kobject内嵌到其他结构体里来实现类似的作用,这里的其他结构体可以看作是kobject的派生类

    struct kobject {
    	const char		*name;
    	struct list_head	entry;
    	struct kobject		*parent;
    	struct kset		*kset;
    	struct kobj_type	*ktype;
    	struct sysfs_dirent	*sd;
    	struct kref		kref;
    	unsigned int state_initialized:1;
    	unsigned int state_in_sysfs:1;
    	unsigned int state_add_uevent_sent:1;
    	unsigned int state_remove_uevent_sent:1;
    	unsigned int uevent_suppress:1;
    };

    name 就是这个对象的名称

    entry是维护对象链表,可以和其他kobject连接起来

    parent 实现kobject进行上下层联系

     kref  kref.h

    struct kref//引用计数  
    {  
        atomic_t refcount;  
    }
    

                        atomic_t 定义的变量是原子变量,进行的操作是原子操作,不可以被分割。

                        refcount 引用计数,被人用了就加一,少一个用的就减一,减到零后会被release掉。

    2、kobj_type

    简称ktype,每一个kobject都需要绑定一个ktype来提供相应功能

    struct kobj_type {
    	void (*release)(struct kobject *kobj);
    	const struct sysfs_ops *sysfs_ops;
    	struct attribute **default_attrs;
    	const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
    	const void *(*namespace)(struct kobject *kobj);
    };
    

    release检测引用计数,如果是0,那么把对象整个占用的内存释放掉,不是零,把计数-1;

    sysfs_ops,提供该对象在sysfs中的操作方法(show和store)linux/sysfs.h

    
    struct sysfs_ops {
    	ssize_t	(*show)(struct kobject *, struct attribute *,char *);
    	ssize_t	(*store)(struct kobject *,struct attribute *,const char *, size_t);
    };

    attribute属性,sysfs下面的文件形式存在的属性,就是应用接口

    3、kset

    struct kset {
    	struct list_head list;
    	spinlock_t list_lock;
    	struct kobject kobj;
    	const struct kset_uevent_ops *uevent_ops;
    };

                      list_head list链表,用于和其他的链接

                      spinlock_t list_lock; 对象上锁

         kset的主要作用是做顶层kobject的容器类
         kset的主要目的是将各个kobject(代表着各个对象)组织出目录层次架构
         可以认为kset就是为了在sysfs中弄出目录,从而让设备驱动模型中的多个对象能够有层次有逻辑性的组织在一起

    4、总结

        1、sys 目录下的层次结构依赖于 kobject.parent ,未指定parent时,默认使用 kobject.kset.kobject 作为 parent,如果都没有,就出现在 /sys 目录下。

        2、该 kobject 目录下的属性文件依赖于 kobject.ktype

        3、设备驱动模型中的各种对象其内部都会包含一个kobject

        4、kobject是属于kset的只不过内部有一个指针又指向kset

    5、三者都是为了实现sysfs下面的东西,kobject是一个基础,kobj——type是目录里的文件及其操作方法,kset是构建目录层次结构。

    6、什么是绑定,什么是包含

          一个结构体中如果另一个结构体就存在这个结构体中就叫做包含

    struct list_head	entry;
    struct kref		kref;

        如果是以结构体指针的形式存在,就叫做绑定

    struct kobject		*parent;
    struct kset		*kset;
    struct kobj_type	*ktype;
    struct sysfs_dirent	*sd;

     

    展开全文
  • 从v2.6开始linux引入了统一的设备模型,用kobject数据结构来描述设备。有了kobject,设备间的拓扑关系就一目了然了,它为设备管理带来了很大的便利。最近学习到kobject_create_and_add(),通过对这个函数的学习,...

    一、引言

    从v2.6开始linux引入了统一的设备模型,用kobject数据结构来描述设备。有了kobject,设备间的拓扑关系就一目了然了,它为设备管理带来了很大的便利。最近学习到kobject_create_and_add(),通过对这个函数的学习,可以全面细致地了解到kobject。p.s.本文相关代码基于linux 5.4.74。内容有点多,读不下去请跳转至文章末尾。

    二、kobject相关数据结构

    首先,简单了解下kobject相关的数据结构。
    kobject结构体如下所示:

    //代码路径kernel5.4/include/linux/kobject.h
    struct kobject {
    	const char		*name; //name指针指向kobject的名称
    	struct list_head	entry;
    	struct kobject		*parent; 
    	struct kset		*kset;
    	struct kobj_type	*ktype;
    	struct kernfs_node	*sd; /* sysfs directory entry */
    	struct kref		kref; //kobject refcount 引用计数,为1引用,为0释放
    #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
    	struct delayed_work	release;
    #endif
    	//下面是一些标志变量,用位域的方式声明
    	unsigned int state_initialized:1; 
    	unsigned int state_in_sysfs:1;
    	unsigned int state_add_uevent_sent:1;
    	unsigned int state_remove_uevent_sent:1;
    	unsigned int uevent_suppress:1;
    };
    

    在这些成员变量中,ktype、kset、kref值得注意。它们是对一个kobject的描述、分类和引用标识。

    2.1 ktype

    ktype指针指向了一个kobj_type的数据结构,该数据结构如下代码段所示:

    struct kobj_type {
    	void (*release)(struct kobject *kobj);//析构函数指针,指向析构函数,该函数在refcount为0时,清理所有”同类“的kobject并释放内存。
    	const struct sysfs_ops *sysfs_ops;//指针指向”sysfs读写操作函数结构体“
    	struct attribute **default_attrs;//指针指向attribute结构体数组,描述了属于该ktype的kobject的默认属性
    	const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
    	const void *(*namespace)(struct kobject *kobj);
    	void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
    };
    

    kobj_type是对kobject的特性描述。ktype数据结构初始化将会在随后的kobject_init流程中看到。

    2.2 kset

    kset指针指向一个kset的数据结构,该数据结构如下代码段所示:

    struct kset {
    	struct list_head list;//kset链表
    	spinlock_t list_lock;
    	struct kobject kobj;//该kset的基类(就是说该kset中的kobject都长这样)
    	const struct kset_uevent_ops *uevent_ops;//指针指向kset_uevent_ops结构体,用于处理kset中的kobject对象的热插拔操作。
    } __randomize_layout;
    

    kset是很多kobject的集合。一般来说,如果一个kobject属于某个kset,即kset->kobj是存在的,那么这个kset->kobj将作为该kobject的父对象。这一点在随后的kobject_add流程中体现。

    2.3 kref

    kref指针指向一个kref的数据结构,该数据结构如下代码段所示:

    //路径/kernel5.4/linux/kref.h
    struct kref {
    	refcount_t refcount;
    };
    

    kref引用计数来标示kobject的生命周期,在对象初始化时,调用kref_init()来使kref->refcount被原子置1(这一步将会在随后的kobject_init流程中看到)。引用了该kobject的代码都要进行引用计数加一。只要这个refcount不为0,该kobject就会继续被保留在内存中,否则对象将被撤销、内存被释放。
    refcount的初始化、增加和减少分别用下面函数来实现:

    //路径/kernel5.4/linux/kref.h
    static inline void kref_init(struct kref *kref)
    {
    	refcount_set(&kref->refcount, 1);
    }
    static inline void refcount_set(refcount_t *r, unsigned int n)
    {
    	atomic_set(&r->refs, n);
    }
    
    static inline void kref_get(struct kref *kref)
    {
    	refcount_inc(&kref->refcount);//这里最终调用也是原子加一
    }
    
    static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref))
    {
    	if (refcount_dec_and_test(&kref->refcount)) { //这里最终调用也是原子减一
    		release(kref);
    		return 1;
    	}
    	return 0;
    }
    

    三、kobject_create_and_add函数

    kobject_create_and_add,功能:动态注册kobject并生成sysfs

    //代码路径kernel5.4/lib/kobject.c
    /**
     * @name: kobject名称
     * @parent: the parent kobject of this kobject, if any.
     * 
     * 返回:一个kobject类型的数据结构
     * 不用这个kobject的时候用kobject_put()释放掉这个kobject
     * 未创建成功返回NULL
     */
    struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
    {
    	struct kobject *kobj;
    	int retval;
    
    	kobj = kobject_create();//获得kobject
    	if (!kobj)
    		return NULL;
    
    	retval = kobject_add(kobj, parent, "%s", name);//添加sysfs
    	if (retval) {
    		pr_warn("%s: kobject_add error: %d\n", __func__, retval);
    		kobject_put(kobj);//释放kobject
    		kobj = NULL;
    	}
    	return kobj;
    }
    

    kobject_create_and_add的整体调用流程图如下图所示:

    kobject_create_and_add函数流程图
    从整体流程图可以看出,实际上是对kobject数据结构的填充。下面详细分析一下以上流程。

    3.1 kobject_create()

    kobject_create()–动态创建kobject数据结构

    //代码路径kernel5.4/lib/kobject.c
    /**
     * kobject_create - create a struct kobject dynamically
     */
    struct kobject *kobject_create(void)
    {
    	struct kobject *kobj;
    	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);//为该kobj分配内核空间
    	if (!kobj)
    		return NULL;
    	kobject_init(kobj, &dynamic_kobj_ktype);//kobject初始化
    	return kobj;
    }
    

    kobject_create()中的关键是kobject_init(kobj, &dynamic_kobj_ktype);
    在深入了解kobject_init之前,先来看下它的入口参数dynamic_kobj_ktype

    //代码路径kernel5.4/lib/kobject.c
    static struct kobj_type dynamic_kobj_ktype = {
    	.release	= dynamic_kobj_release,
    	.sysfs_ops	= &kobj_sysfs_ops,
    };
    

    在kobject.c中已经给出了dynamic_kobj_ktype的定义,它给出了kobj_type的析构函数和sysfs操作函数

    //代码路径kernel5.4/lib/kobject.c
    //析构函数,实质就是释放该kobject
    static void dynamic_kobj_release(struct kobject *kobj)
    {
    	pr_debug("kobject: (%p): %s\n", kobj, __func__);
    	kfree(kobj);
    }
    
    //代码路径kernel5.4/lib/kobject.c
    //sysfs操作函数,包含对sysfs节点属性的读写操作函数设置
    const struct sysfs_ops kobj_sysfs_ops = {
    	.show	= kobj_attr_show, //读操作
    	.store	= kobj_attr_store, //写操作
    };
    

    3.1.1 kobject_init

    下面我们继续深入源码,看看kobject_init做了什么。

    上源码:

    //代码路径kernel5.4/lib/kobject.c
    /**
     * kobject_init() - Initialize a kobject structure.
     * @kobj: pointer to the kobject to initialize
     * @ktype: pointer to the ktype for this kobject.
     *
     * 这个函数在kobject_add()函数中被调用时,将会初始化一个kobject
     *
     * 注意用kobject_put()释放kobject
     */
    void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
    {
    	char *err_str;
    
    	if (!kobj) {
    		err_str = "invalid kobject pointer!";
    		goto error;
    	}
    	if (!ktype) {
    		err_str = "must have a ktype to be initialized properly!\n";
    		goto error;
    	}
    	if (kobj->state_initialized) {
    		/* do not error out as sometimes we can recover */
    		pr_err("kobject (%p): tried to init an initialized object, something is seriously wrong.\n",
    		       kobj);
    		dump_stack();
    	}
    
    	kobject_init_internal(kobj);
    	kobj->ktype = ktype;//这里,直接把入口的ktype即dynamic_kobj_ktype赋值给kobj->ktype
    	return;
    
    error:
    	pr_err("kobject (%p): %s\n", kobj, err_str);
    	dump_stack();
    }
    

    可以看到,在kobject_init中做了两部分工作:(1)对一些错误情况的处理;(2)kobject_init_internal。

    那么kobject_init_internal做了什么呢?

    //代码路径kernel5.4/lib/kobject.c
    static void kobject_init_internal(struct kobject *kobj)
    {
    	if (!kobj)
    		return;
    	kref_init(&kobj->kref); //引用计数初始化。在使用kref前,必须先通过kref_init()函数来初始化它。
    	INIT_LIST_HEAD(&kobj->entry);
    	kobj->state_in_sysfs = 0; 
    	kobj->state_add_uevent_sent = 0;
    	kobj->state_remove_uevent_sent = 0;
    	kobj->state_initialized = 1;
    }
    

    可以看到,kobject_init_internal是对kobject中的一些成员的初始化

    3.1.2 小结

    整体来看kobject_create()就是对kobject数据结构的填充(kobject初始化)。

    3.2 kobject_add()

    在kobject_create_and_add()中kobject_add调用如下:(是时候回头看下kobject_create_and_add了)

    kobject_add(kobj, parent, "%s", name);
    

    kobject_add()–把该kobject添加到sysfs中,源码如下所示:

    //代码路径kernel5.4/lib/kobject.c
    /**
     * 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.
     *
     * 翻译参考《linux内核设计与实现(第三版)》17.4 sysfs
     * The kobject name is set and added to the kobject hierarchy in this
     * function.
     * 翻译:设置kobject的名称并把它添加到kobject层次结构中。
     *
     * 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 associated with the kset assigned to this kobject.  If no kset
     * is assigned to the kobject, then the kobject will be located in the
     * root of the sysfs tree.
     * 翻译:如果parent指针被设置,即该kobject的父指针被设置,那么在sysfs中kobject将被映射
     * 为其父目录下的子目录;未设置,则将被映射为kset->kobject下的子目录。如果parent和kset
     * 都没有被设置,那么我们认为当前kobject没有父对象,因此会被映射成sysfs下的根级目录。
     * tips:如果kobject一开始就不打算设置为根级目录,那么最好在add前设置好parent或kset。
     *
     */
    int kobject_add(struct kobject *kobj, struct kobject *parent,
    		const char *fmt, ...)
    {
    	va_list args;
    	int retval;
    	if (!kobj)
    		return -EINVAL;
    	if (!kobj->state_initialized) {
    		pr_err("kobject '%s' (%p): tried to add an uninitialized object, something is seriously wrong.\n",
    		       kobject_name(kobj), kobj);
    		dump_stack();
    		return -EINVAL;
    	}
    	va_start(args, fmt);
    	retval = kobject_add_varg(kobj, parent, fmt, args);
    	va_end(args);
    	return retval;
    }
    

    kobject_add()中的关键是kobject_add_varg(kobj, parent, fmt, args);

    3.2.1 kobject_add_varg

    该函数设置了kobject的名称、获得父对象并创建sysfs。

    static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
    					   struct kobject *parent,
    					   const char *fmt, va_list vargs)
    {
    	int retval;
    	retval = kobject_set_name_vargs(kobj, fmt, vargs);//设置kobject名称
    	if (retval) {
    		pr_err("kobject: can not set name properly!\n");
    		return retval;
    	}
    	kobj->parent = parent;//获得父对象
    	return kobject_add_internal(kobj);//创建sysfs
    }
    

    在kobject_add_internal()函数中调用**kobject_add_internal()**函数来实现sysfs的创建。

    kobject_add_internal()主要工作:(1)判断kobject是否存在父对象,以及对父对象的设置;(2)创建sysfs目录

    static int kobject_add_internal(struct kobject *kobj)
    {
    	int error = 0;
    	struct kobject *parent;
    
    	if (!kobj)
    		return -ENOENT;
    
    	if (!kobj->name || !kobj->name[0]) {
    		WARN(1,
    		     "kobject: (%p): attempted to be registered with empty name!\n",
    		     kobj);
    		return -EINVAL;
    	}
    
    	parent = kobject_get(kobj->parent);//获取该kobject的父对象指针
    
    	/* join kset if set, use it as parent if we do not already have one */
        /*  下面这一段判断该kobject的kset是否被设置并为kobj->parent赋值。
            如果当前object还没设置父对象, 则引用设置的kset对象为父对象
            如果设置了,则将其加入到其设置的kset集合中(将其挂载到kset的链表上)
            然后设置父对象,即初始化kobj->parent*/
    	if (kobj->kset) { 
    		if (!parent)
    			parent = kobject_get(&kobj->kset->kobj);
    		kobj_kset_join(kobj);
    		kobj->parent = parent;
    	}
    
    	pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
    		 kobject_name(kobj), kobj, __func__,
    		 parent ? kobject_name(parent) : "<NULL>",
    		 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
    
    	error = create_dir(kobj);//根据kobj->ktype创建sysfs目录
    	if (error) {
    		kobj_kset_leave(kobj);
    		kobject_put(parent);
    		kobj->parent = NULL;
    
    		/* be noisy on error issues */
    		if (error == -EEXIST)
    			pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n",
    			       __func__, kobject_name(kobj));
    		else
    			pr_err("%s failed for %s (error: %d parent: %s)\n",
    			       __func__, kobject_name(kobj), error,
    			       parent ? kobject_name(parent) : "'none'");
    	} else
    		kobj->state_in_sysfs = 1;
    
    	return error;
    }
    

    3.2.2 小结

    整体来看kobject_add()就是创建kobject的sysfs。

    四、总结

    源码是最好的教材,别偷懒了,回去吧。
    tips:错误处理的部分可以选择不读,请重点关注加厚字体描述的内容。

    以上,与君共勉。
    【声明】本博文为个人学习笔记,仅供参考。转发请注明出处。如发现有误,还请不吝赐教,谢谢!

    展开全文
  • Linux 设备模型之kobject

    2015-06-08 15:39:09
    kobject_init用来初始化kobject结构,kobject_add用来把kobj加入到设备模型之中。 在实作中,我们先对obj1进行初始化和添加的动作,调用参数里,parent被赋为NULL,表示obj1没有父对象,反映到sysfs里, my_kobj1...
  • kobject.c 注释不完全版

    2021-07-17 14:31:33
    * kobject.c - library routines for handling generic kernel objects * * Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org> * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah....
    /*
     * kobject.c - library routines for handling generic kernel objects
     *
     * Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org>
     * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
     * Copyright (c) 2006-2007 Novell Inc.
     *
     * This file is released under the GPLv2.
     *
     *
     * Please see the file Documentation/kobject.txt for critical information
     * about using the kobject interface.
     */
    
    #include <linux/kobject.h>
    #include <linux/string.h>
    #include <linux/export.h>
    #include <linux/stat.h>
    #include <linux/slab.h>
    #include <linux/random.h>
    
    /**
     * kobject_namespace - return @kobj's namespace tag
     * @kobj: kobject in question
     *
     * Returns namespace tag of @kobj if its parent has namespace ops enabled
     * and thus @kobj should have a namespace tag associated with it.  Returns
     * %NULL otherwise.
     */
    const void *kobject_namespace(struct kobject *kobj)
    {
    	const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj);
    
    	if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE)
    		return NULL;
    
    	return kobj->ktype->namespace(kobj);
    }
    
    /*
     * populate_dir - populate directory with attributes.
     * @kobj: object we're working on.
     *
     * Most subsystems have a set of default attributes that are associated
     * with an object that registers with them.  This is a helper called during
     * object registration that loops through the default attributes of the
     * subsystem and creates attributes files for them in sysfs.
     */
    static int populate_dir(struct kobject *kobj)
    {
    	struct kobj_type *t = get_ktype(kobj);
    	struct attribute *attr;
    	int error = 0;
    	int i;
    
    	if (t && t->default_attrs) {
    		for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {
    			error = sysfs_create_file(kobj, attr);
    			if (error)
    				break;
    		}
    	}
    	return error;
    }
    
    static int create_dir(struct kobject *kobj)
    {
    	const struct kobj_ns_type_operations *ops;
    	int error;
    
    	error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));
    	if (error)
    		return error;
    
    	error = populate_dir(kobj);
    	if (error) {
    		sysfs_remove_dir(kobj);
    		return error;
    	}
    
    	/*
    	 * @kobj->sd may be deleted by an ancestor going away.  Hold an
    	 * extra reference so that it stays until @kobj is gone.
    	 */
    	sysfs_get(kobj->sd);
    
    	/*
    	 * If @kobj has ns_ops, its children need to be filtered based on
    	 * their namespace tags.  Enable namespace support on @kobj->sd.
    	 */
    	ops = kobj_child_ns_ops(kobj);
    	if (ops) {
    		BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);
    		BUG_ON(ops->type >= KOBJ_NS_TYPES);
    		BUG_ON(!kobj_ns_type_registered(ops->type));
    
    		sysfs_enable_ns(kobj->sd);
    	}
    
    	return 0;
    }
    
    static int get_kobj_path_length(struct kobject *kobj)             //获得kobject路径的长度
    {
    	int length = 1;												//初始值为1,默认为'/'
    	struct kobject *parent = kobj;
    
    	/* walk up the ancestors until we hit the one pointing to the
    	 * root.
    	 * Add 1 to strlen for leading '/' of each level.
    	 */
    	do {														//迭代
    		if (kobject_name(parent) == NULL)						//如果parent的名字为空,返回0;
    			return 0;
    		length += strlen(kobject_name(parent)) + 1;				//如果parent的名字不为空,length = length+parent的name+1,估计加1是因为有个‘/’字符
    		parent = parent->parent;								//迭代到parent的parent
    	} while (parent);
    	return length;												//返回length
    }
    
    static void fill_kobj_path(struct kobject *kobj, char *path, int length) //获得当前kobj的节点路径到path,路径长度length可以从上一个函数获得
    {
    	struct kobject *parent;
    
    	--length;													//自减1
    	for (parent = kobj; parent; parent = parent->parent) {
    		int cur = strlen(kobject_name(parent));					//获得kobj的名字长度
    		/* back up enough to print this name with '/' */
    		length -= cur;											//长度减去kobj当前的名字的长度
    		strncpy(path + length, kobject_name(parent), cur);		//路径指针加length是因为处理路径名是从后往前处理的
    		*(path + --length) = '/';								//在当前路径前面加一个'/'
    	}
    
    	pr_debug("kobject: '%s' (%p): %s: path = '%s'\n", kobject_name(kobj),
    		 kobj, __func__, path);
    }
    
    /*
    char *strncpy(char *dest,const char*src,size_t n)  把src所指向的字符串复制到dest,最多复制n个字符
    当src的长度小于n时,dest的剩余部分将用空字符填充
    */
    
    /**
     * kobject_get_path - generate and return the path associated with a given kobj and kset pair.
     *
     * @kobj:	kobject in question, with which to build the path
     * @gfp_mask:	the allocation type used to allocate the path
     *
     * The result must be freed by the caller with kfree().
     */
    char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) //这个函数就是对上两个函数的封装
    {
    	char *path;
    	int len;
    
    	len = get_kobj_path_length(kobj);
    	if (len == 0)
    		return NULL;
    	path = kzalloc(len, gfp_mask);
    	if (!path)
    		return NULL;
    	fill_kobj_path(kobj, path, len);
    
    	return path;
    }
    EXPORT_SYMBOL_GPL(kobject_get_path);
    
    /* add the kobject to its kset's list */			//把kobject加入到它所在kset的list中
    static void kobj_kset_join(struct kobject *kobj)
    {
    	if (!kobj->kset)								//如果kobj不属于任何一个kset,返回NULL
    		return;
    
    	kset_get(kobj->kset);							//kobj所在的kset的kobj引用次数加1
    	spin_lock(&kobj->kset->list_lock);				//上锁
    	list_add_tail(&kobj->entry, &kobj->kset->list);//将kobj加入到它所在kset的尾部
    	spin_unlock(&kobj->kset->list_lock);			//解锁
    }
    
    /* remove the kobject from its kset's list */
    static void kobj_kset_leave(struct kobject *kobj)  //将kobj从它所在的kset移除
    {
    	if (!kobj->kset)								//如果kobj不属于任何一个kset,返回NULL
    		return;
    
    	spin_lock(&kobj->kset->list_lock);				//上锁
    	list_del_init(&kobj->entry);					//将kobj的entry(list_head)从它所在的链表中删除
    	spin_unlock(&kobj->kset->list_lock);			//解锁
    	kset_put(kobj->kset);							//kset的引用次数减一
    }
    
    static void kobject_init_internal(struct kobject *kobj) //kobj的初始化
    {
    	if (!kobj)											//如果kobj不存在,返回NULL
    		return;
    	kref_init(&kobj->kref);								//初始化kobj中的kref属性
    	INIT_LIST_HEAD(&kobj->entry);						//初始化kobj的链表节点
    	kobj->state_in_sysfs = 0;							//不存在与sysfs文件系统中
    	kobj->state_add_uevent_sent = 0;					//未发送add_uevent
    	kobj->state_remove_uevent_sent = 0;					//未发送remove_uevent
    	kobj->state_initialized = 1;						//标志已经被初始化
    }
    
    
    static int kobject_add_internal(struct kobject *kobj)  //kobj添加到。。
    {
    	int error = 0;
    	struct kobject *parent;
    
    	if (!kobj)
    		return -ENOENT;
    
    	if (!kobj->name || !kobj->name[0]) {				//判断该kobj的name是否为空,如果为空,或者name的首部为空,发送警告并退出
    		WARN(1, "kobject: (%p): attempted to be registered with empty "
    			 "name!\n", kobj);
    		return -EINVAL;
    	}
    
    	parent = kobject_get(kobj->parent);					//将它的父节点引用次数加一,因为要添加一个它的子节点 
    
    	/* join kset if set, use it as parent if we do not already have one */
    	if (kobj->kset) {									//如果kobj所在的kset存在,并且kobj的parent不存在,就把kset作为kobj的parent
    		if (!parent)
    			parent = kobject_get(&kobj->kset->kobj);  //把kobj所在的kset的kobj的refcount+1,并且返回这个kobj
    		kobj_kset_join(kobj);						 //将kobj加入到kobj所在的kset的链表中	
    		kobj->parent = parent;						//将kobj的parent设置为kset
    	}
    
    	pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
    		 kobject_name(kobj), kobj, __func__,
    		 parent ? kobject_name(parent) : "<NULL>",
    		 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
    
    	error = create_dir(kobj);					//创建kobj目录及下它的属性文件
    	if (error) {								//错误处理
    		kobj_kset_leave(kobj);					//从kset中移除kobj
    		kobject_put(parent);					//kobj->parant的节点数减一
    		kobj->parent = NULL;					//kobj->parent置空
    
    		/* be noisy on error issues */
    		if (error == -EEXIST)
    			WARN(1, "%s failed for %s with "
    			     "-EEXIST, don't try to register things with "
    			     "the same name in the same directory.\n",
    			     __func__, kobject_name(kobj));
    		else
    			WARN(1, "%s failed for %s (error: %d parent: %s)\n",
    			     __func__, kobject_name(kobj), error,
    			     parent ? kobject_name(parent) : "'none'");
    	} else
    		kobj->state_in_sysfs = 1;        	//将kobj中的是否在sysfs中标志置1
    
    	return error;
    }
    
    /**
     * kobject_set_name_vargs - Set the name of an kobject
     * @kobj: struct kobject to set the name of
     * @fmt: format string used to build the name
     * @vargs: vargs to format the string.
     */
    int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,   //typedef char* va_list;
    				  va_list vargs)									//设置kobj的name属性
    {
    	const char *old_name = kobj->name;								//保存旧名字
    	char *s;
    
    	if (kobj->name && !fmt)											//当kobj的name为空并且fmt(要设置的名字)也为空。返回0
    		return 0;
    
    	kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);				//sprintf fmt和vargs,设置kobj的新名字为它
    	if (!kobj->name) {												//如果kobj的name依旧为空,把kobj重设为旧名字
    		kobj->name = old_name;	
    		return -ENOMEM;												//返回错误代码
    	}
    
    	/* ewww... some of these buggers have '/' in the name ... */
    	while ((s = strchr(kobj->name, '/')))
    		s[0] = '!';												//把名字中出现的所有'/'改成'!'
    																//这里有一个有意思的东西s[0] ==>*(s+0)==>*s
    	kfree(old_name);											//释放旧名字所占的内存空间
    	return 0;
    }
    
    /*C 库函数 char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。*/
    
    /*C 库函数 int sprintf(char *str, const char *format, ...) 发送格式化输出到 str 所指向的字符串。*/
    
    /**
     * kobject_set_name - Set the name of a kobject
     * @kobj: struct kobject to set the name of
     * @fmt: format string used to build the name
     *
     * This sets the name of the kobject.  If you have already added the
     * kobject to the system, you must call kobject_rename() in order to
     * change the name of the kobject.
     */
    int kobject_set_name(struct kobject *kobj, const char *fmt, ...)		//设置kobj的名字为fmt格式的一个巴拉巴拉(不知道怎么描述了,淦)
    {
    	va_list vargs;
    	int retval;
    
    	va_start(vargs, fmt);
    	retval = kobject_set_name_vargs(kobj, fmt, vargs);
    	va_end(vargs);
    
    	return retval;
    }
    EXPORT_SYMBOL(kobject_set_name);
    
    /**
     * kobject_init - initialize a kobject structure
     * @kobj: pointer to the kobject to initialize
     * @ktype: pointer to the ktype for this kobject.
     *
     * This function will properly initialize a kobject such that it can then
     * be passed to the kobject_add() call.
     *
     * After this function is called, the kobject MUST be cleaned up by a call
     * to kobject_put(), not by a call to kfree directly to ensure that all of
     * the memory is cleaned up properly.
     */
    //这个函数将会正确地初始化一个kobject,以便接下来能够被传递给kobject的调用
    //在这个函数被调用之后,这个kobject只能被kobject_put()清理,不能通过kfree直接释放以保证所有的内存空间被正确清理
    void kobject_init(struct kobject *kobj, struct kobj_type *ktype)	//@kobj :要被初始化的kobject
    {																	//@ktype:该kobj要初始化的ktype成员
    	char *err_str;
    
    	if (!kobj) {													//如果kobj为空
    		err_str = "invalid kobject pointer!";						//打印"invalid kobject pointer!"
    		goto error;
    	}
    	if (!ktype) {
    		err_str = "must have a ktype to be initialized properly!\n";//如果ktype为空
    		goto error;													//打印"must have a ktype to be initialized properly!\n"
    	}
    	if (kobj->state_initialized) {									//如果kobj已经被初始化过了
    		/* do not error out as sometimes we can recover */
    		printk(KERN_ERR "kobject (%p): tried to init an initialized "	//打印错误信息:尝试初始化一个已经初始化过的kobject
    		       "object, something is seriously wrong.\n", kobj);
    		dump_stack();													//在控制台打印Oops信息
    	}
    
    	kobject_init_internal(kobj);									//kobj初始化
    	kobj->ktype = ktype;											//把该kobj的ktype成员初始化为ktype
    	return;															//返回
    
    error:
    	printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);			//打印错误信息
    	dump_stack();													//在控制台打印Oops信息
    }
    EXPORT_SYMBOL(kobject_init);
    
    static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,  //将kobject_set_name_vargs和kobject_add_internal的一个简单封装
    			    const char *fmt, va_list vargs)
    {
    	int retval;
    
    	retval = kobject_set_name_vargs(kobj, fmt, vargs);					//线设置名字
    	if (retval) {
    		printk(KERN_ERR "kobject: can not set name properly!\n");		//如果设置不了名字,打印错误信息
    		return retval;
    	}
    	kobj->parent = parent;												//设置kobj的parent
    	return kobject_add_internal(kobj);									//1.父节点引用次数加1
    }																		//2.将kobj加入所在的kset链表,并且将kset的引用次数加一
    																		//3.创建目录和该kobj下的属性文件
    /**
     * 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 associated with the kset assigned to this kobject.  If no kset
     * 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, the caller 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.
     */
    int kobject_add(struct kobject *kobj, struct kobject *parent,     //供外界调用的API接口,将kobject添加
    		const char *fmt, ...)
    {
    	va_list args;												//char * args
    	int retval;
    
    	if (!kobj)													//如果kobj为空返回错误代码
    		return -EINVAL;
    
    	if (!kobj->state_initialized) {								//如果kobj还没初始化,打印错误信息,打印Oops信息,返回错误代码
    		printk(KERN_ERR "kobject '%s' (%p): tried to add an "
    		       "uninitialized object, something is seriously wrong.\n",
    		       kobject_name(kobj), kobj);
    		dump_stack();
    		return -EINVAL;
    	}
    	va_start(args, fmt);
    	retval = kobject_add_varg(kobj, parent, fmt, args);		//1.父节点引用次数加1
    	va_end(args);											//2.将kobj加入所在的kset链表,并且将kset的引用次数加一
    															//3.创建目录和该kobj下的属性文件
    	return retval;
    }
    EXPORT_SYMBOL(kobject_add);
    
    /**
     * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
     * @kobj: pointer to the kobject to initialize
     * @ktype: pointer to the ktype for this kobject.
     * @parent: pointer to the parent of this kobject.
     * @fmt: the name of the kobject.
     *
     * This function combines the call to kobject_init() and
     * kobject_add().  The same type of error handling after a call to
     * kobject_add() and kobject lifetime rules are the same here.
     */
    int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,//对kobject_init和kobject_add_varg()的简单封装
    			 struct kobject *parent, const char *fmt, ...)
    {
    	va_list args;
    	int retval;
    
    	kobject_init(kobj, ktype);
    
    	va_start(args, fmt);
    	retval = kobject_add_varg(kobj, parent, fmt, args);
    	va_end(args);
    
    	return retval;
    }
    EXPORT_SYMBOL_GPL(kobject_init_and_add);
    
    /**
     * kobject_rename - change the name of an object
     * @kobj: object in question.
     * @new_name: object's new name
     *
     * It is the responsibility of the caller to provide mutual
     * exclusion between two different calls of kobject_rename
     * on the same kobject and to ensure that new_name is valid and
     * won't conflict with other kobjects.
     */
    
    //线程有义务提供对kobject_rename函数的互斥访问并且确保新名字是有效的,不会和其他kobjects冲突
    int kobject_rename(struct kobject *kobj, const char *new_name)
    {
    	int error = 0;
    	const char *devpath = NULL;
    	const char *dup_name = NULL, *name;
    	char *devpath_string = NULL;
    	char *envp[2];
    
    	kobj = kobject_get(kobj);								//对该kobj的refcount+1
    	if (!kobj)												//如果kobj为空,返回错误码
    		return -EINVAL;
    	if (!kobj->parent)										//如果该kobj的父节点为空,返回错误码
    		return -EINVAL;
    
    	devpath = kobject_get_path(kobj, GFP_KERNEL);			//获得该kobj在sysfs中的路径	
    	if (!devpath) {											//如果路径为空,返回错误码
    		error = -ENOMEM;
    		goto out;
    	}
    	devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);	//为devpath_string申请内存空间
    	if (!devpath_string) {										//如果申请不到,返回错误码
    		error = -ENOMEM;
    		goto out;
    	}
    	sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);		//devpath_string = DEVPATH_OLD=+devpath
    	envp[0] = devpath_string;								//将devpath_string的地址赋给envp[0]
    	envp[1] = NULL;												
    
    	name = dup_name = kstrdup(new_name, GFP_KERNEL);       //下面这几行有点搞不懂,以后再说吧
    	if (!name) {											//大概就是调用sysfs的API,重改名字
    		error = -ENOMEM;									//然后将kobj->name设置为新名字
    		goto out;											//在发送uevent,告诉用户空间
    	}
    
    	error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj));
    	if (error)
    		goto out;
    
    	/* Install the new kobject name */
    	dup_name = kobj->name;
    	kobj->name = name;
    
    	/* This function is mostly/only used for network interface.
    	 * Some hotplug package track interfaces by their name and
    	 * therefore want to know when the name is changed by the user. */
    	kobject_uevent_env(kobj, KOBJ_MOVE, envp);
    
    out:
    	kfree(dup_name);
    	kfree(devpath_string);
    	kfree(devpath);
    	kobject_put(kobj);
    
    	return error;
    }
    EXPORT_SYMBOL_GPL(kobject_rename);
    
    /**
     * kobject_move - move object to another parent
     * @kobj: object in question.
     * @new_parent: object's new parent (can be NULL)
     */
    int kobject_move(struct kobject *kobj, struct kobject *new_parent)		//实现方法和上面的差不多,改kobj的文件路径
    {
    	int error;
    	struct kobject *old_parent;
    	const char *devpath = NULL;
    	char *devpath_string = NULL;
    	char *envp[2];
    
    	kobj = kobject_get(kobj);
    	if (!kobj)
    		return -EINVAL;
    	new_parent = kobject_get(new_parent);
    	if (!new_parent) {
    		if (kobj->kset)
    			new_parent = kobject_get(&kobj->kset->kobj);
    	}
    
    	/* old object path */
    	devpath = kobject_get_path(kobj, GFP_KERNEL);
    	if (!devpath) {
    		error = -ENOMEM;
    		goto out;
    	}
    	devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);
    	if (!devpath_string) {
    		error = -ENOMEM;
    		goto out;
    	}
    	sprintf(devpath_string, "DEVPATH_OLD=%s", devpath);
    	envp[0] = devpath_string;
    	envp[1] = NULL;
    	error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj));
    	if (error)
    		goto out;
    	old_parent = kobj->parent;
    	kobj->parent = new_parent;
    	new_parent = NULL;
    	kobject_put(old_parent);
    	kobject_uevent_env(kobj, KOBJ_MOVE, envp);
    out:
    	kobject_put(new_parent);
    	kobject_put(kobj);
    	kfree(devpath_string);
    	kfree(devpath);
    	return error;
    }
    
    /**
     * kobject_del - unlink kobject from hierarchy.
     * @kobj: object.
     */
    void kobject_del(struct kobject *kobj)  //删除kobject
    {
    	struct kernfs_node *sd;				//这个结构体不知道干啥的
    
    	if (!kobj)							//为空返回
    		return;
    
    	sd = kobj->sd;						
    	sysfs_remove_dir(kobj);				//sysfs API 移除目录
    	sysfs_put(sd);						//不知道干啥的
    
    	kobj->state_in_sysfs = 0;			//将是否在sysfs标志置0
    	kobj_kset_leave(kobj);				//将kobj从它所在的kset中移除
    	kobject_put(kobj->parent);			//将他的父节点的refcount-1
    	kobj->parent = NULL;				//将它的父节点置空
    }
    
    /**
     * kobject_get - increment refcount for object.
     * @kobj: object.
     */
    struct kobject *kobject_get(struct kobject *kobj)    //将kobj的refcount加1
    {
    	if (kobj) {										//判断两个条件,1:kobj非空 2:条件1满足的情况下,kobj要是已初始化的状态
    		if (!kobj->state_initialized)
    			WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
    			       "initialized, yet kobject_get() is being "
    			       "called.\n", kobject_name(kobj), kobj);
    		kref_get(&kobj->kref);					//将kobj的refcount+1
    	}
    	return kobj;
    }
    
    static struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj) //将kobj的refcount加1除非它已经是0了,正在等待释放
    {
    	if (!kref_get_unless_zero(&kobj->kref))
    		kobj = NULL;
    	return kobj;
    }
    
    /*
     * kobject_cleanup - free kobject resources.
     * @kobj: object to cleanup
     */
    static void kobject_cleanup(struct kobject *kobj)   //kobj的清理函数
    {
    	struct kobj_type *t = get_ktype(kobj);			//获得kobj的所属的ktype
    	const char *name = kobj->name;
    
    	pr_debug("kobject: '%s' (%p): %s, parent %p\n",
    		 kobject_name(kobj), kobj, __func__, kobj->parent);
    
    	if (t && !t->release)                       //如果ktype存在而ktype的release不存在,报警
    		pr_debug("kobject: '%s' (%p): does not have a release() "
    			 "function, it is broken and must be fixed.\n",
    			 kobject_name(kobj), kobj);
    
    	/* send "remove" if the caller did not do it but sent "add" */
    	if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {  //如果已经发送KOBJ_ADD,但是没发送KOBJ_REMOVE,警告并且执行发送KOBJ_REMOVE
    		pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n",
    			 kobject_name(kobj), kobj);
    		kobject_uevent(kobj, KOBJ_REMOVE);
    	}
    
    	/* remove from sysfs if the caller did not do it */
    	if (kobj->state_in_sysfs) {											//如果还存在于sysfs中,调用kobject_del
    		pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
    			 kobject_name(kobj), kobj);
    		kobject_del(kobj);
    	}
    
    	if (t && t->release) {
    		pr_debug("kobject: '%s' (%p): calling ktype release\n",			//如果t存在,并且t->release也存在,调用t->release(kobj)
    			 kobject_name(kobj), kobj);
    		t->release(kobj);
    	}
    
    	/* free name if we allocated it */
    	if (name) {														//如果名字存在,释放名字(如果名字是动态申请的)
    		pr_debug("kobject: '%s': free name\n", name);
    		kfree(name);
    	}
    }
    
    #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
    static void kobject_delayed_cleanup(struct work_struct *work)
    {
    	kobject_cleanup(container_of(to_delayed_work(work),
    				     struct kobject, release));
    }
    #endif
    
    static void kobject_release(struct kref *kref)						//kref的refcount减到0之后的回调函数,kobject_cleanup的简单封装
    {
    	struct kobject *kobj = container_of(kref, struct kobject, kref);	
    #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
    	unsigned long delay = HZ + HZ * (get_random_int() & 0x3);
    	pr_info("kobject: '%s' (%p): %s, parent %p (delayed %ld)\n",
    		 kobject_name(kobj), kobj, __func__, kobj->parent, delay);
    	INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
    
    	schedule_delayed_work(&kobj->release, delay);
    #else
    	kobject_cleanup(kobj);
    #endif
    }
    
    /**
     * kobject_put - decrement refcount for object.
     * @kobj: object.
     *
     * Decrement the refcount, and if 0, call kobject_cleanup().
     */
    void kobject_put(struct kobject *kobj)							//和kobject_get()是一对
    {
    	if (kobj) {
    		if (!kobj->state_initialized)
    			WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
    			       "initialized, yet kobject_put() is being "
    			       "called.\n", kobject_name(kobj), kobj);
    		kref_put(&kobj->kref, kobject_release);
    	}
    }
    
    static void dynamic_kobj_release(struct kobject *kobj)			//kobj的动态释放,调用kfree,结合下面几行就明白什么意思了
    {																//下面定义了一个默认的ktype,在使用动态创建kobject的时候,为kobject的ktype初始化
    	pr_debug("kobject: (%p): %s\n", kobj, __func__);
    	kfree(kobj);
    }
    
    static struct kobj_type dynamic_kobj_ktype = {
    	.release	= dynamic_kobj_release,
    	.sysfs_ops	= &kobj_sysfs_ops,
    };
    
    /**
     * kobject_create - create a struct kobject dynamically
     *
     * This function creates a kobject structure dynamically and sets it up
     * to be a "dynamic" kobject with a default release function set up.
     *
     * If the kobject was not able to be created, NULL will be returned.
     * The kobject structure returned from here must be cleaned up with a
     * call to kobject_put() and not kfree(), as kobject_init() has
     * already been called on this structure.
     */
    struct kobject *kobject_create(void)                 			
    {
    	struct kobject *kobj;
    
    	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
    	if (!kobj)
    		return NULL;
    
    	kobject_init(kobj, &dynamic_kobj_ktype);
    	return kobj;
    }
    
    /**
     * kobject_create_and_add - create a struct kobject dynamically and register it with sysfs
     *
     * @name: the name for the kobject
     * @parent: the parent kobject of this kobject, if any.
     *
     * This function creates a kobject structure dynamically and registers it
     * with sysfs.  When you are finished with this structure, call
     * kobject_put() and the structure will be dynamically freed when
     * it is no longer being used.
     *
     * If the kobject was not able to be created, NULL will be returned.
     */
    struct kobject *kobject_create_and_add(const char *name, struct kobject *parent) //动态创建并添加,对kobject_create和kobject_add的简单封装
    {
    	struct kobject *kobj;
    	int retval;
    
    	kobj = kobject_create();
    	if (!kobj)
    		return NULL;
    
    	retval = kobject_add(kobj, parent, "%s", name);
    	if (retval) {
    		printk(KERN_WARNING "%s: kobject_add error: %d\n",
    		       __func__, retval);
    		kobject_put(kobj);
    		kobj = NULL;
    	}
    	return kobj;
    }
    EXPORT_SYMBOL_GPL(kobject_create_and_add);
    
    /**
     * kset_init - initialize a kset for use
     * @k: kset
     */		
    void kset_init(struct kset *k) 										//kset的初始化
    {
    	kobject_init_internal(&k->kobj);								//kset中的kobj成员初始化
    	INIT_LIST_HEAD(&k->list);										//初始化链表头
    	spin_lock_init(&k->list_lock);									//自旋锁初始化
    }
    
    /* default kobject attribute operations */							//默认的kobject attribute 操作函数
    static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
    			      char *buf)
    {
    	struct kobj_attribute *kattr;									//申明一个kobj_attribute结构体
    	ssize_t ret = -EIO;
    
    	kattr = container_of(attr, struct kobj_attribute, attr);		//获得attr所在的kkobj_attribute结构体
    	if (kattr->show)												//如果kattr->show存在,执行
    		ret = kattr->show(kobj, kattr, buf);
    	return ret;
    } 
    
    static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,	//逻辑与上同
    			       const char *buf, size_t count)
    {
    	struct kobj_attribute *kattr;
    	ssize_t ret = -EIO;
    
    	kattr = container_of(attr, struct kobj_attribute, attr);
    	if (kattr->store)
    		ret = kattr->store(kobj, kattr, buf, count);
    	return ret;
    }
    
    const struct sysfs_ops kobj_sysfs_ops = {								//定义一个sys_ops 结构体
    	.show	= kobj_attr_show,
    	.store	= kobj_attr_store,
    };
    EXPORT_SYMBOL_GPL(kobj_sysfs_ops);
    
    /**
     * kset_register - initialize and add a kset.
     * @k: kset.
     */
    int kset_register(struct kset *k)      //kset注册函数
    {
    	int err;
    
    	if (!k)
    		return -EINVAL;
    
    	kset_init(k);						//初始化kset结构体
    	err = kobject_add_internal(&k->kobj);//把kset下的kobj添加
    	if (err)
    		return err;
    	kobject_uevent(&k->kobj, KOBJ_ADD); //向用户空间发送ADD uevent
    	return 0;
    }
    
    /**
     * kset_unregister - remove a kset.
     * @k: kset.
     */
    void kset_unregister(struct kset *k) //注销
    {
    	if (!k)
    		return;
    	kobject_del(&k->kobj);
    	kobject_put(&k->kobj);
    }
    
    /**
     * kset_find_obj - search for object in kset.
     * @kset: kset we're looking in.
     * @name: object's name.
     *
     * Lock kset via @kset->subsys, and iterate over @kset->list,
     * looking for a matching kobject. If matching object is found
     * take a reference and return the object.
     */
    struct kobject *kset_find_obj(struct kset *kset, const char *name)  					//通过name在klist寻找一个kobj
    {
    	struct kobject *k;
    	struct kobject *ret = NULL;
    
    	spin_lock(&kset->list_lock);														//上锁
    
    	list_for_each_entry(k, &kset->list, entry) {										//  for(k=container of(kset->list->next,struct kobject*,entry); /
    		if (kobject_name(k) && !strcmp(kobject_name(k), name)) {						//      k->entry!=klist->list;k=container of(k->entry->next,struct kobject*,entry))
    			ret = kobject_get_unless_zero(k);											//对每一个迭代到的kobject,如果name存在,并且name和参数中传进来的name相同,调用kobject_get_unless_zero()
    			break;																		//将该kobject的refcount加1(除非refcount已经是0了)  然后break
    		}
    	}
    
    	spin_unlock(&kset->list_lock);														//解锁
    	return ret;																			//返回该kobject
    }
    
    /* int strcmp(const char* stri1,const char* str2);
    strcmp() 会根据 ASCII 编码依次比较 str1 和 str2 的每一个字符,直到出现不到的字符,或者到达字符串末尾(遇见\0)。
    
    返回值:
    如果返回值 < 0,则表示 str1 小于 str2。
    如果返回值 > 0,则表示 str2 小于 str1。
    如果返回值 = 0,则表示 str1 等于 str2。
     */
    
    
    static void kset_release(struct kobject *kobj)											//动态释放klist
    {
    	struct kset *kset = container_of(kobj, struct kset, kobj);
    	pr_debug("kobject: '%s' (%p): %s\n",
    		 kobject_name(kobj), kobj, __func__);
    	kfree(kset);
    }
    
    static struct kobj_type kset_ktype = {
    	.sysfs_ops	= &kobj_sysfs_ops,
    	.release = kset_release,
    };
    
    /**
     * kset_create - create a struct kset dynamically
     *
     * @name: the name for the kset
     * @uevent_ops: a struct kset_uevent_ops for the kset
     * @parent_kobj: the parent kobject of this kset, if any.
     *
     * This function creates a kset structure dynamically.  This structure can
     * then be registered with the system and show up in sysfs with a call to
     * kset_register().  When you are finished with this structure, if
     * kset_register() has been called, call kset_unregister() and the
     * structure will be dynamically freed when it is no longer being used.
     *
     * If the kset was not able to be created, NULL will be returned.
     */
    // 这个函数动态创建一个kset结构体,这个结构体可以稍后被注册到系统中,当你用完了这个结构体,如果kset_register()已经被调用了,调用kset_unregister(),然后这个结构体将被动态释放
    //如果这个kset不能被创建,将会返回NULL
    static struct kset *kset_create(const char *name,
    				const struct kset_uevent_ops *uevent_ops,
    				struct kobject *parent_kobj)
    {
    	struct kset *kset;
    	int retval;
    
    	kset = kzalloc(sizeof(*kset), GFP_KERNEL);
    	if (!kset)
    		return NULL;
    	retval = kobject_set_name(&kset->kobj, "%s", name);
    	if (retval) {
    		kfree(kset);
    		return NULL;
    	}
    	kset->uevent_ops = uevent_ops;
    	kset->kobj.parent = parent_kobj;
    
    	/*
    	 * The kobject of this kset will have a type of kset_ktype and belong to
    	 * no kset itself.  That way we can properly free it when it is
    	 * finished being used.
    	 */
    	kset->kobj.ktype = &kset_ktype;
    	kset->kobj.kset = NULL;
    
    	return kset;
    }
    
    /**
     * kset_create_and_add - create a struct kset dynamically and add it to sysfs
     *
     * @name: the name for the kset
     * @uevent_ops: a struct kset_uevent_ops for the kset
     * @parent_kobj: the parent kobject of this kset, if any.
     *
     * This function creates a kset structure dynamically and registers it
     * with sysfs.  When you are finished with this structure, call
     * kset_unregister() and the structure will be dynamically freed when it
     * is no longer being used.
     *
     * If the kset was not able to be created, NULL will be returned.
     */
    //这个函数动态创建一个kset结构体并且在sysfs中注册该结构体。如果这个kset的生命周期结束了,调用kset_unregister(),这个结构体就会被动态释放
    struct kset *kset_create_and_add(const char *name,
    				 const struct kset_uevent_ops *uevent_ops,
    				 struct kobject *parent_kobj)
    {
    	struct kset *kset;
    	int error;
    
    	kset = kset_create(name, uevent_ops, parent_kobj);
    	if (!kset)
    		return NULL;
    	error = kset_register(kset);
    	if (error) {
    		kfree(kset);
    		return NULL;
    	}
    	return kset;
    }
    EXPORT_SYMBOL_GPL(kset_create_and_add);
    
    
    static DEFINE_SPINLOCK(kobj_ns_type_lock);
    static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES];
    
    int kobj_ns_type_register(const struct kobj_ns_type_operations *ops)
    {
    	enum kobj_ns_type type = ops->type;
    	int error;
    
    	spin_lock(&kobj_ns_type_lock);
    
    	error = -EINVAL;
    	if (type >= KOBJ_NS_TYPES)
    		goto out;
    
    	error = -EINVAL;
    	if (type <= KOBJ_NS_TYPE_NONE)
    		goto out;
    
    	error = -EBUSY;
    	if (kobj_ns_ops_tbl[type])
    		goto out;
    
    	error = 0;
    	kobj_ns_ops_tbl[type] = ops;
    
    out:
    	spin_unlock(&kobj_ns_type_lock);
    	return error;
    }
    
    int kobj_ns_type_registered(enum kobj_ns_type type)
    {
    	int registered = 0;
    
    	spin_lock(&kobj_ns_type_lock);
    	if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES))
    		registered = kobj_ns_ops_tbl[type] != NULL;
    	spin_unlock(&kobj_ns_type_lock);
    
    	return registered;
    }
    
    const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent)
    {
    	const struct kobj_ns_type_operations *ops = NULL;
    
    	if (parent && parent->ktype && parent->ktype->child_ns_type)
    		ops = parent->ktype->child_ns_type(parent);
    
    	return ops;
    }
    
    const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj)
    {
    	return kobj_child_ns_ops(kobj->parent);
    }
    
    bool kobj_ns_current_may_mount(enum kobj_ns_type type)
    {
    	bool may_mount = true;
    
    	spin_lock(&kobj_ns_type_lock);
    	if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
    	    kobj_ns_ops_tbl[type])
    		may_mount = kobj_ns_ops_tbl[type]->current_may_mount();
    	spin_unlock(&kobj_ns_type_lock);
    
    	return may_mount;
    }
    
    void *kobj_ns_grab_current(enum kobj_ns_type type)
    {
    	void *ns = NULL;
    
    	spin_lock(&kobj_ns_type_lock);
    	if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
    	    kobj_ns_ops_tbl[type])
    		ns = kobj_ns_ops_tbl[type]->grab_current_ns();
    	spin_unlock(&kobj_ns_type_lock);
    
    	return ns;
    }
    
    const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk)
    {
    	const void *ns = NULL;
    
    	spin_lock(&kobj_ns_type_lock);
    	if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
    	    kobj_ns_ops_tbl[type])
    		ns = kobj_ns_ops_tbl[type]->netlink_ns(sk);
    	spin_unlock(&kobj_ns_type_lock);
    
    	return ns;
    }
    
    const void *kobj_ns_initial(enum kobj_ns_type type)
    {
    	const void *ns = NULL;
    
    	spin_lock(&kobj_ns_type_lock);
    	if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
    	    kobj_ns_ops_tbl[type])
    		ns = kobj_ns_ops_tbl[type]->initial_ns();
    	spin_unlock(&kobj_ns_type_lock);
    
    	return ns;
    }
    
    void kobj_ns_drop(enum kobj_ns_type type, void *ns)
    {
    	spin_lock(&kobj_ns_type_lock);
    	if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
    	    kobj_ns_ops_tbl[type] && kobj_ns_ops_tbl[type]->drop_ns)
    		kobj_ns_ops_tbl[type]->drop_ns(ns);
    	spin_unlock(&kobj_ns_type_lock);
    }
    
    EXPORT_SYMBOL(kobject_get);
    EXPORT_SYMBOL(kobject_put);
    EXPORT_SYMBOL(kobject_del);
    
    EXPORT_SYMBOL(kset_register);
    EXPORT_SYMBOL(kset_unregister);
    

    刚接触linux不久,有关sysfs的不太会,文章如有漏误,敬请指出

    展开全文
  • Linux设备模型kobject与kset之间的关系汇总
  • linux设备模型二(kobject

    万次阅读 多人点赞 2018-08-03 01:20:14
    Kobject是Linux设备模型的基础,也是设备模型中最难理解的一部分(可参考Documentation/kobject.txt的表述)。因此有必要先把它分析清楚。 2. 基本概念 由上一节可知,Linux设备模型的核心是使用Bus、Class、...
  • kobject,kset的结构分析

    2019-11-20 14:50:07
    kobject 是设备对象 kobject是将整个设备模型连接在一起的基础,类型如下: struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset; struct kobj_type...
  • Kobject是Linux设备模型的基础,也是设备模型中最难理解的一部分(可参考Documentation/kobject.txt的表述)。因此有必要先把它分析清楚。 2. 基本概念 由“Linux设备模型(1)_基本概念”可知,Linux设备模型的核心...
  • Linux内核中有大量的驱动,而这些驱动往往具有类似的结构,根据面向对象的思想,可以将共同的部分提取为父类,而这个父类就是kobjectkobject结构体中包含了大量设备的必须信息,而三大类设备驱动都需要包含这个...
  • 1. kobject定义的头文件 #include <linux/kobject.h> 2. kobject所能处理的任务和它所支持的代码 a. 对象的引用记数。 b. sysfs表述 c. 数据结构关联 d. 热插拔事件处理 3. 如何通过一个kobject...
  • linux kobject-uevent(热插拔事件)

    千次阅读 2021-01-17 12:31:42
    sysfs文件系统主要功能是将系统中所有的设备通过一个拓扑结构全部展示出来,在系统启动的初期,系统通过mount命令将syfs文件系统挂载到/sys节点上, mount-tsysfssysfs/sys ...而kobject是sysfs的基...
  • kobject.c 添加注释

    2019-10-03 22:52:16
    最近结合《Linux Device Drivers》对kobject的理解,对kobject.c文件添加注释,仅供参考! 1/** 2*populate_dir-populatedirectorywithattributes. 3*@kobj:objectwe'reworkingon. 4* ...
  • LDD3中说,Kobject的作用为: 1、sysfs 表述:在 sysfs 中出现的每个对象都对应一个 kobject, 它和内核交互来创建它的可见表述 2、热插拔事件处理 :kobject 子系统将产生的热插拔事件通知用户空间。 3、数据结构...
  • kobject系统分析

    2020-01-11 08:35:52
    要说kobject不得不说sysfs sysfs 是一个最初基于 ramfs 且位于内存的文件系统。它提供导出内核 数据结构及其属性,以及它们之间的关联到用户空间的方法。 sysfs 始终与 kobject 的底层结构紧密相关。 任何 ...
  • Linux内核中的kobject和kset介绍

    千次阅读 2017-09-17 21:28:03
    kobject在内核中应用最多的就是设备驱动模型————总线、设备、驱动、类的管理都使用了kobject,但是kobject并不只为设备驱动模型服务,它是内核中的通用对象模型,用来为内核中各部分的对象管理提供统一视图,...
  • Kobject源码分析

    2019-12-29 09:32:10
    kobject:最小的device module unit,内嵌在kernel的device资源结构中,例如 character device(cdev), block device(blkdev)。这些资料结构中都会内嵌一个kobject。 struct kobject { const char *name; /*该...
  • Linux kobject_uevent_env

    2020-09-18 16:58:31
    kobject_uevent_env用于Linux下热插拔事件产生时,通知到用户空间的一种方式,uevent是sysfs向用户空间发出的消息。 基本结构 // kobject事件类型 // 源码位置/kernel/msm-3.18/include/linux/kobject.h enum ...
  • kobject学习

    2019-06-01 11:13:26
    linux/kobject.h> #include <linux/string.h> #include <linux/sysfs.h> #include <linux/module.h> #include <linux/init.h> /* * This module shows how to create a s...
  • sysfs文件系统是内核对象(kobject)、属性(kobj_type)、及它们相互关系的一种表现。 sysfs非常重要的特征:用户可以从sysfs中读出内核数据,也可以将用户数据写入内核。 2、内核结构与sysfs对应关系: kobject ...
  • kobject与kset

    2020-02-22 22:41:01
    参考:http://blog.chinaunix.net/uid-25695950-id-4475182.html ... kobject、kset、ktype是设备模型中的基本机构。kobject基本结构体,kset是某相同kobject集合,ktype是类型。ko...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,552
精华内容 5,420
关键字:

kobject