리눅스/커널2012. 10. 15. 09:29

출처: Professional Linux Kernel Architecture

division 보다 multiplication 이 빠르기에,


C = A/B 를 하는 대신, C = A * 1/B를 하는 방식이다.  


역시 B가 1/B가 되므로 이 경우, B의 값이 compile-time에 알려진 경우에 한정된다.


커널에서는 다음의 함수에서 위에 내용에 대한 부분을 확인 할 수 있다.


reciprocal_divide(A, reciprocal_value(B))


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

initarray_cache vs arraycache_init  (0) 2012.10.21
BYTES_PER_WORD  (0) 2012.10.15
linux kernel, mem_init()  (0) 2012.10.05
루프백(loopback) 장치 vs 루프(loop) 장치  (0) 2012.10.03
가상 메모리 관리  (0) 2012.10.03
Posted by code cat
리눅스/커널2012. 10. 5. 17:10

void mem_init(void)


free_unused_memmap(struct meminfo &mi)


fee the unused area of the memory map.

with bank=1, non sparse memory, there isn't much to do


free_unused_memmap(struct meminfo *mi)


mem_map array can get very big, hence free the unused area of the memory map

loop thru' each bank and store bank_start

if we had a previous bank, and there is a space between the current bank and the prevous, free it

align up since the VM subsystem insists that the memmap entries are valid from the bank end aligned to MAX_ORDER_NR_PAGES(the maximum number of pages that can be managed by buddy system)


free_all_bootmem(void)


iterate through each node registered to bootmem_node, and free all the pages registered in the bitmap, and finally return the number of pages freed


free_highpages(void)


CONFIG_HIGMEN isn't defined, so nothing to do here



for_each_bank(i, &meminfo)


assign meminfo.bank[0] to membank and calculate bank pfn start&end using membank

convert pfn start&end to page start&end

iterate through pages and add up the number of reserved pages and free pages


for_each_memblock(memory, reg)


since the memory may not be contiguous, calculate the real number of pages in the system by iterating each memory region and adds up the number of pages

this is where you see

"Memory: xxxMB

"Memory: xxx k/ xxx k available, xxx k reserved, xxx k highmem"

"Virtual kernel memory layout:

"vector : ..

"fixmap : ...

"DMA :

"vmalloc

"lowmem:

"pkmap

"modules:

".init

".text

'.data

".bss


sysctl_overcommit_memory = OVERCOMMIT_ALWAYS


if the number of the page does not exceeds a certain value(PAGE_SIZE >= 16384 && num_physpages(128)),

set overcommit as always


__init kmem_cache_init(void)


num_possible_nodes()


with uma system, there's only one node, so there you go; it returns 1

and if this is the case, use_alien_caches = 0



for(i = 0; i < NUM_INIT_LISTS; i++)


NUM_INIT_LISTS = (3 * MAX_NUMNODES) = 3

kmem_lists3_init(&initkmem_list3[i])  /* param type : struct kmem_list3 *parent*/


/* if you don't what this shit is, read my slab allocator note */

  * initkmem_list3[0] = full slab list

  * initkmem_list3[1] = partial slab list

  * initkmem_list3[2] = free slab list 

   */

build list header by using INIT_LIST_HEAD for slabs_full, slabs_partial, slabs_free

set follow properties:

shared = NULL, alien = NULL, colour_next = 0, free_objects  = 0, free_touched = 0

initialize spin lock for initkmem_list3[i]->list_lock

if the index, i, is less than MAX_NUMNODES(1), assign cache_cache.nodelists[i] to NULL


set_up_list3s(&cache_cache, CACHE_CACHE)


iterate through each node(we only have single node), and

setup kmem_cache->nodelists[0] with &initkmem_list3[0 + CACHE_CACHE] /*CACHE_CACHE = 0*/

plus setup reap time, which is a time interval that the kernel must allow to elapse between two attempts to shrink the cache.  %It is to easy system performance cost due to frequent cache shrinking and growing operation %


slab_break_gfp_order = BREAK_GFP_ORDER_HI


if RAM size is over 32M, slab_break_gfp_order is set to BREAK_GFP_ORDER_HI


Bootstrap is tricky, because several objects are allocated from caches that do not exist yet:


1. initialize the cache_cache cache : 

it contains the struct kmem_cache structures of all caches, except cache_cache itself; cache_cache is statically allocated.  Initially, an __init data area is used for the head array and the kmem_list3 sructures, but it's replaced with a kmalloc allocated array at the end of the bootstrap.


2. create the first kmalloc cache:

the struct kmem_cache for the new cache is allocated normally.  an __init data area is used for the head array


3. create the remaining kmalloc cache with minimally sized head array


4. replace the __init data head array for cache_cache and the first kmalloc cache with kmalloc allocated arrays


5. replace the __init data for kmem_list3 for cache_cache and the other cache's with kmalloc allocated memory


6. resize the head arrays of the kmalloc caches to their final sizes


INIT_LIST_HEAD(&cache_chain)

initialize cache chain linked list


list_add(&cache_cache.next, &cache_chain)

add cache_cache.next to cache_chain

setup the rest of properties for cache_cache


for (order = 0; order < MAX_ORDER; order++)


cache_estimate(order, cache_cache.buffer_size, cache_line_size(), 0, &left_over, &cache_cache.num)


based on the object size(buffer_size), get the number of object, the size for the managment data



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

BYTES_PER_WORD  (0) 2012.10.15
Newton-Raphson technique  (0) 2012.10.15
루프백(loopback) 장치 vs 루프(loop) 장치  (0) 2012.10.03
가상 메모리 관리  (0) 2012.10.03
Slab allocator (슬랩 할당자)  (0) 2012.10.03
Posted by code cat
리눅스/커널2012. 10. 3. 16:16

루프백 장치(loopback device)는 통신에서 시그널이나 데이터 스트림들을 변형없이 발생한 소스로 되돌리는 pseudo 장치를 말한다.  대부분 transmission 테스트를 할 때 사용된다.


루프장치(loop device)는 파일을 블록 디바이스 형태로 접근할 수 있도록 해 주는 pseudo 장치를 말한다.


헷갈리지 말자.


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

Newton-Raphson technique  (0) 2012.10.15
linux kernel, mem_init()  (0) 2012.10.05
가상 메모리 관리  (0) 2012.10.03
Slab allocator (슬랩 할당자)  (0) 2012.10.03
GFP_KERNEL vs GFP_ATOMIC vs GFP_USER vs GFP_DMA  (0) 2012.09.16
Posted by code cat
리눅스/커널2012. 10. 3. 13:55

출처: 리눅스 커널 내부구조


각 태스크는 task_struct 이라는 자료구조를 가지고 있다.

메모리 가상 관리를 위해 다음가 같은 hierarchy를 가지고 있다.

task_struct

struct mm_struct

vm_area_struct


vm_area_struct의 vm_end와 vm_start는 가상 메모리 공간에서 vm_area_struct이 가리키는 세그먼트의 끝 주소와, 시작주소를 각각 가리킨다.


물리 메모리 관리와 같이 가상 메모리 역시 고정된 크기(4kb)의 할당 단위로 관리되며 이를 page라 부른다.(물리 메모리의 page frame과 혼동하지 말자)  결국 공통의 속성을 갖는 페이지들이 모여 vm_area를 구성하고, 이를 vm_area_struct라는 자료구조로 관리한다. 그리고 결국 이런 vm_area_struct들이 모여 하나의 mm_struct 내에서 괸리된다.(위의 계층구조를 보자)


그러나 cpu는 물리 메모리에 대한 직접적인 엑세스를 하는게 아니라 가상주소를 참조한다.  그러므로, 이를 위해 페이지 테이블이 존재하고 페이지 테이블을 통해 가상 메모리와 물리 메모리를 연결해 준다.


참고로 버디나 슬랩 할당자를 통해 할당받는 메모리 공간은 늘 물리 메모리상에서 연속이다.


여기서 커널은 어떻게 가상 주소를 물리주소로 변환할까?  리눅스 커널 또한 3~4GB의 가상 주소 공간에서 동작하기에 페이징 단계를 거쳐야 가상 주소를 물리 주소로 변환할 수 있다.  그럼 위에서와 같이 mm_struct안에 pgd(페이지 글로벌 디렉터리)값을 알아야 하는데, 커널한테는 둘다 존재 하지 않고, 커널 자신을 위한 페이지 테이블을 시스템 부팅 시점에 미리 작성해 놓고, 이 위치를 swapper_pg_dir이라는 전역 변수에 저장해 놓고 사용한다.


3GB            1MB              8MB             16MB                                 896MB                                                 4GB

bios comm area 

kernel code image 

DMA region 

mem_map 

Direct Mapping 

vmalloc 

kmap 

fixed mapping 


mem_map은 물리 메모리를 위한 페이지 프레임 자료 구조가 있다.

Direct Mapping은 가상 주소와 물리주소가 direct mapping되어 있어, 간단하게 가장주소-3GB를 통해 가상 주소를 바로 물리 메모리로 연결할 수 있다.

Posted by code cat
리눅스/커널2012. 10. 3. 00:45

출처: 리눅스 커널 내부구조

리눅스에서 메모리의 최소 할당 단위는 페이지 프레임이라고 알고 있다.  근데 만약 그 이하의 공간이 필요할 때는 어떻게 하는 게 좋을까?  그냥  4kb 던져주는게 좋을까?  말할것도 없이 공간낭비이다.

 

대신 미리 정해진 사이즈의 cache를 가지고 있다가 필요할 때 할당한다면 어떨까?  32byte에서 2의 오더로 128kb 까지 유지해서 말이다.

 

각 cache들은 슬랩들로 구성되고, 슬랩은 다시 객체(Object)들로 구성된다.

 

예를 들어 64byte cache이면,

Object (64byte) --> slab (full/free/partial) --> cache

와 같은 구조로 이루어져 있다.  64byte 공간들이 각각의 객체이고, 이 객체들이 슬랩이 되고, 이 슬랩들이 cache가 되는 것이다.

 

참고로 리눅스는 다양한 크기의 캐시를 효율적으로 관리하기 위해 kmem_cache_t라는 자료 구조를 만들어 두었고, 새로운 캐시를 생성시에 kmem_cache_t라는 구조체로부터 할당 받는다.  이 때 슬랩할당자로부터 할당받는 것이다.

kmem_cache_t 구조체 크기의 객체를 담고 있는 cache의 이름이 cache_cache이다.

당연히 cache_cache는 다른 캐시들보다 먼저 생성되어야 한다(그래야 다른 캐시를 만들 때 할당이 가능하지 않겠는가?)  그 후에 cache_cache를 이용해서 kmem_cache_t를 위한 공간을 할당받아 다양한 캐시를 생성한다.

 

슬랩할당자는 이외에도 외부 인터페이스 함수로 kmalloc(), kfree()를 제공한다.(그래서 kmalloc()를 통해 한번에 할당 받는 최대 크기가 128k라는 걸 눈치 챘을 것이다.)

Posted by code cat
리눅스/커널2012. 9. 16. 20:44

 

GFP_ATOMIC

메모리가 있으면 할당 없으면 NULL. 휴면 불가능

GFP_KERNEL

메모리 할당이 항상 성공하도록 요구, 메모리가 충분하지 않을 경우는 호출한 프로세스를 멈추고 동적 메모리 할당할 수 있는 상태가 될때까지 대기. 휴면가능.

GFP_USER

유저 메모리를 할당함.  휴면 가능 

GFP_DMA

연속된 물리 메모리를 할당 받을 때 사용

 

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

가상 메모리 관리  (0) 2012.10.03
Slab allocator (슬랩 할당자)  (0) 2012.10.03
include/linux/fs.h 2.6.35 vs 3.0  (0) 2012.09.16
boot memory allocator 의 필요성  (0) 2012.09.04
defunct 프로세스 죽이기  (0) 2012.08.16
Posted by code cat
리눅스/커널2012. 9. 16. 19:26

왘 가 네... ioctl이 어디 간거지...??


Linux Kernel 2.6.35 



Linux Kernel 3.0




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

Slab allocator (슬랩 할당자)  (0) 2012.10.03
GFP_KERNEL vs GFP_ATOMIC vs GFP_USER vs GFP_DMA  (0) 2012.09.16
boot memory allocator 의 필요성  (0) 2012.09.04
defunct 프로세스 죽이기  (0) 2012.08.16
kmalloc, cache allocator  (0) 2012.07.20
Posted by code cat
리눅스/커널2012. 9. 4. 23:20
boot memory allocator

컴파일 타임에 커널에서 사용하는 그 많은 structure들을 초기화 시킨다는 것은 불가능하다. 그런 structure들을 초기화 시켜주기 위해서는 메모리가 필요한데 그 이유는 physical page allocator조차 자기자신을 초기화 하기 위해서는 메모리가 필요하기 때문이다.


iPhone 에서 작성된 글입니다.

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

GFP_KERNEL vs GFP_ATOMIC vs GFP_USER vs GFP_DMA  (0) 2012.09.16
include/linux/fs.h 2.6.35 vs 3.0  (0) 2012.09.16
defunct 프로세스 죽이기  (0) 2012.08.16
kmalloc, cache allocator  (0) 2012.07.20
리눅스커널 timestamp 찍는 법  (0) 2012.07.18
Posted by code cat
리눅스/커널2012. 8. 16. 09:54

defunct 라고 나오는 프로세스는 우리가 흔히 알고 있는 Zombie 프로세스로 부모 프로세스에서 아직 wait을 부르지 않은 상태이다.

ps 시 defunct라고 나오는 프로세스를 죽일라면 부모 프로세스를 찾아서 부모 프로세스를 죽여야 한다.  부모가 죽은 고아 프로세스는 결국 init프로세스에서 회수에서 처리하기 때문이다.

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

include/linux/fs.h 2.6.35 vs 3.0  (0) 2012.09.16
boot memory allocator 의 필요성  (0) 2012.09.04
kmalloc, cache allocator  (0) 2012.07.20
리눅스커널 timestamp 찍는 법  (0) 2012.07.18
__user  (0) 2012.07.01
Posted by code cat
리눅스/커널2012. 7. 20. 21:25
cache allocator 의 핵심:
1) 메모리를 각각 다른 사이즈의 오브젝트 들끼리 모아놓은 pool 들로 나누는 것
2) 메모리 할당에 대한 request가 오면 1)에서 맞는 사이즈를 가진 pool을 리턴

이런 pool들을 cache하고 하며 kmem_cache_t 의 타입으로 선언되어 있다. kmem_cache_t에는 cache에 대한 여러가지 정보를 담을 수 있는 변수들이 준비되어 있다.
kmem_cache_create()를 통하여 cache를 생성할 수 있다.
kmem_cache_create()는 caller에서 넘겨중 사이즈만한 cache를 생성하며 cache_cache라는 생성된 cache들의 global list에 넣는다.

cache_cache는 static kmem_cache_t 타입이며 시스템 전반적으로 cache들을 가지고 있다. 따라서 pool이 속해있는 object들의 사이즈는 sizeof(kmem_cache_t) 이다. 시스템 전반에 걸친 cache들에 대한 정보는 /proc/slabinfo에서 볼 수 있다. cache_cache외에도 cache들의 array 형태로 되어있는 일반적인 cache들이 있다. array마다 2배수로 커지는 사이즈 형태이며 각 사이즈별로 2개의 cache(일반 cache, DMA용 cache)가 있다. kmalloc()은 이 일반적인 cache들에서 맞는 사이즈의 cache를 찾고 __kmem_cache_alloc()으로 cache 오브젝트을 caller에게 넘겨주는 일을 한다.
유사하게 kfree() 은 __kmem_cache_free()으로 오브젝트를 cache에 돌려준다.

iPhone 에서 작성된 글입니다.

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

boot memory allocator 의 필요성  (0) 2012.09.04
defunct 프로세스 죽이기  (0) 2012.08.16
리눅스커널 timestamp 찍는 법  (0) 2012.07.18
__user  (0) 2012.07.01
__initcall(), module_init()  (0) 2012.07.01
Posted by code cat