[kernelreadfans] summarization about "understanding linux vm"

  • From: "oyk" <oyk@xxxxxxxxxxx>
  • To: kernelreadfans <kernelreadfans@xxxxxxxxxxxxx>
  • Date: Wed, 4 Jun 2003 21:47:3 +0800

Hi,guys
1. Linux对Memory的认知。
Linux采用NUMA(Non-Uniform Memory 
Access)组织物理内存。根据CPU访问内存的"距离"("distance"),将内存分为不同的bank,每一个bank称为一个node,每一个node通过数据结构pg_data_t描述,所有的nodes通过pgdat_list全局链表链接,具体的划分机制和平台相关。由于我只有I386体系的机子,因此,我们现在只考虑I386体系。I386认知所有物理内存为一个node,记为contig_page_data,故而pgdat_list链表也只有contig_page_data一个结点。因此,我们可以认为I386体系其实质是采用的UMA机制。我认为Linux采用NUMA机制的目的是最大限度地提高代码的可扩展性和平台间可移植性。
对于一个node,Linux最多可以将其分成3个域(zone):ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。在I386体系中:ZONE_DMA负责最开始16MB;ZONE_NORMAL负责16MB~896MB(内核可以直接访问的物理空间);ZONE_HIGHMEM负责896MB以后的空间(内核不能直接访问的物理空间)。每个域是通过数据结构zone_t描述。而具体的内存页面是通过数据结构page描述的。
1.1 区域水位
每个zone都有三个水位,当前自由页面数目与这三个水位值比较,决定pageout守护进程kswapd的操作:
pages_min: 
当自由页面数目小于等于pages_min时,kswapd必须以同步模式工作,申请页面的进程必须sleep直到自由页面数目超过pages_min。
pages_low: 
当自由页面数目小于等于pages_low时,kswapd进程被唤醒,通过buddy分配器释放页面,以增加自由页面数目;pages_low缺省是pages_min的两倍。
pages_high:当自由页面数目大于等于pages_high时,kswapd不会被唤醒,系统认为zone是平稳、安定的(balanced)。
Pfree小于pages_min,大于pages_high都好理解。其它的情况,我的理解是:
假设Pfree属于(pages_min, pages_low): 
kswapd是可以唤醒的,并通过buddy分配器释放页面;假设Pfree属于(pages_low, 
pages_high): 系统认为该zone不是"balanced",需要kswapd调整平衡值。
1.2 Linux支持的最大区域
<mm/page_alloc.c>
zone_t *zone_table[MAX_NR_ZONES*MAX_NR_NODES];
系统能支持的最大zone数目是MAX_NR_ZONES(一个node支持的最大zone数目)乘以MAX_NR_NODES(系统支持的最大node数目),zone_table是存放系统区域结构地址指针数组的首地址。
建立页面和区域之间的联系:
<include/linux/mm.h>
static inline void set_page_zone(struct page *page, unsigned long zone_num)
{
        page->flags &= ~(~0UL << ZONE_SHIFT);
        page->flags |= zone_num << ZONE_SHIFT;
}
2. 页表管理
Linux采用了与平台无关性的三级页表管理(PGD-PMD-PTE-Offset),如果硬件平台只支持两级页面管理(没有使用PAE机制的I386体系),Linux只是将PMD设置为1,其实质是两级页面管理了。
2.1 I386页表类型定义
<include/asm-i386/page.h>
#if CONFIG_X86_PAE
typedef struct { unsigned long pte_low, pte_high; } pte_t;
typedef struct { unsigned long long pmd; } pmd_t;
typedef struct { unsigned long long pgd; } pgd_t;
#define pte_val(x)      ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
#else
typedef struct { unsigned long pte_low; } pte_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
#define pte_val(x)      ((x).pte_low)
#endif
这段定义,我们需要注意的是PAE模式下pte_t的定义:pte_high指向36位地址线的高4位。
typedef struct { unsigned long pgprot; } pgprot_t;
pgprot_t用于表示存储页面属性,每一个页面属性存储在pte_t的低12位里。具体属性类型定义在include/asm-i386/pgtable.h中。比如:
#define _PAGE_USER      0x004
static inline int pte_read(pte_t pte)           { return (pte).pte_low & 
_PAGE_USER; }

waiting.........
Best Regards
  Ouyang Kai



Other related posts:

  • » [kernelreadfans] summarization about "understanding linux vm"