pgtable_init()

<kernel v5.0>

페이지 테이블용 슬랩 캐시 준비

pgtable_init()

include/linux/mm.h

static inline void pgtable_init(void)
{
        ptlock_cache_init();
        pgtable_cache_init();
}

페이지 테이블용 슬랩 캐시들을 준비한다.

  • page->ptl에 사용되는 슬랩 캐시
  • pgd 테이블용 슬랩 캐시
    • x86, arm에서는 빈 함수이다.

 

page->ptl용 슬랩 캐시 준비

DEBUG_SPINLOCK과 DEBUG_LOCK_ALLOC이 활성화된 경우 수 만개 이상의 페이지에 사용되는 page->ptl용 spinlock_t 사이즈가 커진다. 이를 kmalloc 메모리 할당자를 통해 할당하게 되면 2의 배수 크기 중 하나를 사용하게 되므로 사용하지 못하고 낭비되는 메모리 양이 매우 커진다. 이에 따라 디버그 상황에서는 메모리 낭비를 최소화하기 위해 page->ptl용 전용 슬랩 캐시를 만들어 사용하게 하였다.

 

ptlock_cache_init()

mm/memory.c

#if USE_SPLIT_PTE_PTLOCKS && ALLOC_SPLIT_PTLOCKS
static struct kmem_cache *page_ptl_cachep;

void __init ptlock_cache_init(void)
{       
        page_ptl_cachep = kmem_cache_create("page->ptl", sizeof(spinlock_t), 0,
                        SLAB_PANIC, NULL);
}
#endif

페이지 테이블의 spinlock에 사용할 ptlock 캐시를 생성한다.

 

include/linux/mm_types.h

#define USE_SPLIT_PTE_PTLOCKS   (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS)

 

include/linux/mm_types.h

#define ALLOC_SPLIT_PTLOCKS     (SPINLOCK_SIZE > BITS_PER_LONG/8)

 

페이지 테이블 lock/unlock

ptlock_alloc()

mm/memory.c

bool ptlock_alloc(struct page *page)
{       
        spinlock_t *ptl;

        ptl = kmem_cache_alloc(page_ptl_cachep, GFP_KERNEL);
        if (!ptl)
                return false;
        page->ptl = ptl;
        return true;
}

spinlock에 사용할 slub object를 할당받아 page->ptl에 대입한다.

 

ptlock_free()

mm/memory.c

void ptlock_free(struct page *page)
{
        kmem_cache_free(page_ptl_cachep, page->ptl);
}

page->ptl에서 사용한 spinlock이 사용한 slub object를 해제한다.

 

CONFIG_SPLIT_PTLOCK_CPUS 커널 옵션

mm/Kconfig

# Heavily threaded applications may benefit from splitting the mm-wide
# page_table_lock, so that faults on different parts of the user address
# space can be handled with less contention: split it at this NR_CPUS.
# Default to 4 for wider testing, though 8 might be more appropriate.
# ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock.
# PA-RISC 7xxx's spinlock_t would enlarge struct page from 32 to 44 bytes.
# DEBUG_SPINLOCK and DEBUG_LOCK_ALLOC spinlock_t also enlarge struct page.
#
config SPLIT_PTLOCK_CPUS
        int
        default "999999" if !MMU
        default "999999" if ARM && !CPU_CACHE_VIPT
        default "999999" if PARISC && !PA20
        default "4"

 


pgd 테이블용 슬랩 캐시 준비

pgtable_cache_init() – ARM64

arch/arm64/include/asm/pgtable.h

#define pgtable_cache_init      pgd_cache_init

 

pgd_cache_init() – ARM64

arch/arm64/mm/pgd.c

void __init pgd_cache_init(void)
{
        if (PGD_SIZE == PAGE_SIZE)
                return;

#ifdef CONFIG_ARM64_PA_BITS_52
        /*
         * With 52-bit physical addresses, the architecture requires the
         * top-level table to be aligned to at least 64 bytes.
         */
        BUILD_BUG_ON(PGD_SIZE < 64);
#endif

        /*
         * Naturally aligned pgds required by the architecture.
         */
        pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
                                      SLAB_PANIC, NULL);
}

pgd 테이블용 슬랩 캐시를 준비한다.

 

pgd 테이블 할당/해제

pgd_alloc()

arch/arm64/mm/pgd.c

pgd_t *pgd_alloc(struct mm_struct *mm)
{
        if (PGD_SIZE == PAGE_SIZE)
                return (pgd_t *)__get_free_page(PGALLOC_GFP);
        else
                return kmem_cache_alloc(pgd_cache, PGALLOC_GFP);
}

pgd 테이블 슬랩 캐시를 사용하여 pgd 테이블을 할당한다.

 

pgd_free()

arch/arm64/mm/pgd.c

void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{
        if (PGD_SIZE == PAGE_SIZE)
                free_page((unsigned long)pgd);
        else
                kmem_cache_free(pgd_cache, pgd);
}

pgd 테이블 슬랩 캐시에 pgd 테이블을 할당 해제한다.

 

댓글 남기기