5.1.5 初始化地址散列表
560行,page_address_init()函数,来自mm/highmem.c:
409void __init page_address_init(void) 410{ 411 int i; 412 413 INIT_LIST_HEAD(&page_address_pool); 414 for (i = 0; i < ARRAY_SIZE(page_address_maps); i++) 415 list_add(&page_address_maps[i].list, &page_address_pool); 416 for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) { 417 INIT_LIST_HEAD(&page_address_htable[i].lh); 418 spin_lock_init(&page_address_htable[i].lock); 419 } 420 spin_lock_init(&pool_lock); 421} |
这个函数很简单,首先413初始化一个链表page_address_pool,这个链表在编译的时候被定义成一个全局变量在同一个文件的309行:
static struct list_head page_address_pool
414行,page_address_maps也是个全局变量,来自同一个文件:
static struct page_address_map page_address_maps[LAST_PKMAP];
其每一个元素是一个page_address_map结构:
struct page_address_map {
struct page *page;
void *virtual;
struct list_head list;
};
OK,第一次见到我们熟悉的page数据结构了。一个page代表一个物理页面,想要深入了解这方面知识的请访问博客“Linux页框管理”。
ARRAY_SIZE获得数组的元素个数,这里肯定就是LAST_PKMAP了,由于我们没有启动PAE,这个值等于1024,也就是说page_address_maps共有1024个元素。随后415行,1024个循环以后,page_address_pool通过每个page_address_maps的元素的list字段将他们全部链接起来形成个双向循环链表,又page_address_pool作为head。
416行,page_address_htable,也定义于同一文件:
static struct page_address_slot {
struct list_head lh; /* List of page_address_maps */
spinlock_t lock; /* Protect this bucket's list */
} ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER];
____cacheline_aligned_in_smp是一个编译优化选项,用于SMP方式的缓存优化。PA_HASH_ORDER被定义为7,所以2^7=128。所以ARRAY_SIZE(page_address_htable)为128,那么经过128个循环以后,每个page_address_htable元素的lh都被初始化成一个链表头了,而对于的互斥锁lock也通过spin_lock_init函数进行初始化了。具体的初始化过程请查阅博客“Linux内核入门(三)—— C语言基本功”以及“自旋锁”。
最后page_address_pool的自旋锁pool_lock初始化之后,函数就结束了。简单归简单,但是大家必须知道这个函数的意义。我们知道一个page结构代表一个4k的页面,我们内核初始化这么一个全局的page_address_maps和page_address_htable这么两个结构,作为页面的地址映射。
561行,执行一个printk函数。start_kernel()开始执行至此,会显示“Linux version 2.6.34…”信息。