structzone*zone=pgdat->node_zones+j;
unsignedlongsize,realsize,memmap_pages;
//size=realsize=SDRAM的页表数量,对MSDRAM,其值为x3fff
size=zone_spanned_pages_in_node(nid,j,zones_size);
realsize=size-zone_absent_pages_in_node(nid,j,
zholes_size);
/*
*Adjustrealsizesothatitaccountsforhowmuchmemory
*isusedbythiszoneformemmap.Thisaffectsthewatermark
*andper-cpuinitialisations
*/
memmap_pages=(size*sizeof(structpage))>>PAGE_SHIFT;
if(realsize>=memmap_pages){
realsize-=memmap_pages;
printk(KERN_DEBUG
"%szone:
%lupagesusedformemmap\n",
zone_names[j],memmap_pages);
}else
printk(KERN_WARNING
"%szone:
%lupagesexceedsrealsize%lu\n",
zone_names[j],memmap_pages,realsize);
/*Accountforreservedpages*/
//dma_reserve的值可以从引导程序导入,在此为0
if(j==0&&realsize>dma_reserve){
realsize-=dma_reserve;
printk(KERN_DEBUG"%szone:
%lupagesreserved\n",
zone_names[0],dma_reserve);
}
//is_highmem_idx恒为
if(!
is_highmem_idx(j))
nr_kernel_pages+=realsize;
nr_all_pages+=realsize;
….
}
}
从上述代码可以看出,这两个值都表示可用的页的数量,其表示的内存范围从0到60M,不包含page数组所占用的页。
对于64MSDRAM(实际限制为60M),不启用MTD的情况,其值为0x3b6a。
1.1.4 mem_map
这个全局变量的定义在mm/nommu.c中:
structpage*mem_map;
在内核中每个4K的页都有一个structpage与之相对应,而mem_map就是指向这个page数组的头指针。
它的初始化由alloc_node_mem_map完成:
staticvoid__init_refokalloc_node_mem_map(structpglist_data*pgdat)
{
…
/*ia64getsitsownnode_mem_map,beforethis,withoutbootmem*/
if(!
pgdat->node_mem_map){
unsignedlongsize,start,end;
structpage*map;
/*
*Thezone'sendpointsaren'trequiredtobeMAX_ORDER
*alignedbutthenode_mem_mapendpointsmustbeinorder
*forthebuddyallocatortofunctioncorrectly.
*/
start=pgdat->node_start_pfn&~(MAX_ORDER_NR_PAGES-1);
end=pgdat->node_start_pfn+pgdat->node_spanned_pages;
end=ALIGN(end,MAX_ORDER_NR_PAGES);
size=(end-start)*sizeof(structpage);
map=alloc_remap(pgdat->node_id,size);
if(!
map)
map=alloc_bootmem_node(pgdat,size);
pgdat->node_mem_map=map+(pgdat->node_start_pfn-start);
}
/*
*WithnoDISCONTIG,theglobalmem_mapisjustsetasnode0's
*/
if(pgdat==NODE_DATA(0)){
mem_map=NODE_DATA(0)->node_mem_map;
}
}
从这个函数可以看出,它的值与pglist_data中的node_mem_map成员相同。
在这里pgdat指向全局唯一的pglist_data:
externstructpglist_datacontig_page_data;
pgdat->node_start_pfn的值为0。
pgdat->node_spanned_pages的值为整个SDRAM中的页(4K)数量。
1.1.5 contig_page_data
内核支持所谓的NUMA结构,它将整个系统的存储空间分成几个不连续的节点,每个节点用一个pglist_data进行描述,再将这些节点放在一个链表中,但在BF561系统内核中定义了一个叫NODE_DATA的宏,它的定义在include/linux/mmzone.h中
externstructpglist_datacontig_page_data;
#defineNODE_DATA(nid) (&contig_page_data)
从这个定义可以看出,在内核中实际只有一个pglist_data。
即contig_page_data。
1.1.6 vm_total_pages
这个值的定义在mm/vmscan.c中:
longvm_total_pages; /*ThetotalnumberofpageswhichtheVMcontrols*/
它表示内存的可用页数,其初始化由
void__meminitbuild_all_zonelists(void)
{
…
vm_total_pages=nr_free_pagecache_pages();
printk("Built%izonelists.Totalpages:
%ld\n",
num_online_nodes(),vm_total_pages);
}
函数完成,对于64M内存(实际限制为60M),其值将为0x3b6a。
再读内核存储管理
(2):
相关的数据结构
1.1 相关的数据结构
1.1.1 pglist_data
pglist_data的定义在include/linux/mmzone.h中:
/*
*Thepg_data_tstructureisusedinmachineswithCONFIG_DISCONTIGMEM
*(mostlyNUMAmachines?
)todenoteahigher-levelmemoryzonethanthe
*zonedenotes.
*
*OnNUMAmachines,eachNUMAnodewouldhaveapg_data_ttodescribe
*it'smemorylayout.
*
*Memorystatisticsandpagereplacementdatastructuresaremaintainedona
*per-zonebasis.
*/
structbootmem_data;
typedefstructpglist_data{
structzonenode_zones[MAX_NR_ZONES];
structzonelistnode_zonelists[MAX_NR_ZONES];
intnr_zones;
structpage*node_mem_map;
structbootmem_data*bdata;
unsignedlongnode_start_pfn;
unsignedlongnode_present_pages;/*totalnumberofphysicalpages*/
unsignedlongnode_spanned_pages;/*totalsizeofphysicalpage
range,includingholes*/
intnode_id;
wait_queue_head_tkswapd_wait;
structtask_struct*kswapd;
intkswapd_max_order;
}pg_data_t;
这个结构体用于描述可用存储空间的情况。
l bdata
staticbootmem_data_tcontig_bootmem_data;
structpglist_datacontig_page_data={.bdata=&contig_bootmem_data};
从这个定义还可以看出在这个结构体中,bdata实际将指向一个固定的位置contig_bootmem_data且在mem_init函数调用后此成员将不再使用。
l zone
对于这个结构体中的zone,内核实际只使用了ZONE_DMA(0)这个区域,它的范围从内核代码结束一直到物理内存结束。
l node_id
因为整个内核只使用了一个NODE,因此在这个结构体中node_id的值将为0。
l node_start_pfn
将为0。
l node_spanned_pages和node_present_pages
两个成员的初始化在calculate_node_totalpages函数中完成,它们的值为SDRAM的页表数量,包含未用的区域和内核代码等,其值相等。
对于64M内存而言(实际限制到60M),其值为0x3bff。
l node_mem_map
在内核中每个4K的页都有一个structpage结构体与之对应,这个成员指向这个page数组的首地址,它将在初始化时由alloc_node_mem_map函数进行空间分配(使用bootmem)。
l nr_zones
这个值用于表示可用的zone的最高序号+1。
对于BF561而言,只使用了ZONE_DMA,因此这个值将为1。
1.1.2 per_cpu_pageset
这个结构体的定义在include/linux/mmzone.h中:
enumzone_stat_item{
/*First128bytecacheline(assuming64bitwords)*/
NR_FREE_PAGES,
NR_INACTIVE,
NR_ACTIVE,
NR_ANON_PAGES, /*Mappedanonymouspages*/
NR_FILE_MAPPED, /*pagecachepagesmappedintopagetables.
onlymodifiedfromprocesscontext*/
NR_FILE_PAGES,
NR_FILE_DIRTY,
NR_WRITEBACK,
/*Second128bytecacheline*/