72. 메모리 관리 내부 (mm/internal.h)

개요

mm/internal.h는 Linux 커널 메모리 관리 서브시스템의 내부 정의를 담고 있는 핵심 헤더 파일입니다. 이 파일은 외부에 공개되지 않는 내부 구조체, 유틸리티 함수, 매크로를 정의하여 MM 서브시스템 간의 통신과 데이터 교환을 담당합니다.

/* internal.h: mm/ internal definitions - 1773줄 */
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/pagewalk.h>
#include <linux/rmap.h>
#include <linux/swap.h>
#include "vma.h"

이 파일은 page_alloc.c, vmscan.c, compaction.c, rmap.c, filemap.c, mremap.c 등 MM 서브시스템 전반에서 사용되며, 공개 API와 내부 구현 사이의 다리 역할을 합니다.

빠른 점검 명령

# internal.h 줄 수 확인
wc -l ~/Chamber_linux/linux-7.0-source/mm/internal.h

# 포함된 주요 구조체 목록
grep -n "^struct" ~/Chamber_linux/linux-7.0-source/mm/internal.h

# GFP 플래그 마스크 정의 확인
grep -n "GFP_" ~/Chamber_linux/linux-7.0-source/mm/internal.h | head -20

# 할당 관련 상수 확인
grep -n "ALLOC_" ~/Chamber_linux/linux-7.0-source/mm/internal.h

# 함수 선언 확인
grep -n "^void\|^int\|^static inline\|^extern" ~/Chamber_linux/linux-7.0-source/mm/internal.h | head -30

# CONFIG 옵션 확인
grep -n "CONFIG_" ~/Chamber_linux/linux-7.0-source/mm/internal.h | sort -u | head -20

# 내부 매크로 확인
grep -n "^#define" ~/Chamber_linux/linux-7.0-source/mm/internal.h | head -30

# vma 관련 유틸리티 확인
grep -n "vma" ~/Chamber_linux/linux-7.0-source/mm/internal.h | head -15

# swap 관련 함수 확인
grep -n "swap\|swp" ~/Chamber_linux/linux-7.0-source/mm/internal.h

# compaction 관련 구조체 확인
grep -n "compact_control\|capture_control" ~/Chamber_linux/linux-7.0-source/mm/internal.h

핵심 자료구조

1. pagetable_move_control (파일:라인 46-56)

페이지 테이블 이동 연산의 상태를 관리하는 구조체입니다.

/* 페이지 테이블 이동 제어 구조체 */
struct pagetable_move_control {
struct vm_area_struct *old;     /* 소스 VMA */
struct vm_area_struct *new;     /* 대상 VMA */
unsigned long old_addr;         /* 이동 시작 주소 */
unsigned long old_end;          /* 이동 범위 끝 주소 (배타적) */
unsigned long new_addr;         /* 이동 대상 주소 */
unsigned long len_in;           /* 사용자가 지정한 바이트 수 */

bool need_rmap_locks;           /* rmap 잠금 필요 여부 */
bool for_stack;                 /* 스택 이동 여부 */
};

2. GFP 플래그 마스크 (파일:라인 74-87)

할당 제약 조건을 정의하는 마스크들입니다.

/* 워터마크 체크 및 회수 동작에만 영향을 주는 플래그 */
#define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\
__GFP_NOWARN|__GFP_RETRY_MAYFAIL|__GFP_NOFAIL|\
__GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\
__GFP_NOLOCKDEP)

/* 부팅 초기에 허용되는 GFP 플래그 */
#define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS))

/* cpuset 및 노드 배치 제약 조건 제어 */
#define GFP_CONSTRAINT_MASK (__GFP_HARDWALL|__GFP_THISNODE)

/* slab 할당자에서 사용 불가 플래그 */
#define GFP_SLAB_BUG_MASK (__GFP_DMA32|__GFP_HIGHMEM|~__GFP_BITS_MASK)

3. WARN_ON_ONCE_GFP (파일:라인 92-101)

__GFP_NOWARN 지정 시 경고를 억제하는 매크로입니다.

/* __GFP_NOWARN 지정 시 경고 미발생 */
#define WARN_ON_ONCE_GFP(cond, gfp) ({                 \
static bool __section(".data..once") __warned;      \
int __ret_warn_once = !!(cond);                     \
if (unlikely(!(gfp & __GFP_NOWARN) && __ret_warn_once && !__warned)) { \
__warned = true;                                \
WARN_ON(1);                                     \
}                                                   \
unlikely(__ret_warn_once);                          \
})

4. alloc_context (파일:라인 657-675)

페이지 할당 매개변수를 보관하는 구조체입니다.

/* 할당 컨텍스트 - 할당 함수 간 전달되는 매개변수 */
struct alloc_context {
struct zonelist *zonelist;          /* 존 리스트 */
nodemask_t *nodemask;               /* 노드 마스크 */
struct zoneref *preferred_zoneref;  /* 선호 존 참조 */
int migratetype;                    /* 마이그레이션 유형 */

/*
* highest_zoneidx는 이 할당 요청에서 사용 가능한 최고 존 인덱스
* lower 존은 lowmem_reserve[highest_zoneidx]에 의해 보호됨
*/
enum zone_type highest_zoneidx;
bool spread_dirty_pages;            /* 더티 페이지 확산 여부 */
};

5. compact_control (파일:라인 950-988)

메모리 컴팩션 연산을 추적하는 구조체입니다.

/* 컴팩션 컨트롤 - 마이그레이션 중인 페이지 관리 */
struct compact_control {
struct list_head freepages[NR_PAGE_ORDERS]; /* 마이그레이션 대상 빈 페이지 목록 */
struct list_head migratepages;       /* 마이그레이션 중인 페이지 목록 */
unsigned int nr_freepages;           /* 격리된 빈 페이지 수 */
unsigned int nr_migratepages;        /* 마이그레이션할 페이지 수 */
unsigned long free_pfn;             /* 격리 검색 기준PFN */
unsigned long migrate_pfn;          /* 마이그레이션 검색 기준PFN */
unsigned long fast_start_pfn;       /* 선형 스캔 시작PFN */
struct zone *zone;                  /* 대상 존 */

/* 통계 */
unsigned long total_migrate_scanned;
unsigned long total_free_scanned;
unsigned short fast_search_fail;
short search_order;

/* 할당 관련 */
const gfp_t gfp_mask;
int order;
int migratetype;
const unsigned int alloc_flags;
const int highest_zoneidx;
enum migrate_mode mode;

/* 제어 플래그 */
bool ignore_skip_hint;
bool no_set_skip_hint;
bool ignore_block_suitable;
bool direct_compaction;
bool proactive_compaction;
bool whole_zone;
bool contended;
bool finish_pageblock;
bool alloc_contig;
};

핵심 함수

1. folio_pte_batch_flags (파일:라인 337-390)

대형 folio에 대한 PTE 배치를 감지합니다.

static inline unsigned int folio_pte_batch_flags(struct folio *folio,
struct vm_area_struct *vma, pte_t *ptep, pte_t *ptentp,
unsigned int max_nr, fpb_t flags)
{
bool any_writable = false, any_young = false, any_dirty = false;
pte_t expected_pte, pte = *ptentp;
unsigned int nr, cur_nr;

/* 유효성 검사 */
VM_WARN_ON_FOLIO(!pte_present(pte), folio);
VM_WARN_ON_FOLIO(!folio_test_large(folio) || max_nr < 1, folio);
VM_WARN_ON_FOLIO(page_folio(pfn_to_page(pte_pfn(pte))) != folio, folio);

/* 실제 배치 크기 제한 */
max_nr = min_t(unsigned long, max_nr,
folio_pfn(folio) + folio_nr_pages(folio) - pte_pfn(pte));

/* 배치 감지 시작 */
nr = pte_batch_hint(ptep, pte);
expected_pte = __pte_batch_clear_ignored(pte_advance_pfn(pte, nr), flags);
ptep = ptep + nr;

/* 연속된 PTE 스캔 */
while (nr < max_nr) {
pte = ptep_get(ptep);

if (!pte_same(__pte_batch_clear_ignored(pte, flags), expected_pte))
break;

/* 쓰기 가능/접근/더티 플래그 병합 */
if (flags & FPB_MERGE_WRITE)
any_writable |= pte_write(pte);
if (flags & FPB_MERGE_YOUNG_DIRTY) {
any_young |= pte_young(pte);
any_dirty |= pte_dirty(pte);
}

cur_nr = pte_batch_hint(ptep, pte);
expected_pte = pte_advance_pfn(expected_pte, cur_nr);
ptep += cur_nr;
nr += cur_nr;
}

/* 플래그 업데이트 */
if (any_writable)
*ptentp = pte_mkwrite(*ptentp, vma);
if (any_young)
*ptentp = pte_mkyoung(*ptentp);
if (any_dirty)
*ptentp = pte_mkdirty(*ptentp);

return min(nr, max_nr);
}

PTE 배치 플래그 (fpb_t):

  • FPB_RESPECT_DIRTY: 더티 비트 비교 유지
  • FPB_RESPECT_SOFT_DIRTY: 소프트 더티 비트 비교 유지
  • FPB_RESPECT_WRITE: 쓰기 가능 비트 비교 유지
  • FPB_MERGE_WRITE: 배치 내 쓰기 가능 여부 병합
  • FPB_MERGE_YOUNG_DIRTY: 배치 내 접근/더티 병합
  • 2. swap_pte_batch (파일:라인 449-476)

    스왑 PTE 배치를 감지합니다.

    static inline int swap_pte_batch(pte_t *start_ptep, int max_nr, pte_t pte)
    {
    pte_t expected_pte = pte_next_swp_offset(pte);
    const pte_t *end_ptep = start_ptep + max_nr;
    const softleaf_t entry = softleaf_from_pte(pte);
    pte_t *ptep = start_ptep + 1;
    unsigned short cgroup_id;
    
    VM_WARN_ON(max_nr < 1);
    VM_WARN_ON(!softleaf_is_swap(entry));
    
    cgroup_id = lookup_swap_cgroup_id(entry);
    while (ptep < end_ptep) {
    softleaf_t entry;
    
    pte = ptep_get(ptep);
    
    if (!pte_same(pte, expected_pte))
    break;
    entry = softleaf_from_pte(pte);
    if (lookup_swap_cgroup_id(entry) != cgroup_id)
    break;
    expected_pte = pte_next_swp_offset(expected_pte);
    ptep++;
    }
    
    return ptep - start_ptep;
    }

    3. buddy 함수들 (파일:라인 685-788)

    Buddy 할당자의 핵심 유틸리티 함수들입니다.

    /* 버디 순서 반환 */
    static inline unsigned int buddy_order(struct page *page)
    {
    /* PageBuddy()는 호출자가 검증해야 함 */
    return page_private(page);
    }
    
    /* 영역 잠금 없이 버디 순서 확인 */
    #define buddy_order_unsafe(page) READ_ONCE(page_private(page))
    
    /* 페이지가 유효한 버디인지 확인 */
    static inline bool page_is_buddy(struct page *page, struct page *buddy,
    unsigned int order)
    {
    if (!page_is_guard(buddy) && !PageBuddy(buddy))
    return false;
    
    if (buddy_order(buddy) != order)
    return false;
    
    /* 존 검사는 마지막에 수행 */
    if (page_zone_id(page) != page_zone_id(buddy))
    return false;
    
    VM_BUG_ON_PAGE(page_count(buddy) != 0, buddy);
    
    return true;
    }
    
    /* 버디 PFN 계산 (XOR 연산) */
    static inline unsigned long
    __find_buddy_pfn(unsigned long page_pfn, unsigned int order)
    {
    return page_pfn ^ (1 << order);
    }

    4. mlock/munlock 함수들 (파일:라인 1110-1146)

    VMA 잠금 처리 함수들입니다.

    void mlock_folio(struct folio *folio);
    
    static inline void mlock_vma_folio(struct folio *folio,
    struct vm_area_struct *vma)
    {
    /*
    * VM_SPECIAL 체크 두 가지 목적:
    * 1) VM_IO가 mlock 중 마이그레이션 이중 계산 방지
    * 2) mmap_region()과 mlock_fixup()이 VM_LOCKED를
    *    VM_SPECIAL VMA에 남기지 않도록 보장
    */
    if (unlikely((vma->vm_flags & (VM_LOCKED|VM_SPECIAL)) == VM_LOCKED))
    mlock_folio(folio);
    }
    
    void munlock_folio(struct folio *folio);
    
    static inline void munlock_vma_folio(struct folio *folio,
    struct vm_area_struct *vma)
    {
    if (unlikely(vma->vm_flags & VM_LOCKED))
    munlock_folio(folio);
    }

    5. vma_address 함수 (파일:라인 1159-1177)

    페이지 범위의 가상 주소를 찾습니다.

    static inline unsigned long vma_address(const struct vm_area_struct *vma,
    pgoff_t pgoff, unsigned long nr_pages)
    {
    unsigned long address;
    
    if (pgoff >= vma->vm_pgoff) {
    address = vma->vm_start +
    ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
    /* VMA 범위 초과 또는 0 래핑 체크 */
    if (address < vma->vm_start || address >= vma->vm_end)
    address = -EFAULT;
    } else if (pgoff + nr_pages - 1 >= vma->vm_pgoff) {
    /* 32비트에서 0 래핑 가능성 회피 */
    address = vma->vm_start;
    } else {
    address = -EFAULT;
    }
    return address;
    }

    호출 흐름

    ┌─────────────────────────────────────────────────────────────┐
    │                     MM 서브시스템 전체                        │
    ├─────────────────────────────────────────────────────────────┤
    │  page_alloc.c  │  vmscan.c  │  compaction.c  │  rmap.c     │
    │  filemap.c     │  mremap.c  │  memory.c      │  swap.c     │
    └────────┬───────────┴───────────────┴───────────────────────┘
    │
    ▼
    ┌─────────────────────────────────────────────────────────────┐
    │                    mm/internal.h                           │
    │  ┌─────────────────────────────────────────────────────┐   │
    │  │  내부 구조체 (alloc_context, compact_control 등)     │   │
    │  └─────────────────────────────────────────────────────┘   │
    │  ┌─────────────────────────────────────────────────────┐   │
    │  │  유틸리티 함수 (buddy 함수, folio 함수 등)           │   │
    │  └─────────────────────────────────────────────────────┘   │
    │  ┌─────────────────────────────────────────────────────┐   │
    │  │  플래그 마스크 (GFP_* 마스크, ALLOC_* 상수)          │   │
    │  └─────────────────────────────────────────────────────┘   │
    └─────────────────────────────────────────────────────────────┘
    │
    ▼
    ┌─────────────────────────────────────────────────────────────┐
    │                    외부 공개 API                             │
    │  mm.h, page_alloc.h, vmscan.h, compaction.h, rmap.h      │
    └─────────────────────────────────────────────────────────────┘

    조건별 비교

    internal.h 구성 요소 분류

    분류구조체/함수/매크로용도
    페이지 테이블 이동pagetable_move_control, move_page_tablesVMA 간 페이지 테이블 이동
    GFP 플래그GFP_RECLAIM_MASK, GFP_BOOT_MASK할당 제약 조건 정의
    할당 컨텍스트alloc_context할당 함수 간 매개변수 전달
    컴팩션compact_control, capture_control메모리 컴팩션 추적
    Buddy 시스템buddy_order, find_buddy_pfn, page_is_buddy버디 페이지 검색/검증
    PTE 배치folio_pte_batch_flags, swap_pte_batch대형 folio PTE 처리 최적화
    VMA 처리vma_address, mlock_vma_folio가상 메모리 영역 관리
    할당 플래그ALLOC_WMARK_*, ALLOC_OOM존 워터마크 기반 할당 제어

    GFP 플래그별 허용 범위

    플래그의미사용 시점
    GFP_RECLAIM_MASK회수 관련 플래그 모음직접 회수 시
    GFP_BOOT_MASK부팅 시 허용 플래그조기 부팅 할당
    GFP_CONSTRAINT_MASK배치 제약 조건NUMA/cpuset 할당
    GFP_SLAB_BUG_MASKslab에서 사용 불가slab 할당 시

    ALLOC 플래그 동작

    플래그동작조건
    ALLOC_WMARK_MIN최소 워터마크에서 할당기본 할당 경로
    ALLOC_WMARK_LOW저 워터마크에서 할당kswapd 간접 회수 후
    ALLOC_WMARK_HIGH높은 워터마크에서 할당정상 동작
    ALLOC_NO_WATERMARKS워터마크 무시특수 할당
    ALLOC_OOMOOM 상태 할당메모리 부족 시
    ALLOC_NON_BLOCK차단 없이 할당논블로킹 할당
    ALLOC_CMACMA 영역에서 할당연속 메모리 할당

    관련 문서

  • 01-page_alloc.md - Buddy Allocator 상세
  • 11-compaction.md - 메모리 컴팩션
  • 28-rmap.md - Reverse Mapping
  • 03-vma_mmap.md - VMA/mmap
  • 20-migrate.md - 페이지 마이그레이션
  • 12-folio.md - Folio/Page Cache
  • 07-swap_zswap.md - Swap/zswap
  • 36-mprotect.md - mprotect
  • 37-mremap.md - mremap
  • 70-pgtable_generic.md - 페이지 테이블 일반
  • 다이어그램

    internal.h 구성 관계도

    internal.h 구성 관계도

    PTE 배치 처리 흐름

    PTE 배치 처리 흐름