歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux下I/O資源管理(原理)

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

日期:2017/2/28 16:06:13   编辑:Linux教程

下圖為示意圖,讀者可以參考該圖來閱讀代碼。

個人認為對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在鏈表中是以地址范圍從小到大排序,如示意圖所示)

new->sibling = tmp;
*p = new;
new->parent = root;
return NULL;
}
p = &tmp->sibling;//從如上if 條件tmp->start > end不成立得出對比資源有可能與申請資源沖突或其地址范圍在當前對比資源的後面,將兄弟指針保存以便後續用兄弟資源與新申請資源進行比較。
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再申請的情況了嗎!

Copyright © Linux教程網 All Rights Reserved