2.6内核增加了一个引人注目的新特性——统一设备模型(device model)。设备模型提供一个独立的机制专门来表示设备,并描述了其在系统中的拓扑结构。 17.1 kobject 设备模型的核心部分就是kobject,它由struct kobject结构表示,定义于头文件(linux/kobject)中。kobject类似于C#或java这些面向对象语言中的object对象类,提供了诸如引用计数、名称和父指针等字段,可以创建对象的层次结构。 struct kobject { parent指针指向kobject的父对象。因此,kobject就会在内核中构造一个对象层次结构,并且可以将对各对象间的关系表现出来,就如你看到的,这便是sysfs的真正面目:一个用户空间的文件系统,用来表示内核中kobject对象的层次结构。 dentry指针指向dentry结构体,在sysfs中该结构体就表示这个kobject,当然假设该kobject已反映在sysfs中。 kobject通常是嵌入到其他结构中的,其单独意义其实并不大。相反,那些更为重要的结构体才真正需要用到kobject结构。比如struct cdev。 struct cdev { struct kobject kobj; struct module *owner; struct file_operations *ops; struct list_head list; dev_t dev unsigned int count; }; 当kobject被嵌入到其他结构体中时,该结构体便拥有了kobject提供的标准功能。更重要的一点是,嵌入kobject接结构体可以成为对象层次架构中的一部分。比如cdev结构体就可以通过其父进程指针cdev->kobj->parent和链表cdev->kobj->entry来插入到对象层次结构中。 17.2 ktype kobject对象被关联到一种特殊的类型,即ktype。ktype由kobj_type结构体表示,定义于<linux/kobject.h>中: struct kobj_type { 17.3 kset kset是kobject对象的集合体。把它看成一个容器,可将所有相关的kobject对象,比如“全部的块设备”置于同一位置。kset可把kobject集中到一个集合中,而ktype描述相关类型kobject所共有的特性,它们之间的重要区别在于:具有相同ktype的kobject可以分到不同的kset中(同一个kset中的kobject是否具有相同的ktype吗???)。kobject的kset指针指向相应的kset集合。 struct kset { 17.4 subsystem subsystem在内核中代表高层概念,它是一个或多个kset的大集合。 struct subsystem { 17.6 管理和操作kobject 17.7 引用计数 kobject的主要功能之一就是为我们提供了一个统一的引用计数系统。初始化后,kobject的引用计数设置为1。只要引用计数不为0,那么该对象就会继续保留在内存中,也可以说是被“钉”住了,任何包含对象引用的代码首先要增加该对象的引用计数,当代码结束后则减少它的引用计数。当引用计数减为0时,对象便可以被销毁,同时相关内存也都被释放。 增加一个引用计数可通过kobject_get()函数完成: struct kobject * kobject_get(struct kobject *kobj); 该函数正常情况下返回一个指向kobject的指针,如果失败,则返回NULL指针。 减少引用计数通过kobject_put()完成: void kobject_put(struct kobject *kobj); 17.8 sysfs sysfs文件系统是一个处于内存中的虚拟文件系统,它为我们提供了kobject对象层次结构的视图。帮助用户可以一个简单文件系统的方式来观察系统中各种设备的拓扑结构。借助属性对象,kobject可用导出文件的方式,将内核变量提供给用户读取或写入。 sysfs的诀窍是把kobject对象与目录项紧密联系起来,这点是通过kobject中的dentry(directory entry)字段实现的。回忆一下12章,dentry结构体表示目录项,通过连接kobject到指定的目录项上,无疑方便的将kobject映射到该目录上。好了,kobject其实已经形成了一棵树了——就是我们心爱的对象模型体系。 sysfs的根目录下包含了七个子目录:block、bus、class、devices、firmware、module和power。block目录下的每个子目录都对应着系统中的一个块设备。反过来,每个目录下又都包含了该块设备的所有分区。bus目录提供了一个系统总线视图。class目录包含了以高层功能逻辑组织起来的系统设备视图。devices目录是系统中设备拓扑结构视图,它直接映射出了内核中设备结构体的组织层次。firmware目录包含一些诸如ACPI、EDD、EFI等低层子系统的特殊树。power目录包含了系统范围的电源管理数据。 17.8.1 sysfs中添加和删除kobject 仅仅初始化一个kobject是不能自动将其导出到sysfs中的,想要把kobject导入sysfs,需要用到函数kobject_add(): int kobject_add(struct kobject *kobj); kobject在sysfs中的位置取决于kobject在对象层次结构中的位置。如果kobject的父指针被设置,那么在sysfs中kobject将被映射为其父目录下的子目录,如果parent没有设置,那么kobject将被映射到kset->kobj中的子目录。两者都未设置,映射为sysfs下的根级目录。 17.8.2 向sysfs中添加文件 我们已经看到kobject被映射为文件目录,而且所有的对象层次结构都优雅的、一个不少的映射成为sys下的目录结构。但是里面的文件是什么?sysfs仅仅是一个漂亮的树,但是没有提供实际数据的文件。 默认属性 默认的文件集合是通过kobject和kset中的ktype字段提供的。因此所有具有相同类型的kobject在它们对应的sysfs目录下都拥有相同的默认文件集合。kobj_type字段含有一个字段——default_attrs,它是看一个attribute结构体数组。这些属性负责将内核数据映射成sysfs中的文件。 struct attribute { 虽然default_attrs列出了默认的属性,sysfs_ops字段则描述了如何使用它们。sysfs_ops字段指向了一个定义与文件<linux/sysfs.h>的同名结构体: struct sysfs_ops { store()方法在写操作时调用,它会从buffer中读取size大小的字节,并将其放入attr表示的属性结构体变量中。 |