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