上一章我们分析了regmap子系统,本章我们讨论一下linux设备驱动模型的设备资源管理,linux设备资源管理虽然是一个小模块,却起到了一个很大的功能,那就是设备资源的自动释放功能。目前新版的内核中各设备驱动模块基本上都提供了基于设备资源管理的接口。
设备资源管理也可以理解为设备相关的资源垃圾回收功能,设备资源管理的实现虽然不复杂,却真的是解决了一个很大的问题,具体来说就是,在没有设备资源管理时,我们在设备驱动的probe接口中,需要进行内存的申请,并且各设备驱动模块自行维护申请的内存资源(在设备驱动卸载时进行内存资源的释放操作),这样的话每一个设备驱动程序都存在了大量的内存资源的释放操作(在remove接口中将申请的内存资源释放掉),而设备资源管理出来以后,各设备驱动模块只需要在probe接口中调用支持设备资源管理的接口实现内存的申请即可,而无需关注内存的释放,这样的话remove接口就完全不需要关注内存的释放,且无需关注内存的释放以及设备的注销等等。
设备资源管理实现的基础
在进行设备资源管理的实现前,我们先看下设备驱动模型的引用计数功能。设备驱动模型主要借助kobject的kref实现引用计数功能,针对struct device、kobject、kref等结构体的关联如下:
struct device借助于其struct kobject kobj成员的kref,即可实现对struct device的引用计数功能。
而设备驱动模型就是借助struct device这种引用计数机制,实现针对struct device的资源自动释放功能。如下图所示,当我们调用device_unregister注销device时,完成设备与device、bus的解绑之后,即调用put_device完成对device引用计数减一,当引用计数为0后即调用kobject_release进行资源的释放,而针对设备驱动模型而言,其最终会调用struct kobj_type device_ktype.release接口,即接口device_release接口,而在device_release接口中dev->release、dev->type->release接口进行资源的释放(如针对platform device则会调用platform_device_release进行platform device相关的资源释放)。
而设备资源管理模块也是借助上述机制,只是在上图的基础上增加了对申请的设备资源的释放接口,如下图总红色标注的部分即为设备资源管理的释放接口。这就是设备资源管理模块申请的资源自动释放的基础。
设备资源管理的实现
为了支持设备资源管理,在struct device中增加了链表头成员devres_head,该链表中存储了所有该设备申请的资源(此处主要指通过设备资源管理接口devres_alloc、devres_add申请并添加到该链表上的资源)。同时又创建了两个数据结构struct devres_node、struct devres,其中struct devres_node主要实现将申请的设备资源加入到的devres_head链表上,并提供该资源的释放接口,而struct devres则主要定义了struct devres_node类型的节点变量、以及零长度数组data,而data即为申请的内存首地址,该指针会返回给应用模块使用。如下图即是struct device、struct devres_node、struct devres的关联。
设备资源管理模块提供接口devres_alloc用于设备资源的申请(根据传递的申请内存大小,申请struct devres,并将申请成功的内存资源的首地址struct devres->data返回给用户)、而devres_add则实现将通过devres_alloc申请的资源加入到struct device的devres_head链表中。该模块也提供了devm_kmalloc接口进行内存的释放(该接口申请到内存后,则使用者不用关注内存的释放工作了,当然了用户也可以调用接口devm_kfree手动释放)。
而设备资源模块申请的资源在什么时候释放呢?,在上面我们已经介绍了,即device release时,调用devres_release_all接口释放链表devres_head上所有的资源。
本章我们主要分析了设备资源管理模块的实现流程,借助设备驱动模型的引用计数即设备释放流程,设备资源管理模块的实现就水到渠成了。虽然实现起来不复杂,但该模块的出现确实让设备驱动的开发更简便了,从此在设备驱动开发中,涉及到内存资源申请时,再也无需关注申请资源的释放操作了。以上就是本篇文章的主要内容。