Download presentation
Presentation is loading. Please wait.
1
Chapter 7. Getting Hold of Memory
kmalloc 동일 크기 할당(lookaside caches) 페이지 단위 할당 vmalloc 부팅 시 메모리 할당 순천향대학교 정보기술공학부 이 상 정
2
단원 소개 이 장에서는 드라이버가 시스템의 메모리를 효과적으로 사용하는 방법을 소개
커널이 드라이버에게 일관된 메모리 관리 인터페이스를 제공 모듈에서는 세그멘테이션, 페이징 등과 같은 내용들은 관여하지 않음 메모리 관리에 관한 자세한 내용은 13장의 “Memory Management in Linux” 에서 자세히 기술 순천향대학교 정보기술공학부 이 상 정
3
kmalloc 순천향대학교 정보기술공학부 이 상 정
4
kmalloc 소개 kmalloc은 물리 메모리의 연속적인 영역을 할당
할당된 영역의 이전의 값을 클리어하지 않음 첫번째 인수는 할당될 블록의 크기이고, 두번째 인수는 할당 플래그 #include <linux/malloc.h> void *kmalloc(unsigned int size, int priority); GFP_KERNEL(GFP는 get_free_pages) 플래그 가장 자주 사용되는 플래그로 현재 프로세스 상에서 시스템 콜을 수행 메모리가 부족한 경우 페이지를 기다리는 수면에 들어감 따라서 GFP_KERNEL을 사용하여 메모리를 할당하는 함수는 재진입(reentrant)이 가능해야 함 현재 프로세스가 수면에 있는 동안 커널은 메모리 페이지를 구하기 위해 버퍼를 디스크에 배출(flushing)하거나 사용자 프로세스의 메모리를 제거하고 스와핑(swapping out) 등을 하여 메모리 영역을 확보 GFP_ATOMIC 플래그 kmalloc이 프로세스 컨텍스트의 밖에서 호출하고 수면에 들어가지 않음 예를들어 인터럽트 핸들러, 태스크 큐, 커널 타이머에서 호출 커널은 빈 페이지들을 유지할려고 노력하지만 마지막 페이지까지 다 써서 메모리가 부족하면 할당은 실패 순천향대학교 정보기술공학부 이 상 정
5
플래그 GFP_KERNEL GFP_BUFFER GFP_ATOMIC GFP_USER GFP_HIGHUSER __GFP_DMA
커널 메모리의 일반적인 할당으로 수면에 들어갈 수도 있음 GFP_BUFFER 버퍼 캐시를 관리하는데 사용되고 수면에 들어갈 수도 있음 GFP_KERNEL과 다른 점은 더티 페이지들을 디스크에 배출하여 메모리를 비우려는 시도를 줄임 GFP_ATOMIC 인터럽트 핸들러와 프로세스 컨텍스트 밖의 코드에서 메모리를 할당하고자 할 때 사용되며 절대 수면에 들어가지 않음 GFP_USER 사용자를 위해 메모리를 할당하는데 사용되며 수면에 들어갈 수도 있고, 우선순위가 낮은 요청 GFP_HIGHUSER 사용자를 위해 상위메모리(high memory)를 할당 __GFP_DMA 디바이스와 DMA 데이터 전송을 위해 사용될 메모리를 요청 플랫폼에 종속적이고, 플래그는 GFP_KERNEL이나 GFP_ATOMIC과 OR될 수 있음 __GFP_HIGHMEM 상위 메모리를 요청 순천향대학교 정보기술공학부 이 상 정
6
메모리 영역(memory zones) 2.4 버전 커널은 표준 메모리, DMA 가능 메모리, 상위 메모리로 세가지 영역으로 구분 플랫폼 종속적인 플래그 __GFP_DMA, __GFP_HIGHMEM 플래그를 사용하여 각 영역에 메모리를 할당 메모리 영역과 관련된 메커니즘은 mm/page_alloc.c에서 구현 DMA 가능 메모리(DMA-capable memory) 주변장치와 DMA 전송에 관여하는 메모리 주소버스가 일반 RAM을 접근하는 주소버스와 비교해서 주변장치와 프로세서를 연결하는 주소버스에 제한이 있다는 점에서 표준 메모리와 차이 예를들어 ISA 버스에 삽입되는 디바이스들은 0-16MB 주소 메모리만을 사용 상위 메모리(high memory) 물리메모리를 64GB까지 확장을 위해 펜티엄 II의 가상 메모리 확장(virtual memory extension)을 지원하는 커널 메모리 관리를 위해 2.3 버전에서 도입 순천향대학교 정보기술공학부 이 상 정
7
크기 인수 리눅스 커널은 페이지 단위로 사용되는 시스템의 물리메모리를 관리
고정된 크기 메모리 객체(object)들 풀(pool)의 세트를 생성하여 관리 메모리 할당 요청 시 충분히 큰 크기의 객체들로 이루어진 풀들을 조사하여 전체 메모리 묶음을 반환 디바이스 드라이버 개발자가 알아야 할 것은 커널이 미리 정의된 고정된 크기의 바이트의 배열들을 할당 임의의 바이트를 요청하면 요청한 것보다 약간 많은-최대 2배까지- 메모리가 할당 kmalloc이 다루는 최소 메모리는 아키텍처가 사용하는 페이지 크기에 따라 32 또는 64 바이트 보통 데이터 크기가 2의 멱승으로 표시되는데, 커널 2.0에서는 관리 시스템에 의해 추가되는 제어 플래그로 인해 2의 멱승보다 작게 됨 scull에서 퀀텀의 크기를 4096 대신 4000으로 사용한 이유 할당되는 블록들의 정확한 크기는 mm/kmalloc.c(2.0 커널)이나 mm/slab.c(현재 커널)에서 기술 순천향대학교 정보기술공학부 이 상 정
8
동일 크기 할당(Lookaside Caches )
순천향대학교 정보기술공학부 이 상 정
9
캐시 객체 생성함수 lookaside cache는 같은 크기의 많은 객체(메모리)들을 할당하는데 사용
USB, ISDN 드라이버가 이 캐시를 사용 캐시 객체들을 생성 함수 kmem_cache_t * kmem_cache_create(const char *name, size_t size, size_t offset, unsigned long flags, void (*constructor)(void *, kmem_cache_t *, unsigned long flags), void (*destructor)(void *, kmem_cache_t *,unsigned long flags) ); 인수 size 만큼의 동일한 크기의 메모리 영역들을 구성할 수 있는 새로운 캐시 객체들을 생성 인수 name에는 대개 캐시되는 구조체의 타입의 이름으로 지정 offset은 페이지에서 첫번째 객체의 오프셋으로 할당된 객체들을 위한 정렬를 보장하는데 사용될 수 있지만 대개 디폴트로 0이 세팅 flags는 할당을 제어하며 다음 플래그들의 비트 마스크 SLAB_NO_REAP: 이 플래그가 세팅되면 시스템이 메모리를 요구할 때 캐시가 줄어드는 것을 방지한다. 대개 이 플래그를 세팅하지 않음 SLAB_HWCACHE_ALIGN: 각 데이터 객체들이 캐시 라인에 정렬되도록 함 SLAB_CACHE_DMA: 각 데이터 객체가 DMA-가능 메모리에 할당 constructor와 destructor 인수는 선택적인 함수이다. 전자는 새로 할당된 객체들을 초기화하는데 사용되며, 후자는 메모리를 시스템에 해제하기 전에 객체들을 클린업(clean up)하는데 사용 순천향대학교 정보기술공학부 이 상 정
10
할당 및 해제 함수 일단 객체들의 캐시가 생성되었으면 kmem_cache_alloc을 호출하여 객체들을 할당
void *kmem_cache_alloc(kmem_cache_t *cache, int flags); cache 인수는 전에 생성했던 캐시이고 플래그는 kmalloc에 전달되는 플래그와 동일 kmem_cache_free는 객체를 해제 void kmem_cache_free(kmem_cache_t *cache, const void *obj); 모듈에서 드라이버가 제거될 때 다음과 같이 캐시를 제거 int kmem_cache_destroy(kmem_cache_t *cache); 순천향대학교 정보기술공학부 이 상 정
11
Slab 캐시를 사용한 scull : scullc
scullc는 scull의 축약형으로 지속적인 메모리 영역의 디바이스를 kmalloc이 아닌 메모리 캐시를 사용하여 구현한 버전 퀀텀의 크기는 실행 시가 아닌 컴파일이나 로드 시에만 수정 실행 시에 수정하려면 새로운 메모리 캐시를 생성해야 되기 때문에 배제 scullc는 scull에 비해 속도가 다소 빠르고 더 효율적으로 메모리를 사용 퀀텀의 크기가 메모리 단편화의 크기와 정확히 일치하기 때문에 메모리 단편화를 예측할 수 없는 scull에 비해 조밀하기 때문 순천향대학교 정보기술공학부 이 상 정
12
scullc 소스 (1) 캐시 생성 및 제거 소스 75 /* declare one cache pointer: use it for all devices */ kmem_cache_t *scullc_cache; 562 /* init_module: create a cache for our quanta */ scullc_cache = kmem_cache_create("scullc", scullc_quantum, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); /* no ctor/dtor */ if (!scullc_cache) { result = -ENOMEM; goto fail_malloc2; } 597 /* cleanup_module: release the cache of our quanta */ kmem_cache_destroy(scullc_cache); 순천향대학교 정보기술공학부 이 상 정
13
scullc 소스 (2) 메모리 할당 및 해제 300 /* Allocate a quantum using the memory cache */ if (!dptr->data[s_pos]) { dptr->data[s_pos] = kmem_cache_alloc(scullc_cache, GFP_KERNEL); => scull, dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL); if (!dptr->data[s_pos]) goto nomem; memset(dptr->data[s_pos], 0, scullc_quantum); } 510 for (i = 0; i < qset; i++) if (dptr->data[i]) kmem_cache_free(scullc_cache, dptr->data[i]); kfree(dptr->data); 순천향대학교 정보기술공학부 이 상 정
14
페이지 단위 할당 순천향대학교 정보기술공학부 이 상 정
15
페이지 단위 할당 (1) 모듈이 큰 크기의 메모리를 사용하는 경우 페이지 단위로 할당 페이지 단위 할당 함수
페이지 단위로 할당하면 속도도 약간 증가하지만 가장 큰 이점은 효율적으로 메모리를 사용하여 메모리 낭비가 없음 한 페이지 전체를 다 사용한다는 이점 페이지 단위 할당 함수 unsigned long get_zeroed_page(int flags); 새 페이지의 포인터를 리턴하고 페이지를 0으로 초기화 unsigned long __get_free_page(int flags); get_zeroed_page와 같고, 다만 페이지를 클리어하지 않음 unsigned long __get_free_pages(int flags, unsigned long order); 여러 페이지들(물리적으로 연속적인)을 할당하고 할당된 메모리 영역에서 첫 바이트의 포인터를 리턴 unsigned long __get_dma_pages(int flags, unsigned long order); DMA 가능 메모리에 할당된다는 점만 제외하고 __get_free_pages와 같다(커널 2.0 버전). __get_free_pages() 함수에 __GFP_DMA 플래그를 기술해도 됨 순천향대학교 정보기술공학부 이 상 정
16
페이지 단위 할당 (2) flags는 kmalloc의 플래그와 같음 order는 베이스가 2인 로그(log2N)로 표시되는 페이지의 크기 예를들어 1 페이지는 0, 8 페이지는 3으로 표시된다. 최대값은 5(리눅스 2.0, 32 페이지)에서 9(최근버전, 512 페이지)까지 표시 페이지를 해제 함수 void free_page(unsigned long addr); void free_pages(unsigned long addr, unsigned long order); 순천향대학교 정보기술공학부 이 상 정
17
전체 페이지를 사용하는 scull : scullp
메모리 할당 코드 290 /* Here's the allocation of a single quantum */ if (!dptr->data[s_pos]) { dptr->data[s_pos] = (void *)__get_free_pages(GFP_KERNEL, dptr->order); if (!dptr->data[s_pos]) goto nomem; memset(dptr->data[s_pos], 0, PAGE_SIZE << dptr->order); } 메모리 해제 코드 부분 511 /* This code frees a whole quantum-set */ for (i = 0; i < qset; i++) if (dptr->data[i]) free_pages((unsigned long)(dptr->data[i]), dptr->order); 순천향대학교 정보기술공학부 이 상 정
18
vmalloc 순천향대학교 정보기술공학부 이 상 정
19
vmalloc 소개 (1) vmalloc은 가상주소공간(virtual address space) 상에서 연속적인 메모리 영역을 할당 페이지들이 물리 메모리 상에서 연속적이지 않지만(각 페이지는 개개의 __get_free_page를 호출하여 할당) 커널은 이들을 하나의 연속적인 주소영역으로 간주 새로운 페이지 테이블 구축하기 때문에 __get_free_pages 보다도 오버헤드 큼 할당 성공 시 최소한 size 크기의 선형 메모리 영역의 포인터를 리턴하고, 실패 시 0(NULL 주소)을 리턴 페이지 테이블을 위한 기억공간 확보를 위해 kmalloc(GFP_KERNEL)을 내부적으로 사용하기 때문에 수면에 들어갈 수 있어서 인터럽트 시간에 사용될 수 없음 vmalloc 할당 및 해제 함수 #include <linux/vmalloc.h> void * vmalloc(unsigned long size); void vfree(void * addr); 순천향대학교 정보기술공학부 이 상 정
20
vmalloc 소개 (2) kmalloc, get_free_pages vmalloc
리턴되는 메모리 주소는 가상주소로 MMU(memory management unit)에 의해 물리주소로 변환 가상주소의 범위는 물리 메모리와 일-대-일 매핑 vmalloc 사용되는 주소범위는 완전히 새로이 합성되고 페이지 테이블에 의해 설정된 메모리 영역을 할당 드라이버가 실제 물리메모리 주소(시스템 버스를 구동하기 위해 주변장치에 의해 사용되는 DMA 주소들과 같이)가 필요할 때 vmalloc은 사용할 수 없음 vmalloc은 소프트웨어 상에서 존재하는 큰 시퀀셜 버퍼를 위한 메모리를 할당하는 경우 등에 사용 순천향대학교 정보기술공학부 이 상 정
21
ioremap() 함수 vmalloc과 같이 ioremap은 새로운 페이지 테이블을 구축하지만 vmalloc과는 달리 어떤 메모리도 할당하지 않는 함수 ioremap은 지정된 물리메모리 영역을 접근하기 위해 가상주소 할당 void *ioremap(unsigned long phys_addr, unsigned long size); 가상주소는 iounmap을 호출하여 해제 void iounmap(void * addr); ioremap은 PCI 버퍼의 (물리) 주소를 (가상) 커널영역으로 매핑하는데 유용 예를들어 PCI 비디오 디바이스의 프렘임 버퍼를 접근하는데 사용 이러한 버퍼들은 대개 상위 물리 주소들에 매핑되는데 이는 커널이 부팅 시 구축하는 페이지 테이블의 영역을 벗어남 ioremap과 vmalloc은 페이지 지향이어서 재배치 또는 할당되는 크기는 페이지 단위 순천향대학교 정보기술공학부 이 상 정
22
가상주소를 사용하는 scull: scullv
scullv는 vmalloc을 사용하여 데이터의 공간을 확보한 scull의 간소화된 버전 모듈은 한 번에 16개 페이지의 메모리를 할당 __get_free_pages를 사용하여 한 페이지 이상 할당하면 실패하기 쉽고 성공해도 느림 vmalloc은 여러 페이지를 할당하는데 다른 함수들보다 빠르지만 페이지 테이블 구축 오버헤드로 인해 한 페이지를 가져오는 데는 느림 scullv 소스 scullv는 scullp와 비슷하게 설계 scullv와 scullp는 새로운 메모리를 확보하기 위해 vmalloc을 사용하는 할당관리 부분만 다름 Order는 각 할당의 “order”를 표시하며 디폴트로 4를 가짐 순천향대학교 정보기술공학부 이 상 정
23
scullv 소스 메모리 할당 /* Allocate a quantum using virtual addresses */ if (!dptr->data[s_pos]) { dptr->data[s_pos] =(void *)vmalloc(PAGE_SIZE << dptr->order); if (!dptr->data[s_pos]) goto nomem; memset(dptr->data[s_pos], 0, PAGE_SIZE << dptr->order); } 메모리 해제 /* Release the quantum set */ for (i = 0; i < qset; i++) if (dptr->data[i]) vfree(dptr->data[i]); 순천향대학교 정보기술공학부 이 상 정
24
부팅 시 메모리 할당 순천향대학교 정보기술공학부 이 상 정
25
부팅 시 메모리 할당 물리적으로 연속적인 큰 메모리 버퍼가 필요한 경우에는 부팅 시에 메모리를 할당
이 기법은 유연성이 없고 좋은 방식은 아니지만 메모리 확보 실패할 가능성이 적은 방식 그러나 모듈은 부팅 시 메모리를 할당할 수 없고 커널에 직접 연결된 드라이버만이 할당 부팅 시 메모리 할당은 자신의 고유 메모리 풀을 확보하여 모든 메모리 관리 정책들을 무시하기 때문에 “dirty”한 기법 부팅 시 할당은 일반 사용자 옵션으로 가능하지 않고 커널 이미지에 연결된 코드에서만 사용 가능 즉, 이를 이용하는 드라이버는 커널을 다시 컴파일하여 구축하고 재 부팅해야만 설치되고 수정 가능 순천향대학교 정보기술공학부 이 상 정
26
부팅 시 메모리 할당 함수 #include <linux/bootmem.h>
void *alloc_bootmem(unsigned long size); void *alloc_bootmem_low(unsigned long size); void *alloc_bootmem_pages(unsigned long size); void *alloc_bootmem_low_pages(unsigned long size); 순천향대학교 정보기술공학부 이 상 정
27
과제 실행, 결과 및 코드 분석 7장에서 소개된 소스 예 분석 scullc scullp scullv
순천향대학교 정보기술공학부 이 상 정
Similar presentations