build_zone_zonelists() 建立管理結點及其內存域所需的數據結構,即node_zonelists數組。
type struct pglist_data{
...
struct zonelists node_zonelists[MAX_ZONELISTS];
...
}pg_data_t;
node_znoelists 指定了備用結點(node)及其內存域(zone)的鏈表,以便在當前結點沒有可用空間時,在備用結點分配內存。在UMA中只有一個結點,所以不用考慮備用結點(node)鏈表。在UMA中,MAX_ZONELISTS=1, 即node_zonelists數組有且只有一個元素。在linux-4.4中利用struct zoneref數組結構管理備用內存區,這與linux-2.6存在很大差異。源碼中詳細介紹了struct zoneref。
struct zonelist {
struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];
};
/*
* This struct contains information about a zone in a zonelist. It is stored
* here to avoid dereferences into large structures and lookups of tables
*/
struct zoneref {
struct zone *zone; /* Pointer to actual zone */
int zone_idx; /* zone_idx(zoneref->zone) */
};
通過start_kernel()->build_all_zonelists()調用,linux在系統啓動期間,初始化了node_zonelists數組。
static int __build_all_zonelists(void *data)
{
...
/* 遍歷每個正在使用的結點, UMA 有且只有一個結點。 */
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
build_zonelists(pgdat);
}
...
}
build_zonelists()初始化node_zonlists數組元素。UMA中node_zonelists數組中只有一個元素。
static void build_zonelists(pg_data_t *pgdat)
{
...
zonelist = &pgdat->node_zonelists[0];
j = build_zonelists_node(pgdat, zonelist, 0);
/*
* Now we build the zonelist so that it contains the zones
* of all the other nodes.
* We don't want to pressure a particular node, so when
* building the zones for node N, we make sure that the
* zones coming right after the local ones are those from
* node N+1 (modulo N)
*/
/* UMA中只有一個結點,沒有備用結點,因此不需要關注 */
....
/* ! 注意 : struct zonelist中成員數組_zonerefs是以NULL結尾 */
zonelist->_zonerefs[j].zone = NULL;
zonelist->_zonerefs[j].zone_idx = 0;
}
build_zonelists_node() 針對某個結點建立備用內存域(zone)鏈表。以內存域(zone)分配代價由低到高的初始化_zoneref數組。我是debian 64位系統,若沒有激活ZONE_MOVABLE虛擬可移動內存域爲例:
/*
* Builds allocation fallback zone lists.
*
* Add all populated zones of a node to the zonelist.
*/
static int build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist,
int nr_zones)
{
struct zone *zone;
enum zone_type zone_type = MAX_NR_ZONES;
do {
zone_type--;
zone = pgdat->node_zones + zone_type;
if (populated_zone(zone)) {
zoneref_set_zone(zone,
&zonelist->_zonerefs[nr_zones++]);
check_highest_zone(zone_type);
}
} while (zone_type);
return nr_zones;
}
參考:professional linux kernel architecture 深入linux內核架構
參考源碼:linux-4.4