kobject kset

sysfs文件系统

  sysfs is a ram-based filesystem initially based on ramfs. It provides a means to export kernel data structures, their attributes, and the linkages between them to userspace.”

                                     --- documentation/filesystems/sysfs.txt

sysfs类似proc文件系统,把连接在系统上的设备和总线组织成分级的文件,使用户在用户空间可以访问

 

ls /sys/
block/ bus/ class/ devices/ firmware/ kernel/ module/ power/

 

 

Block目录:包含所有的块设备
Devices目录:包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构
Bus目录:包含系统中所有的总线类型

ls /sys/bus
i2c/ ide/ pci/ pci express/ platform/ pnp/ scsi/ serio/ usb/

总线包含两个子目录

  drivers:包含注册到该总线的所有驱动

  devices:包含在整个系统中发现的属于该总线的类型设备

 

Class目录(按照功能分类):系统中的设备类型(如网卡设备,声卡设备等)

decives: 所有的系统设备

kernel:内核配置参数

Module:系统中所有的模块信息

Firmweare:系统中固件

Fs:描述系统中的文件系统

power:系统中电源选项

Drivers目录:包括内核中所有已注册的设备驱动程序

  


 

 

 一个设备在class下是一个鼠标,在bus下是一个usb,最终软连接到devices下

 

kobject

kobject实现了面向对象的管理机制,在内核中每个kobject对象对应sysfs文件系统中的一个目录,通过struct kobject表示,使所有设备在底层具有统一的接口

struct kobject {
    char *name; 指向设备名称的指针
    char name[KOBJ NAME LEN]; 设备名称
    struct kref kref; 对象引用计数
    struct list_head entry; 挂接到所在kset中去的单元
    struct kobject * parent; 指向父对象的指针
    struct kset * kset; 所属kset的指针
    struct kobj_type * ktype; 指向其对象类型描述符的指针
    struct dentry * dentry; sysfs文件系统中与该对象对应的文件节点路径指针
};

 

处理函数

void kobject_init(struct kobject * kobj);    //kobject初始化函数。
int kobject_add(struct kobject * kobj);
//将kobj对象加入Linux设备层次。挂接该kobject对象到kset的list链中,增加父目录各级kobject的引用计数,
//在其 parent指向的目录下创建文件节点,并启动该类型内核对象的hotplug函数。
int kobject_register(struct kobject * kobj);
/*kobject注册函数。通过调用kobject init()初始化kobj,再调用kobject_add()完成该内核对象的注册
*/
void kobject_del(struct kobject * kobj);//从Linux设备层次(hierarchy)中删除kobj对象。
void kobject_unregister(struct kobject * kobj);//kobject注销函数。与kobject register()相反,它首先调用kobject del从设备层次中删除该对象,再调用kobject put()减少该对象的引用计数,如果引用计数降为0,则释放kobject对象

 

 

struct kobj_type {
    void (*release)(struct kobject *);
    struct sysfs_ops *sysfs_ops;
    struct attribute **default_attrs;
};

ktype是一个指向kobj_type结构的指针,记录一些kobject的属性。Kobj_type数据结构包含三个域:一个release方法用于释放kobject占用的资源;一个sysfs_ops指针指向sysfs操作表和一个sysfs文件系统缺省属性列表。Sysfs操作表包括两个函数store()和show()。当用户态读取属性 时,show()函数被调用,该函数编码指定属性值存入buffer中返回给用户态;而store()函数用于存储用户态传入的属性值。

struct attribute {
    char * name;    //属性文件名
    struct module * owner;
    mode_t mode;    //属性保护位
}

attribute, 属性。它以文件的形式输出到sysfs的目录当中。在kobject对应的目录下面。文件名就是name。文件读写的方法对应于kobj type中的sysfs ops。

 

 

kset

kset是相同类型的kobject的集合。kset最重要的是建立上层(sub-system)和下层的 (kobject)的关联性。kobject 也会利用它了分辨自已是属于那一個类型,然後在/sys 下建立正确的目录位置。而kset 的优先权比较高,kobject会利用自已的*kset 找到自已所属的kset,並把*ktype 指定成該kset下的ktype,除非沒有定义kset,才会用ktype來建立关系。Kobject通过kset组织成层次化的结构,kset是具有相 同类型的kobject的集合,在内核中用kset数据结构表示,定义为:

struct kset {
    struct subsystem * subsys; //所在的subsystem的指针
    struct kobj type * ktype; //指向该kset对象类型描述符的指针
    struct list head list; //用于连接该kset中所有kobject的链表头
    struct kobject kobj; //嵌入的kobject
    struct kset hotplug ops * hotplug ops;// 指向热插拔操作表的指针
}

 

 

 

热插拔事件

  当系统配置发生变化时,如kset添加到系统,移动kobject,一个通知会从内核空间发送到用户空间,就是热插拔事件,热插拔事件会导致用户空间中的相应处理程序(udev,mdev)被调用,这些处理程序会加载驱动,创建节点相应热插拔。

 

操作合集

struct kset_uevent_ops{
    int (*filter)(struct kset *kset, struct kobject *kobj);//决定是否将事件传递到用户空间中
    const char *(*name)(struct kset *kset, struct kobject *kobj);//用于将字符串传递给用户空间的热插拔处理程序
    int (*uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env);//将用户空间需要的参数添加到环境变量中
}

  当kset所管理的kobject和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>
#include <linux/kobject.h>

MODULE_LICENSE("GPL");

struct kset *kset_p;
struct kset kset_c;

/* 函数声明 */
void obj_test_release(struct kobject *);
ssize_t kobj_test_show(struct kobject *,struct attribute *,char *);
ssize_t kobj_test_store(struct kobject *,struct attribute *,const char *,size_t);

static struct attribute test_attr =
{
    .name = "kobj_config",
    .mode = S_IRWXUGO,
};

static struct attribute *def_attrs[] =
{
    &test_attr,
    NULL,
};

static struct sysfs_ops obj_test_sysops =
{
    .show = kobj_test_show,
    .store = kobj_test_store,
};

static struct kobj_type ktype =
{
    .release = obj_test_release,
    .sysfs_ops = &obj_test_sysops,
    .default_attrs = def_attrs,
};

void obj_test_release(struct kobject *kobject)
{
    printk("[kobj_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 size)
{
    printk("Have store -->\n");
    printk("write: %s.\n",buf);
    return size;
}

static int kset_filter(struct kset *kset,struct kobject *kobj)
{
    printk("Filter: kobj %s.\n",kobj->name);
    return 1;
}

static const char *kset_name(struct kset *kset,struct kobject *kobj)
{
    static char buf[20];
    printk("Name kobj %s.\n",kobj->name);
    sprintf(buf,"%s","kset_name");
    return buf;
}

static int kset_uevent(struct kset *kset,struct kobject *kobj, struct kobj_uevent_env *env)

{
    int i = 0;
    printk("uevent: kobj %s.\n",kobj->name);

    while(i < env->envp_idx)
    {
        printk("%s.\n",env->envp[i]);
        i ++;
    }

    return 0;
}

static struct kset_uevent_ops uevent_ops =
{
    .filter = kset_filter,
    .name = kset_name,
    .uevent = kset_uevent,
};


static int __init kset_test_init(void)
{
    int ret = 0;

    printk("kset test init!\n");

    /* 创建并注册 kset_p */
    kset_p = kset_create_and_add("kset_p",&uevent_ops,NULL);

    /* 添加 kset_c 到 kset_p */
    kobject_set_name(&kset_c.kobj,"kset_c");
    kset_c.kobj.kset = kset_p;

    /* 对于较新版本的内核,在注册 kset 之前,需要  
     * 填充 kset.kobj 的 ktype 成员,否则注册不会成功 */
    kset_c.kobj.ktype = &ktype;
    ret = kset_register(&kset_c);

    if(ret)
        kset_unregister(kset_p);

    return 0;
}

static void __exit kset_test_exit(void)
{
    printk("kset test exit!\n");
    kset_unregister(kset_p);
    kset_unregister(&kset_c);

}

module_init(kset_test_init);
module_exit(kset_test_exit);

 

posted @ 2020-11-25 13:22  11YS  阅读(134)  评论(0)    收藏  举报