percpu_init_late()

 

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()보다 느리다.

 

참고

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.