下圖為示意圖,讀者可以參考該圖來閱讀代碼。
個人認為對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.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再申請的情況了嗎!