讲师博文
Kobject 与 sysfs 文件系统框架的分析 来源 : 未知     2018-05-14

1、设备模型

2.6内核增加了一个引人注目的新特性------统一设备模型

设备模型提供了一个独立的机制专门来表示设备,并描述在系统中的拓扑结构

(1)代码重复最小化

(2)可以列出系统中所有的设备,观察到他们的状态,并且查看他们连接的总线

(3) 可以将设备和其对应的驱动联系起来

(4) 可以按照设备类型进行分类

2、kobject

设备模型的核心部分就是kobject

struct kobject {

const char *name; /*指向kobject的名字*/

struct list_head entry;

struct kobject *parent/*指向父kobject 实现层次结构*/

struct kset *kset;

struct kobj_type *ktype;

struct sysfs_dirent *sd;/*指向sysfs_dirent结构体 这个结构体就表示kobject对象的层次结构*/

struct kref kref;/*提供引用计数 其核心成员是一原子型变量,用来表示内核对象的引用计数 内核通过该成员追踪内核对象生命周期*/

unsigned int state_initialized:1;

unsigned int state_in_sysfs:1;/*是否已经加入sysfs*/

unsigned int state_add_uevent_sent:1;

unsigned int state_remove_uevent_sent:1;

};

3、ktype

kobject对象被关联到一种特殊的类型 即ktype(kernel object type的缩写) ktype由kobj_type结构体来表示,定义于头文件

struct kobj_type {

void (*release)(struct kobject *kobj);

struct sysfs_ops *sysfs_ops;

struct attribute **default_attrs;

};

1)ktype的存在是为了描述一族kobject所具有的普遍特性,实现同类的kobject都能共享相同的特性

2)release指针指向在kobject引用计数减至零时调用析构函数,该函数负责释放所有kobject使用的内存和其他相关的清理工作

3)defaults_attrars 结构体数组定义了所有具有相同类型的kobject对象的属性

4)sysfs文件系统根据对应的kobject属性来创建文件

4、kset

1)kset是kobject对象的集合体,将相关的kobject集合到一起

2)具有相同ktype的kobject可以被分组到不同的kset

5、管理和操作kobject

kobject一般都被嵌入到设备结构体中

(1)kobject的初始化一个kobject对象

void kobject_init(struct kobject *kobj,struct kobj_type *ktype)

(2)定义并初始化

struct kobject *kobject_create(void)

6、引用计数

1)kobject通过引用计数控制对象的有效生命周期

(1)初始化后kobject的引用计数置为1

(2)当引用计数为0时,则表示设备已经卸载,不能在操作对应的设备

2)操作引用计数的接口

(1)增加一个引用计数

struct kobject *kobject_get(struct kobject *kobj)

(2)减少一个引用计数

void kobject_put(struct kobject *kobj)

3)描述引用计数的结构kref

kobject计数是通过kref实现

struct kref{

atomic_t refcount

}

(1)初始化

void kref_init(struct kref *kref)

(2)增加一个计数

void kref_get(struct kref *kref)

(3)减一个计数

void kref_put(struct kref *kref)

代码:

(1)创建一个kobject对象并初始化

(2) 定制自己的kobject对象创建与释放函数

7、sysfs

sysfs文件系统是一个处于内存中的虚拟文件系统,用文件系统的方式提供kobject对象层次结构的视图

bus:提供一个系统总线视图

dev:提供已经注册设备节点的视图

device:系统中设备结构体视图

class:给用户的视图 通过对device实际设备目录的符号链接

kernel:包含内核配置项和状态信息

fs:已经注册文件系统的视图

class与devices 一个是高层概念 给用户的视图 一个底层物理设备 给内核的视图

8、sysfs添加和删除kobject

将kobject对象映射到sysfs文件系统中,产生对应的文件

int kobject_add(struct kobject *kobj, struct kobject *parent,

const char *fmt, ...)

从sysfs文件系统中删除一个kobject对应文件目录,需要使用函数kobject_decl()

void kobject_del(struct kobject *kobj)

int kobject_set_name(struct kobject *kobj, const char *fmt, ...)//设置kobject对象在sysfs中的名字

int sysfs_create_dir(struct kobject * kobj)//在sysfs文件系统中创建目录

void sysfs_remove_dir(struct kobject * kobj)//在sysfs文件系统中删除目录

struct kobject *kobject_get(struct kobject *kobj)//可以用来获取kobj-parent

代码3:将对应的kobject映射到对应sysfs文件系统中,增加my_kobject_add()函数my_kobject_del()函数

代码4:将当前的kobject对象增加parent节点 增加my_kobject_create_and_add()函数

9、向sysfs添加文件

1)默认的文件集合通过kobject和kset中的ktype字段提供

2)具有相同属性的kobject导入到sysfs文件系统中的文件也具有相同的属性

3)默认文件属性由kobj_type结构来描述

struct kobj_type {

void (*release)(struct kobject *kobj);

struct sysfs_ops *sysfs_ops;

struct attribute **default_attrs;

};

4)kobj_type结构中包含默认文件集合中所有文件的属性,

default_attrs 默认文件属性结构体数组

struct attribute {

const char *name; 属性名称,在sysfs文件系统中显示的名字

struct module *owner;所属模块 如果存在

mode_t mode;权限

};

sysfs 文件系统根据默认文件属性建立对应的文件

5)增加新的文件

(1)根据新文件属性在sysfs文件系统创建文件

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

{

BUG_ON(!kobj || !kobj->sd || !attr);

return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);

}

6)对sysfs文件系统中的文件进行读写

struct sysfs_ops {

在读sysfs文件时该方法会调用

ssize_t (*show)(struct kobject *, struct attribute *,char *);

在写sysfs文件时该方法被调用

ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);

};

struct kset *kset_create_and_add(const char *name,struct kset_uevent_ops *uevent_ops,struct kobject *parent_kobj)//创建一个kset集合

10、创建新属性

sysfs_create_link():增加新的链接

sysfs_remove_file():删除新的文件

sysfs_remove_link() 删除链接文件

代码5:在sysfs文件系统中增加文件

代码6:在sysfs文件系统中增加多个文件,并设置新文件的属性

代码7: 在sysfs文件系统中针对每个文件设置相应的的操作方法show()与store()

代码8:底层实现led驱动并关联到kobject对象中

11、uevent

1)kset是属于一组kobject的集合

struct kset { struct list_head list;

spinlock_t list_lock;

struct kobject kobj;

const struct kset_uevent_ops *uevent_ops;

};

kset_uevent_ops : 当kset中的kobject对象发生状态变化需要通知用户空间

struct kset_uevent_ops {

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

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

int (* const uevent)(struct kset *kset, struct kobject *kobj,

struct kobj_uevent_env *env);

};

2)kset相关的API

void kset_init(struct kset *k)

初始化kset对象

int kset_register(struct kset *k)

初始化并向系统注册一个kset对象

static void kobject_init_internal(struct kobject *kobj)

注册kset对象

notes:

.kset对象本身也是一个kobject内核对象,在sysfs文件系统中生成一个新的目录

.注册kset对象,内核编译启用了CONFIG_HOTPLUG,则需要就这一事件通知用户空间(内核配置文件中可以查询)

.事件通知由kobject_uevent完成

.不属于kset的kobject对象不能完成事件通知

.kobject之间通过parent成员实现层次关系,当kobject的parent为NULL时,就会把kobj->kset->kobj作为kobj的parent

struct kset *kset_create_and_add(const char *name, const struct kset_uevent_ops *uevent_ops,

struct kobject *parent_kobj)

创建一个kset对象并添加到sysfs文件系统中

3)hotplug(热插拔)

当一个设备动态加入系统时,设备驱动程序可以检查到设备,并通过通知的方式告知用户空间

通知用户空间的方式一般有两种:udev 与 /sbin/hotplug,现在使用更多的是udev

udev 的实现基于内核中的网络机制,通过标准的socket接口来监听来自内核的网络广播包,并对接收的包进行分析处理

4)hotplug相关的API

int kobject_uevent(struct kobject *kobj, enum kobject_action action)

发送一个 event给用户空间,以网络数据包的形式发送给用户空间应用程序

@action : 发送event类型

enum kobject_action {

KOBJ_ADD,

KOBJ_REMOVE,

KOBJ_CHANGE,

KOBJ_MOVE,

KOBJ_ONLINE,

KOBJ_OFFLINE,

KOBJ_MAX

};

kobject_uevent_env()

sprintf(scratch, "%s@%s", action_string, devpath); @273L

传递给用户空间event数据的内容

"事件类型@设备路径"

example:

"add@/kset-test/kobject-test/"

uevent一般与应用程序结合起来使用,一般可以接收并处理uevent的应用程序有udev or mdev

udev工具通过netlink获取内核发出的uevent消息,并且处理,加载相应的驱动或者在/dev/目录下生成对应的设备结点

udev服务启动后,会扫描/sys目录下所有具有uevent属性文件,在进行相应的处理

uevent的触发被封装到设备模型的操作中,当添加设备的时则会发送一个uevent(user event)事件,

udev 工具会通过netlink获取uevent消息 ,然后进行加载驱动或者在/dev/目录下生成对应的设备结点

int device_add()

{

......

kobject_uevent(&dev->kobj, KOBJ_ADD);

......

}

5)netlink机制

(1)netlink机制的特点

.netlink是一种特殊的socket

.netlink可以实现内核与应用程序进行双向传输通讯,并且使用socket()API进行交互

.netlink是一种异步通讯方式,在内核与用户态进行传递的消息保存在socket缓冲区数据队列中,发送消息只是把消息保存在接收者的socket的接收队列中,而不需要等待接收者收到消息

(2)使用socket()创建netlink套接字

int socket(int domain, int type, int protocol);

@domain:协议族 AF_NETLINK or PF_NETLINK

@type :socket类型 SOCK_DGRAM or SOCK_RAW

@protocol : 协议类型 NETLINK_KOBJECT_UEVENT

(3)netlink地址结构

struct sockaddr_nl {

__kernel_sa_family_t nl_family; /* AF_NETLINK */

unsigned short nl_pad; /* zero */

__u32 nl_pid; /* port ID */

__u32 nl_groups; /* multicast groups mask */

};

@nl_family : AF_NETLINK 协议族

@nl_pad : 填0

@nl_pid : 进程pid ,可以通过getpid()获取

(3)使用setsockopt()设置套接字选项

setsockopt(sd, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));

@SO_RCVBUFFORCE:设置或者获取缓冲区的大小

(4)使用bind()绑定地址结构

retval= bind(sd, (void*)&snl, sizeof(struct sockaddr_nl))

(5)读取netlink接收缓冲区的内容

read(sd, buf, sizeof(buf));

扫码申领本地嵌入式教学实录全套视频及配套源码

上一篇:EPOLL的工作原理及流程

下一篇:Linux下科大讯飞语音识别全面总结

400-611-6270

Copyright © 2004-2024 华清远见教育科技集团 版权所有
京ICP备16055225号-5京公海网安备11010802025203号