Linux下I/O资源管理(原理)

下图为示意图,读者可以参考该图来阅读代码。

个人认为对Linux下I/O资源的管理如掌握__request_region函数就能掌握其精髓。

Linux下对I/O资源主要用结构体resource来管理,管理的方法就是用resource来描述使用的I/O资源的状态,并将这些resource用如下两个resource作为表头按地址大小的顺序链接起来。

struct resource ioport_resource = {.name= “PCI IO”,.start= 0,.end= IO_SPACE_LIMIT,.flags= IORESOURCE_IO,};EXPORT_SYMBOL(ioport_resource);struct resource iomem_resource = {.name= “PCI mem”,.start= 0,.end= -1,.flags= IORESOURCE_MEM,};

__request_region函数的主要功能为:查找resource链表中是否有与申请的I/O资源有冲突,如冲突则返回NULL,如不冲突则将新申请resource按resource地址从小到大的顺放插入至以ioport_resource或iomem_resource为表头(root)的单向指针链表中

/*

* This is compatibility stuff for IO resources.** Note how this, unlike the above, knows about* the IO flag meanings (busy etc).** request_region creates a new busy region.** check_region returns non-zero if the area is already busy.** release_region releases a matching busy region.*//*** __request_region – create a new busy resource region* @parent: parent resource descriptor* @start: resource start address* @n: resource region size* @name: reserving caller’s ID string* @flags: IO resource flags*/struct resource * __request_region(struct resource *parent, resource_size_t start, resource_size_t n, const char *name, int flags){struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);//申请resource资源if (!res)return NULL;res->name = name;res->start = start;res->end = start + n – 1;res->flags = IORESOURCE_BUSY;res->flags |= flags;write_lock(&resource_lock);for (;;) {struct resource *conflict;conflict = __request_resource(parent, res);//从parent为表头的资源链表中检查是否当前申请资源冲突,如冲突则返回冲突资源,不冲突则将新申请资源resource结构体插入链表中if (!conflict)//没有冲突资源(说明申请资源成功)则返回break;if (conflict != parent) {//如冲突资源为不是parent,则将冲突资源作为parent,此处可能有人会问为什么冲突资源不是parenet就将conflict作为 parent呢,将在下面回答该问题。parent = conflict;if (!(conflict->flags & IORESOURCE_BUSY))//IORESOURCE_BUSY表示正在申请的资源,此处表示如果冲突资源不属正在申请的资源则继续申请continue;}/* Uhhuh, that didn’t work out.. *///申请资源与parent资源冲突退出。kfree(res);res = NULL;break;}write_unlock(&resource_lock);return res;}

EXPORT_SYMBOL(__request_region);

下面我们再看__request_resource函数

该函数先确保新申请资源在root的范围之内,接着从第

static struct resource * __request_resource(struct resource *root, struct resource *new){resource_size_t start = new->start;resource_size_t end = new->end;struct resource *tmp, **p;//检查申请资源与parent是否冲突if (end < start)return root;if (start < root->start)return root;if (end > root->end)return root;

//如上已确保新申请资源在parent的范围之内(条件A)p = &root->child;//从第1个儿子开始查找是否与链表中的资源冲突for (;;) {tmp = *p;if (!tmp || tmp->start > end) {//!tmp,说明要对比资源不存在(条件B)。tmp->start > end,,说明对比资源在新增加资源后面(条件C)

//将新增资源插入到对比资源的前面(所以资源resource在链表中是以地址范围从小到大排序,如示意图所示)

if (tmp->end < start)//如成立说明新申请资源在当前所对比资源的后面,则继续用兄弟资源与新资源进行对比。不成立说明新申请资源与当前资源有冲突continue;return tmp;}}

解疑:在__request_region函数中为什么冲突资源不是parenet就将conflict作为 parent呢?

对此处的回答我也只是通过代码推理,并无找代码中的实例

假设您申请如上130~180的I/O空间,后来又将135~175的I/O resource 释放掉

您再申请135~145的I/O空间不就会遇到冲突资源,并将conflict资源作为parent再申请的情况了吗!

而消极的人则在每个机会都看到某种忧患。

Linux下I/O资源管理(原理)

相关文章:

你感兴趣的文章:

标签云: