设备资源管理模块
1.解决的问题
相信每一个写过Linux driver的工程师,都在probe函数中遇到过上面的困惑:在顺序申请多种资源(IRQ、Clock、memory、regions、ioremap、dma、等等)的过程中,只要任意一种资源申请失败,就要回滚释放之前申请的所有资源。 于是在函数的最后,就一定会出现很多的goto标签,用于释放不同的资源(如上面的exit_free_irq、exit_free_dma、等等)。 在申请资源出错时,小心翼翼的goto到正确的标签上,以便释放已申请资源。
这样在代码中,整个函数被大段的、重复的如下代码充斥。
if (!condition)
{
err = xxx;
goto xxx;
}
既浪费精力容易出错,也不美观。 有困惑,就有改善的办法。 方法就是Linux设备模型中的device resource management(设备资源管理)。
2.解决的思路
devres提供了一种机制,用资源节点的形式记录它申请的资源,并在系统中为设备分配一个链表,当申请某个资源时,就构建一个资源节点,然后把它加入到这个链表中,对应的释放函数也会被记录,以便在driver detach的时候,自动释放。
为了使用devres机制,资源要对各自的资源分配函数重新封装,加入资源节点的申请、添加和释放,一般新函数名改成了devm_xxx()的形式。driver作者只管调用这些devm_xxx()接口来申请资源,不用考虑释放,设备模型会在适当的时候释放它们。
device resource management位于“drivers/base/devres.c”中,它实现了上述机制。
3.提供的接口
以下是devres提供的几个基本接口
interface | Description |
---|---|
devres_alloc( ) | // 分配资源节点 |
devres_free( ) | // 释放资源节点 |
devres_add( ) | // 添加资源节点到链表 |
devres_destroy( ) | // 释放资源 |
devres_release_all() | //释放所有资源 |
4.接口的使用
其他资源模块,可以通过调用devres提供的接口,利用devres机制实现资源的自动释放。
4.1 资源节点函数的应用举例
下面的代码是利用devres机制实现分配中断资源函数 devm_request_threaded_irq( ), 上层模块可以调用它来分配中断资源,在出错时,不必考虑对该资源的释放,系统会自动释放。
主要涉及到devres_alloc()、devres_free()和devres_add()
4.2 资源释放函数的应用举例
资源释放函数devres_destroy()的使用举例,资源模块可以用它来封装资源释放函数。
5. 函数的内部实现
5.1 devres_alloc()
devrs_alloc()函数的实现,主要调用了内部函数alloc_dr(), 它会分配size+sizeof(struct devres)的内存大小, struct devres用于存储资源节点信息,并记录release 函数。
5.2 devres_add()
devres_add()主要实现把资源节点添加到设备的资源链表中。
5.3 devres_destroy()
devres_destroy()主要涉及到以下几个内部函数:
- devres_remove() //查找到资源节点,并从链表中删除
- find_dr() //根据release函数指针、match函数查找资源节点
- devres_free() //释放资源节点
可以结合上面它的使用实例来学习。
5.4 devers_release_all()
devers_release_all()的调用会释放所有资源。它的被调用时机有两个:
- really_probe()失败
- 设备与驱动分离时, deriver_dettach时 就是driver_remove时。