percpu_init_late()
mm/percpu.c
/* * First and reserved chunks are initialized with temporary allocation * map in initdata so that they can be used before slab is online. * This function is called after slab is brought up and replaces those * with properly allocated maps. */ void __init percpu_init_late(void) { struct pcpu_chunk *target_chunks[] = { pcpu_first_chunk, pcpu_reserved_chunk, NULL }; struct pcpu_chunk *chunk; unsigned long flags; int i; for (i = 0; (chunk = target_chunks[i]); i++) { int *map; const size_t size = PERCPU_DYNAMIC_EARLY_SLOTS * sizeof(map[0]); BUILD_BUG_ON(size > PAGE_SIZE); map = pcpu_mem_zalloc(size); BUG_ON(!map); spin_lock_irqsave(&pcpu_lock, flags); memcpy(map, chunk->map, size); chunk->map = map; spin_unlock_irqrestore(&pcpu_lock, flags); } }
slab(slub) 메모리 관리자가 활성화된 이후 pcpu_first_chunk와 pcpu_reserved_chunk에서 사용한 할당 map을 새로 할당 받은 메모리에 복사한다.
pcpu_mem_zalloc()
mm/percpu.c
/** * pcpu_mem_zalloc - allocate memory * @size: bytes to allocate * * Allocate @size bytes. If @size is smaller than PAGE_SIZE, * kzalloc() is used; otherwise, vzalloc() is used. The returned * memory is always zeroed. * * CONTEXT: * Does GFP_KERNEL allocation. * * RETURNS: * Pointer to the allocated area on success, NULL on failure. */ static void *pcpu_mem_zalloc(size_t size) { if (WARN_ON_ONCE(!slab_is_available())) return NULL; if (size <= PAGE_SIZE) return kzalloc(size, GFP_KERNEL); else return vzalloc(size); }
요청 size로 메모리 할당 후 0으로 초기화한다.
- 요청 size가 PAGE_SIZE보다 작은 경우 kzalloc() 함수를 사용하고
- 물리적으로 연속된 메모리가 확보되며 빠르지만 파편화된 메모리로 인해 실패할 확률이 vzalloc보다 크다. 따라서 작은 사이즈의 메모리의 할당에 더 어울린다.
- DMA 버퍼에 사용하는 메모리는 물리적으로 연속된 메모리의 할당이 요구된다.
- 요청 size가 PAGE_SIZE보다 큰 경우 vzalloc() 함수를 사용한다.
- 연속된 물리 주소는 필요하지 않고 연속된 가상 주소만 있으면 되는 상황에서 사용된다. kzalloc()보다 파편화되지 않는다. 내부적으로는 여러 번의 kzalloc()함수가 호출되어 관리되어 사용되므로 kzalloc()보다 느리다.
참고
- Per-cpu -1- (Basic) | 문c
- Per-cpu -2- (초기화) | 문c
- Per-cpu -3- (동적 할당) | 문c
- Per-cpu -4- (atomic operations) | 문c
percpu 관련 내용 중 궁금한 점이 있습니다..
percpu중에서 static하게 사용되는 영역은 컴파일 타임에 정적영역에 존재하다가 커널이 수행되면서
cpu별로 자기만의 공간이 따로 확보되는것 같더라고요 각각의 offset 영역으로 점프해서 그곳을 자기의 percpu공간으로 사용하는거 같은데
그게 맞는것인가요??
만약 그렇다면 컴파일타임에 생성된 원래 공간은 아무데도 활용되지 않는다고 보면 되는 건가요??
안녕하세요?
생각하신대로 static 선언된 per-cpu 데이터들은 smp cpu 수 만큼 복사하여 사용합니다.
그리고 원래 공간(.data..percpu 섹션)은 초기화 이후에도 그냥 삭제하지 않고 남겨두는 것 같습니다.
아무래도 static으로 선언한 데이터 크기가 수십K 정도밖에 안되므로 그냥 방치(?)하는 듯 합니다.
감사합니다.