linux map 内存,linux系统mem_map的定义和赋值(mips架构)

mem_map 的定义:

在mm/memory.c中:

#ifndef CONFIG_NEED_MULTIPLE_NODES

/* use the per-pgdat data instead for discontigmem - mbligh */

unsigned long max_mapnr;

struct page *mem_map;

EXPORT_SYMBOL(max_mapnr);

EXPORT_SYMBOL(mem_map);

#endif

mem_map的赋值:

arch\mips\kernel\Setup.c\arch_mem_init

arch\mips\mm\Init.c\paging_init

mm\Page_alloc.c\free_area_init_nodes

mm\Page_alloc.c\free_area_init_node

mm\Page_alloc.c\alloc_node_mem_map

mem_map = NODE_DATA(0)->node_mem_map;

转:初始化mem_map

mem_map是一个struct page的数组,管理着系统中所有的物理内存页面。在系统启动的过程中,创建和分配mem_map的内存区域。UMA体系结构中,free_area_init()函数在系统唯一的struct node对象contig_page_data中node_mem_map成员赋值给全局的mem_map变量。调用的关系图:

0818b9ca8b590ca3270a3433284dd417.png

主要的核心函数free_area_init_core(),为node的初始化过程分配本地的lmem_map(node->node_mem_map)。数组的内存在boot memory 分配的alloc_bootmem_node()函数分配.在UMA体系结构中,这个新分配的lmem_map成为全局的mem_map. 对于NUMA体系,lmem_map赋值给每一个node的node_mem_map成员,而这个情况下mem_map就被简单的赋值为PAGE_OFFSET(有兴趣理解NUMA体系结构的可以阅读英文原版,了解更多信息)。UMA体系中,node中的各个zone的zone_mem_map就指向mem_map中的某些元素作为zone所管理的第一个page的地址。

系统中的每个物理页面用struct page数据结构对象来表示,并且跟踪page使用的状态:(省略了一些特定平台用到的成员)

struct page {

unsigned long flags;

atomic_t _count;

union {

atomic_t _mapcount;

unsigned int inuse;

};

union {

struct {

unsigned long private;

struct address_space *mapping;

};

struct kmem_cache *slab;    /* SLUB: Pointer to slab */

struct page *first_page;    /* Compound tail pages */

};

union {

pgoff_t index;          /* Our offset within mapping. */

void *freelist;         /* SLUB: freelist req. slab lock */

};

struct list_head lru;

#if defined(WANT_PAGE_VIRTUAL)

void *virtual;

#endif

};

union {

atomic_t _mapcount;

unsigned int inuse;

}: 和页表转换有关的PTE链,下面章节将描述。

index:这个成员根据page的使用的目的有2种可能的含义。第一种情况:如果page是file mapping的一部分,它指明在文件中的偏移。如果page是交换缓存,则它指明在address_space所声明的对象:swapper_space(交换地址空间)中的偏移。第二种情况:如果这个page是一个特殊的进程将要释放的一个page块,则这是一个将要释放的page块的序列值,这个值在__free_page_ok()函数中设置。

mapping: 当文件或设备需要内存映射,文件或设备的inode对象有一个address_space类型的成员。如果page属于这个文件或设备,mapping将指向inode中这个成员。如果page不属于任何文件或设备,但是 mapping被设置了,则mapping指向了一个address_space类型的swapper_space对象,则page用于管理交换地址空间(swap address space)了。

lru: page交换调度策略使用。page可能被调度到active_list或者inactive_list队列里。就是使用lru这个list_head。

private:这个保存了一些和mapping(文件mapping到内存)有关的一些特定的信息。如果page是一个buffer page,则它就保存了一个指向buffer_head的指针。

virtual: 不再用于将high memory的映射到ZONE_NORMAL区域的作用了,除了一些其他的体系结构会用到外。

count: page的访问计数,当为0是,说明page是空闲的,当大于0的时候,说明page被一个或多个进程真正使用或者kernel用于在等待I/O。

flags:  page状态的标志信息。kernel代码里定义了大量的宏用于设置,清楚,检测flag成员中的各个位所表示的page状态信息。特别提示一下,SetPageUptodate(),它需要调用一个和体系结构有关的函数:arch_set_page_uptodate().

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

映射页面到zone(Mapping page to zones)

在2.4.18内核之前,struct page数据结构中有一个zone的成员,后来证明这样做会无谓的浪费大量的内存空间,因为系统中会有大量的page对象,所以以后版本的page中不在有这样的成员了,而是有一个索引表示,这个索引保存在flag成员中的某些位段中,这个索引占用8个位。2.6.19版本的kernel系统中建立了一个全局的zone数组:

EXPORT_SYMBOL宏的作用,是让zone_table能够被其他载入的模块使用。free_area_init_core()函数对node里的所有page做初始化。

zone_table[nid * MAX_NR_ZONES + j] = zone; //对zone_table做初始化。

nid是node ID。 j是zone的索引。

对每个page调用set_page_zone()初始化page中的zone的索引值(在page->flag中)。

set_page_zone(page, nid * MAX_NR_ZONES + j);

但是2.6.20后就不用这一套了,mm/sparse.c文件中做了一套管理系统。新的方法将多个page组成section来管理。

这里略微描述一下,有兴趣的,可以详细阅读sparse.c的源代码。kernel将所有的page分成多个section管理,对于x86平台,有64个section,每个section管理着(1<<26)个或(1<<30)个(对于支持PAE的情况下)内存区域。

以下是几个主要的define:

include/asm-x86/sparsemem_32.h:

#ifdef CONFIG_X86_PAE

#define SECTION_SIZE_BITS       30

#define MAX_PHYSADDR_BITS       36

#define MAX_PHYSMEM_BITS        36

#else

#define SECTION_SIZE_BITS       26

#define MAX_PHYSADDR_BITS       32

#define MAX_PHYSMEM_BITS        32

#endifinclude/linux/mmzone.h:#define SECTIONS_SHIFT          (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS)#define NR_MEM_SECTIONS         (1UL << SECTIONS_SHIFT)#ifdef CONFIG_SPARSEMEM_EXTREME

#define SECTIONS_PER_ROOT       (PAGE_SIZE / sizeof (struct mem_section))

#else

#define SECTIONS_PER_ROOT       1

#endif#define SECTION_NR_TO_ROOT(sec) ((sec) / SECTIONS_PER_ROOT)

#define NR_SECTION_ROOTS        (NR_MEM_SECTIONS / SECTIONS_PER_ROOT)

#define SECTION_ROOT_MASK       (SECTIONS_PER_ROOT - 1)

首先声明了一个全局的mem_section的全局数组。

struct mem_section *mem_section[NR_SECTION_ROOTS];

调用sparse_add_one_section()函数,分配mem_section,并且初始化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值