⑥如果上述两条件不能同时满足,则说明还没有找到,因此要继续扫描链表。在继续扫描之前,我们还是要判断一下this指针是否为空。如果为空, 说明已经扫描完整个child链表,因此就可以推出for循环了。否则就将new->start的值修改为this->end+1,并让 this指向下一个兄弟资源节点,从而继续扫描链表中的下一个子资源节点。
3.2.5 分配接口allocate_resource()
在find_resource()函数的基础上,函数allocate_resource()实现:在一颗资源树中分配一条指定大小的、且包含在指定区域[min,max]中的、未使用资源区域。其源代码如下:
/* * Allocate empty slot in the resource tree given range and alignment. */int allocate_resource(struct resource *root, struct resource *new, unsigned long size, unsigned long min, unsigned long max, unsigned long align, void (*alignf)(void *, struct resource *, unsigned long), void *alignf_data){ int err; write_lock(&resource_lock); err = find_resource(root, new, size, min, max, align, alignf, alignf_data); if (err >= 0 && __request_resource(root, new)) err = -EBUSY; write_unlock(&resource_lock); return err;}
3.2.6 获取资源的名称列表
函数get_resource_list()用于获取根节点root的子资源名字列表。该函数主要用来支持/proc/文件系统(比如实现proc/ioports文件和/proc/iomem文件)。其源代码如下:
int get_resource_list(struct resource *root, char *buf, int size){ char *fmt; int retval; fmt = " %08lx-%08lx : %s"; if (root->end < 0x10000) fmt = " %04lx-%04lx : %s"; read_lock(&resource_lock); retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf; read_unlock(&resource_lock); return retval;}
可以看出,该函数主要通过调用内部静态函数do_resource_list()来实现其功能,其源代码如下:
/* * This generates reports for /proc/ioports and /proc/iomem */static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end){ if (offset < 0) offset = 0; while (entry) { const char *name = entry->name; unsigned long from, to; if ((int) (end-buf) < 80) return buf; from = entry->start; to = entry->end; if (!name) >"; buf += sprintf(buf, fmt + offset, from, to, name); if (entry->child) buf = do_resource_list(entry->child, fmt, offset-2, buf, end); entry = entry->sibling; } return buf;}
函数do_resource_list()主要通过一个while{}循环以及递归嵌套调用来实现,较为简单,这里就不在详细解释了。
3.3 管理I/O Region资源
Linux将基于I/O映射方式的I/O端口和基于内存映射方式的I/O端口资源统称为“I/O区域”(I/O Region)。I/O Region仍然是一种I/O资源,因此它仍然可以用resource结构类型来描述。下面我们就来看看Linux是如何管理I/O Region的。
3.3.1 I/O Region的分配
在函数__request_resource()的基础上,Linux实现了用于分配I/O区域的函数__request_region(),如下:
struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name){ struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL); if (res) { memset(res, 0, sizeof(*res)); res->name = name; res->start = start; res->end = start + n - 1; res->flags = IORESOURCE_BUSY; write_lock(&resource_lock); for (;;) { struct resource *conflict; conflict = __request_resource(parent, res); if (!conflict) break; if (conflict != parent) { parent = conflict; if (!(conflict->flags & IORESOURCE_BUSY)) continue; } /* Uhhuh, that didn't work out.. */ kfree(res); res = NULL; break; } write_unlock(&resource_lock); } return res;}
NOTE:
①首先,调用kmalloc()函数在SLAB分配器缓存中分配一个resource结构。
②然后,相应的根据参数值初始化所分配的resource结构。注意!flags成员被初始化为IORESOURCE_BUSY。
③接下来,用一个for循环开始进行资源分配,循环体的步骤如下: