'리눅스 커널 메모리'에 해당되는 글 1건

  1. 2012.03.18 Virtual Linux Manager 정리 1
리눅스/커널2012. 3. 18. 20:20

출처: virtual linux manager by Mel Gorman

memory 는 bank로 나뉘어짐
bank는 node라고 불리며,
node는 struct pglist_data로 표현됨.(UMA일때도 마찬가지)

pglist_datapg_data_t로 참조된다. 
시스템의 모든 node는 NULL로 끝나는 pgdata_list 이라는 리스트로 관리된다.
그리고 각 node는 pg_data_t->node_next로 다른 node와 연결된다.

UMA의 경우 contig_page_data라는 하나의 pg_data_t 구조체를 사용한다.(노드가 하나 이니까)

각 node는 'zone' 이라 불리는 여러개의 블록으로 나뉜다.

zone은 struct zone_struct 이라는 구조체로 정의되며, zone_t로 사용자정의된다.

zone의 종류에는,
ZONE_DMA 
ZONE_NORMAL
ZONE_HIGHMEM
(ZONE_MOVEABLE)
이 있다.
 
신경써야 할 부분은 ZONE_NORMAL이다.  ZONE_HIGHMEM은 ZONE_NORMAL의 상위 위쪽 부분이다.

시스템의 메모리는 page frame이라는 고정된 chunk들로 이루어져 있다.
각각의 physical page frame들은 struct page라는 구조체로 표현되며,
이 모든 구조체들은 mem_map이라는 배열에 저장된다.
(mem_map은 보통 ZONE_NORMAL 시작부분이나 지정된 커널 로딩 영역 뒤에 저장된다)

2.1 Nodes
리눅스는 page를 할당할 때, node-local alloocation policy를 사용해서
현재 실행 중인 CPU에서 가장 가까운 node의 메모리를 할당한다.

pg_data_t, 즉 pglist_data는 다음가 같이 정의되어 있다.


  node_zones ZONE_HIGHMEM, ZONE_NORMAL_ZNOE_DMA가 있다. 
  node_zonelists  zone들이 할당되는 순서를 가지고 있다.  free_area_init_core()에 호출 된 mm/page_alloc.c의 build_zonelists()가  순서를 정한다.
  nr_zones zones의 갯수 
  valid_addr_bitmap 메모리 node에 있는 "holes" 에 대한 비트맵 
  bdata boot memory allocator  
  node_start_paddr node의 시작 주소(physical)   Page Frame Number(PFN)에 기록하는게 좋다.   PFN은 physicla memory의 index이며, page-sized unit 단위로 세어진다.
PFN 은 (page_phys_addr >> PAGE_SHIFT) 로 손쉽게 정의될 수 있다. 
  node_start_mapnr 전역 mem_map안의 page offset.  
 free_area_init_core()에서 mem_map과 지역적 mem_map사이의 페이지 개수로 계산됨 
  node_size zone안의 총 page 수 
  node_id  node ID (NID).  0부터 시작함 
  node_next 위에서 말한 node list의 다음 node를 가리킴 
             
앞서 말했듯이, 시스템의 모든 node들은 pgdat_list라는 리스트에서 관리되며, init_bootmem_core()에 의해 이 리스트에 추가된다.


2.2 Zones

각 zone들은 struct zone_struct으로 구성된다. (linux/mmzone.h 참조)

내용은 다음과 같다.

  lock zone을 보호하는 spinlock 
  free_pages zone에 존재하는 free page  

  pages_min,   page_low, pages_high 

 
  zone_pgdata pg_data_t 를 가리킨다.
  zone_mem_map 전역 mem_map 
  zone_start_paddr node_start_paddr와 유사 
  zone_start_mapnr node_start_mapnr와 유사 
  name zone 이름, "DMA", "NORMAL", "HighMem" 
  size pages단위로 표현된 zone의 사이즈 

 

2.2.1 Zone Watermarks

시스템에 남아있는 메모리가 적을 경우, kswapd라는 pageout 데몬이 실행되어 page들을 free하기 시작한다.  만약 메모리를 많이 회수해야 한다면, kswapd 데몬은 동기적으로 메모리를 free 한다.(이 방식은 direct-reclaim이라고 불리기도 한다.)

각 zoned은 세가지의 watermark를 가지고 있는데, 이들은 각각 다음과 같다.

 pages_low

 free page의 수가 pages_low에 이르면, kswapd가 buddy allocator에 의해 깨어나서 page들을 free한다

 pages_min

 pages_min에 이르면, buddy allocator는 kswapd를 동기화적으로 돌린다.

 pages_high

 page_high에 이르면 kswapd는 다시 sleep으로 돌아간다.

pages_minfree_area_init_core()에서 메모리 초기화 과정에서 page 단위로 표현된 zone의 크기로 표현되어 계산된다.


2.2.2 Calculating the size of Zones

각 zone의 크기는 setup_memory()에서 계산된다.

PFN은 pages단위로 세어진 실제 메모리 맵(physical memory map)안의 오프셋이다.

min_low_pfn은 첫번째 PFN이며, _end 다음의 첫번째 페이지에 위치한다.  min_low_pfn은 나중에 쓰일 boot memory allocator를 위해 mm/bootmem.c 에 file scope 변수로 지정되어 있다.

unsigned long min_low_pfn;

unsigned long max_low_pfn;

unsigned long max_pfn;

마지막 페이지 프레임인 max_pfn 은 아키텍쳐 의존적으로 계산된다.  x86의 경우 find_max_pfn()으로 e820 map을  통해 가장 높은 값을 갖는 페이지 프레임을 읽는다. (e820은 BIOS를 통해 얻어지는 테이블이며, 어떤 physicla memory가 있는지, 예약되어 있는지등을 알려준다)  

max_low_pfn은 (x86의 경우) find_max_low_pfn()을 통해 계산되며, 이는 ZONE_NORMAL의 끝을 표시한다.

                          ZONE
_end   
 min_low_pfn                     first page 
                       pages ...
 max_low_pfn            end of ZONE_NORMAL     <- kernel/userspace split point


2.2.3 Zone Wait Queue Table

(생략)

 

2.3 Zone Initialization

zone 들은 kernel page table 이 paginig_init()에 의해 완전히 세팅되고 나면 초기화 된다.  페이지 테이블 초기화에 대해서는 3.6을 참조하자.

아키텍쳐마다 방식에는 다르겠지만, 기본적으로 UMA 일 경우, free_area_init()에 보낼 매개변수를, NUMA일 경우, free_area_init_node()에 보낼 매게변수를 결정한다.  이 매게변수들은 다음과 같다.

  nid 초기화 될 zone을 가지고 있는 NODE의 NODE id 
  pgdat 초기화되는 node의 pg_data_t이며, UMA의 경우 contig_page_data이다. 
  pmap free_area_init_core()에 의해 지정되며, local mem_map의 시작부분을 가리킨다. NUMA는 mem_map을 PAGE_OFFSET에 시작하는 가상 배열로 생각하기 때문에 무시하며, UMA의 경우 pmap은 global mem_map을 가리킨다. 
  zone_sizes 각 zone의 크기를 담고 있는 배열 
  zone_start_paddr 첫번째 zone의 시작 실제 주소(starting physical address) 
  zone_holes zones에 있는 메모리 홀의 총 사이즈를 담고 있는 배열 

free_area_init_core()는 각 zone_t의 내용을 연관성이 있는 정보로 채우는 역활 및 mem_map 배열 할당을 한다.  현 상황에서는 어떤 페이지가 free인지는 알 수 없으며, boot memory allocator의 작업이 끝날 때 까지는 알 수 없다.

 

2.4 Initializing mem_map

mem_map은 시스템 초기화 과정에서 생성된다.

NUMA의 경우, global mem_map이 PAGE_OFFSET에서 시작하는 가상 배열로 취급되며, 각 node 마다 free_area_init_node()를 호출하여 이 가상 배열을 할당한다.  

UMA의 경우, free_area_init()contig_page_data를 node로, global mem_map을 local mem_map으로 동일하게 취급한다.

locla mem_map은 free_area_init_core()에 의해 할당되며, 이를 위한 배열은 boot memory allocator가 alloc_bootmem_node()를 호출하여 할당한다.  UMA의 경우, 이렇게 할당된 메모리는, 위에서 말한 거 처럼, global mem_map이 되나, NUMA의 경우 조금 다르다.  NUMA는 local mem_map을 각 node의 고유한 메모리에서 할당하며, global mem_map의 경우 따로 할당되지는 않으나, (가상 배열로 취급되는)PAGE_OFFSET으로 설정된다.  local map은 pg_data_t->node_mem_map에 저장된다.

node에 존재하는 각 zone들은  가상 mem_map의 주소를 zone_t->zone_mem_map에 저장한다.  이 외의 작업에서는 mem_map을 실제 배열로 취급한다.

 

2.5 Pages

모든 시스템의 physical page frame은 struct page를 가지고 있다.


      





'리눅스 > 커널' 카테고리의 다른 글

__initcall(), module_init()  (0) 2012.07.01
리눅스 커널 분석 시 아키텍쳐별 tag 및 cscope생성  (0) 2012.04.16
GCC, typeof  (0) 2012.02.23
Documentation/arm/booting  (0) 2011.09.25
Linux 3.0 Kernel  (0) 2011.07.31
Posted by code cat