Linux高端内存管理之非连续内存区(描述)


总结了高端内存区的固定内核映射区、临时内核映射与永久内核映射。但是对于高端内存中各个区间的布置我们任然不是很清楚,首先我们从整体上看看内核对高端内存的划分情况。

如果内存足够大(比如用户:内核线性空间=3:1,内核就只能访问线性空间的第4GB内容,如果物理内存超过1GB则视为足够大),内核线性空间无法同时映射所有内存。这就需要将内核线性空间分出一段不直接映射物理内存,而是作为窗口分时映射使用到的未映射的内存。

相关阅读:

一、非连续内存区布局

Linux内核中对于非连续区间的开始:

[cpp]
  1. #define VMALLOC_START   ((unsigned long)high_memory + VMALLOC_OFFSET)  
[cpp]
  1. #define VMALLOC_OFFSET  (8 * 1024 * 1024)  
对于变量high_memory变量:

[cpp]
  1. void __init initmem_init(unsigned long start_pfn,  
  2.                   unsigned long end_pfn)  
  3. {  
  4.     highstart_pfn = highend_pfn = max_pfn;  
  5.     if (max_pfn > max_low_pfn)  
  6.         highstart_pfn = max_low_pfn;  
  7. ……  
  8.     num_physpages = highend_pfn;  
  9.     /*高端内存开始地址物理*/  
  10.     high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;  
  11. ……  
  12. }   

其中,变量max_low_pfnhighmem_pfn_init()函数中初始化为下面值

[cpp]
  1. #define MAXMEM  (VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE)  
[cpp]
  1. <p>unsigned int __VMALLOC_RESERVE = 128 << 20;</p>  
对于非连续区间的结束定义:

[cpp]
  1. # define VMALLOC_END    (PKMAP_BASE - 2 * PAGE_SIZE)  

由上面的内核代码,画出内存布局细节图如下

Linux高端内存管理之非连续内存区(描述)

由上面的布局可知128M+4M+4M+8K,然而直接映射区和连续内存之间空出来了8M的空间不能用,非连续空间和永久内核映射区之间也有8K的空间不可用,另外,内存顶端空出了4K不可用的。这样,高端内存能用的空间为128M+4M+4M+8K-4K-8M-8K=128M-4K大小的内存。

二、数据结构描述

虚拟内存区描述(对于vmlist链表)

[cpp]
  1. struct vm_struct {  
  2.     struct vm_struct    *next;  
  3.     void            *addr;/*内存区的第一个内存单元的线性地址*/  
  4.     unsigned long       size;  
  5.     unsigned long       flags;/*类型*/  
  6.     struct page     **pages;/*指向nr_pages数组的指针,该数组由指向页描述符的指针组成*/  
  7.     unsigned int        nr_pages;/*内存区填充的页的个数*/  
  8.     unsigned long       phys_addr;/*该字段设为0,除非内存已被创建来映射一个硬件设备的IO共享内存*/  
  9.     void            *caller;  
  10. };  

虚拟内存区描述(对于红黑树)

[html]
  1. struct vmap_area {  
  2.     unsigned long va_start;  
  3.     unsigned long va_end;  
  4.     unsigned long flags;  
  5.     struct rb_node rb_node;     /* address sorted rbtree */  
  6.     struct list_head list;      /* address sorted list */  
  7.     struct list_head purge_list;    /* "lazy purge" list */  
  8.     void *private;  
  9.     struct rcu_head rcu_head;  
  10. };  

内存区由next字段链接到一起,并且为了查找简单,他们以地址为次序。为了防止溢出,每个区域至少由一个页面隔离开。

Linux高端内存管理之非连续内存区(描述)
三、非连续内存区初始化 非连续内存区的初始化工作在start_kernel()->mm_init()->vmalloc_init()完成 [cpp]
  1. void __init vmalloc_init(void)  
  2. {  
  3.     struct vmap_area *va;  
  4.     struct vm_struct *tmp;  
  5.     int i;  
  6.   
  7.     for_each_possible_cpu(i) {  
  8.         struct vmap_block_queue *vbq;  
  9.   
  10.         vbq = &per_cpu(vmap_block_queue, i);  
  11.         spin_lock_init(&vbq->lock);  
  12.         INIT_LIST_HEAD(&vbq->free);  
  13.         INIT_LIST_HEAD(&vbq->dirty);  
  14.         vbq->nr_dirty = 0;  
  15.     }  
  16.   
  17.     /* Import existing vmlist entries. */  
  18.     for (tmp = vmlist; tmp; tmp = tmp->next) {/*导入vmlist中已经有的数据到红黑树中*/  
  19.         va = kzalloc(sizeof(struct vmap_area), GFP_NOWAIT);  
  20.         va->flags = tmp->flags | VM_VM_AREA;  
  21.         va->va_start = (unsigned long)tmp->addr;  
  22.         va->va_end = va->va_start + tmp->size;  
  23.         __insert_vmap_area(va);  
  24.     }  
  25.   
  26.     vmap_area_pcpu_hole = VMALLOC_END;  
  27.   
  28.     vmap_initialized = true;/*已经初始化*/  
  29. }  
  • 1
  • 2
  • 下一页

相关内容