build_zone_zonelists() 初始化備用內存域鏈表node_zonelists

         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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章