๏ปฟ# HugeTLB (HugeTLBfs)
๊ด๋ จ ์์ค:mm/hugetlb.c,include/linux/hugetlb.h
๊ฐ์ (Overview)
HugeTLB๋ ๋ฆฌ๋
์ค ์ปค๋์์ ์ฌ์ ํ ๋น๋ ๊ฑฐ๋ ํ์ด์ง(Huge Page)๋ฅผ ๊ด๋ฆฌํ๋ ์๋ธ์์คํ
์
๋๋ค. THP(Transparent Huge Pages)์ ๋ฌ๋ฆฌ HugeTLB๋ ์ฌ์ฉ์๊ฐ ๋ช
์์ ์ผ๋ก ๊ฑฐ๋ ํ์ด์ง ํ(Huge Page Pool)์ ๊ตฌ์ฑํ๊ณ , hugetlbfs ํ์ผ ์์คํ
์ด๋ MAP_HUGETLB ํ๋๊ทธ๋ฅผ ํตํด ๊ฑฐ๋ ํ์ด์ง๋ฅผ ์ง์ ํ ๋นํฉ๋๋ค. 2MB(๊ธฐ๋ณธ) ๋๋ 1GB ํฌ๊ธฐ์ ํ์ด์ง๋ฅผ ์ฌ์ฉํ์ฌ TLB ๋ฏธ์ค๋ฅผ ์ค์ด๊ณ ๋์ฉ๋ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค.
ํต์ฌ ์ค๊ณ ์์น์ ์ฌ์ ํ ๋น(Pre-allocation)๊ณผ ์์ฝ(Reservation)์
๋๋ค. ๋ถํ
์ ๋๋ ๋ฐํ์์ hugepages= ์ปค๋ ํ๋ผ๋ฏธํฐ๋ก ๋ฏธ๋ฆฌ ํ๋ณดํ ๊ฑฐ๋ ํ์ด์ง ํ์์ ํ ๋น์ด ์ด๋ฃจ์ด์ง๋ฉฐ, hugetlb_reserve_pages()๊ฐ VMA ์์ฑ ์ ์์ฝ์ ์ํํ๊ณ alloc_hugetlb_folio()๊ฐ ์ค์ ํ ๋น์ ์ฒ๋ฆฌํฉ๋๋ค. subpool์ hugetlbfs ํ์ผ ์์คํ
๋ณ, memcg๋ cgroup๋ณ๋ก ํ์ ๋ถ๋ฆฌํ์ฌ ๊ด๋ฆฌํฉ๋๋ค.
// ์์ค ํ์ผ ๊ฒฝ๋ก
mm/hugetlb.c /* ํต์ฌ ํ ๋น/๊ด๋ฆฌ ๋ก์ง */
mm/hugetlb_vmemmap.c /* vmemmap ์ต์ ํ */
mm/hugetlb_cma.c /* CMA๋ฅผ ํตํ ๊ฑฐ๋ ํ์ด์ง ํ ๋น */
include/linux/hugetlb.h /* ํต์ฌ ๊ตฌ์กฐ์ฒด/ํจ์ ์ ์ธ */
include/linux/hugetlb_inline.h /* ์ธ๋ผ์ธ ํฌํผ */
fs/hugetlbfs/inode.c /* hugetlbfs ํ์ผ ์์คํ
*/
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# HugeTLB ํ ์ํ ํ์ธ
cat /proc/meminfo | grep -i huge
# HugePages_Total: ํ ๋น๋ ๊ฑฐ๋ ํ์ด์ง ์
# HugePages_Free: ํ์์ ์ฌ์ฉ ๊ฐ๋ฅํ ์
# HugePages_Rsvd: ์์ฝ๋์์ผ๋ ์์ง ๋งคํ ์ ๋ ์
# HugePages_Surplus: ์ค๋ฒ์ปค๋ฐ์ผ๋ก ์ด๊ณผ ํ ๋น๋ ์
# Hugepagesize: ๊ฑฐ๋ ํ์ด์ง ํฌ๊ธฐ (๋ณดํต 2048 kB)
# ๊ฑฐ๋ ํ์ด์ง ํ ํฌ๊ธฐ ํ์ธ (์ํคํ
์ฒ๋ณ)
grep -i huge /proc/meminfo
# hugetlbfs ๋ง์ดํธ ํ์ธ
mount | grep hugetlb
# NUMA ๋
ธ๋๋ณ ๊ฑฐ๋ ํ์ด์ง ๋ถํฌ
cat /sys/devices/system/node/node*/hugepages/hugepages-2048kB/*
# ํ๋ก์ธ์ค ๊ฑฐ๋ ํ์ด์ง ์ฌ์ฉ๋
cat /proc/$$/status | grep -i hugetlb
# ๊ฑฐ๋ ํ์ด์ง ํ ๋น/ํด์ ์ถ์
cat /proc/vmstat | grep -i huge
# ๊ฑฐ๋ ํ์ด์ง ํ ๋ฆฌ์ฌ์ด์ฆ (๋ฐํ์)
echo 1024 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
# hugetlbfs ๋๋ ํ ๋ฆฌ ๋ง์ดํธ
mkdir -p /mnt/huge
mount -t hugetlbfs -o pagesize=2M none /mnt/huge
# memcg ๊ฑฐ๋ ํ์ด์ง ์ ํ ํ์ธ
cat /sys/fs/cgroup/memory hugetlb.max 2>/dev/null
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
struct hstate โ ๊ฑฐ๋ ํ์ด์ง ์ํ ๊ด๋ฆฌ
ํ๋์ ๊ฑฐ๋ ํ์ด์ง ํฌ๊ธฐ(์: 2MB, 1GB)๋ฅผ ๋ํํ๋ ์ ์ญ ์ํ ๊ตฌ์กฐ์ฒด์
๋๋ค. hstates[] ๋ฐฐ์ด์ HUGE_MAX_HSTATE๊ฐ๊น์ง ์กด์ฌํ๋ฉฐ, for_each_hstate() ๋งคํฌ๋ก๋ก ์ํํฉ๋๋ค.
/* include/linux/hugetlb.h:666-687 */
struct hstate {
struct mutex resize_lock; /* ๋ฆฌ์ฌ์ด์ฆ ์ง๋ ฌํ */
struct lock_class_key resize_key;
int next_nid_to_alloc; /* ๋ค์ ํ ๋น ๋์ ๋
ธ๋ */
int next_nid_to_free; /* ๋ค์ ํด์ ๋์ ๋
ธ๋ */
unsigned int order; /* ๊ฑฐ๋ ํ์ด์ง order (1=2MB, 3=1GB) */
unsigned int demote_order; /* ๋๋ชจํธ ์ target order */
unsigned long mask; /* ํ์ด์ง ์ ๋ ฌ ๋ง์คํฌ ~(size-1) */
unsigned long max_huge_pages; /* ๋ชฉํ ํ ํฌ๊ธฐ (sysctl ์ค์ ) */
unsigned long nr_huge_pages; /* ํ์ฌ ํ์ ์๋ ์ ์ฒด ๊ฑฐ๋ ํ์ด์ง ์ */
unsigned long free_huge_pages; /* ์ฌ์ฉ ๊ฐ๋ฅํ ๊ฑฐ๋ ํ์ด์ง ์ */
unsigned long resv_huge_pages; /* ์์ฝ๋ ๊ฑฐ๋ ํ์ด์ง ์ */
unsigned long surplus_huge_pages; /* ์ค๋ฒ์ปค๋ฐ ์ด๊ณผ ์ */
unsigned long nr_overcommit_huge_pages; /* ์ค๋ฒ์ปค๋ฐ ํ๋ */
struct list_head hugepage_activelist; /* ํ์ฑ ๋ฆฌ์คํธ (ํ ๋น๋ ํ์ด์ง) */
struct list_head hugepage_freelists[MAX_NUMNODES]; /* ๋
ธ๋๋ณ ํ๋ฆฌ ๋ฆฌ์คํธ */
unsigned int max_huge_pages_node[MAX_NUMNODES]; /* ๋
ธ๋๋ณ ๋ชฉํ ์ */
unsigned int nr_huge_pages_node[MAX_NUMNODES]; /* ๋
ธ๋๋ณ ํ์ฌ ์ */
unsigned int free_huge_pages_node[MAX_NUMNODES]; /* ๋
ธ๋๋ณ ์ฌ์ ์ */
unsigned int surplus_huge_pages_node[MAX_NUMNODES];/* ๋
ธ๋๋ณ ์ด๊ณผ ์ */
char name[HSTATE_NAME_LEN]; /* "hugepages-2048kB" ๋ฑ */
};
/*ๅบๅค: mm/hugetlb.c:57 โ ์ ์ญ ๋ฐฐ์ด */
struct hstate hstates[HUGE_MAX_HSTATE];
struct hugepage_subpool โ ์๋ธํ ๊ด๋ฆฌ
hugetlbfs ํ์ผ ์์คํ
์ด๋ memcg์ ๊ฑฐ๋ ํ์ด์ง ํ์ ๋ถ๋ฆฌํ์ฌ ๊ด๋ฆฌํ๋ ๊ตฌ์กฐ์ฒด์
๋๋ค. max_hpages๋ก ์ํ, min_hpages๋ก ํํ์ ์ค์ ํฉ๋๋ค.
/* include/linux/hugetlb.h:37-47 */
struct hugepage_subpool {
spinlock_t lock; /* ์ ๊ธ */
long count; /* ์ฐธ์กฐ ์นด์ดํธ */
long max_hpages; /* ์ต๋ ๊ฑฐ๋ ํ์ด์ง ์ ๋๋ -1 (๋ฌด์ ํ) */
long used_hpages; /* ์ฌ์ฉ ์ค์ธ ์ (ํ ๋น+์์ฝ ํฌํจ) */
struct hstate *hstate; /* ์ฐ๊ฒฐ๋ hstate */
long min_hpages; /* ์ต์ ๊ฑฐ๋ ํ์ด์ง ์ ๋๋ -1 */
long rsv_hpages; /* ๊ธ๋ก๋ฒ ํ์์ ์์ฝํ ์ */
};
struct resv_map / file_region โ ์์ฝ ์์ญ ์ถ์
๊ฑฐ๋ ํ์ด์ง ์์ฝ(reservation)์ ๊ตฌ๊ฐ(region) ๋จ์๋ก ์ถ์ ํฉ๋๋ค. file_region์ [from, to) ๊ตฌ๊ฐ์ ๋ํ๋ด๋ interval ๋
ธ๋์ด๊ณ , resv_map์ ์ด๋ค์ ์ฐ๊ฒฐ ๋ฆฌ์คํธ์ ์ ๊ธ์ ๊ด๋ฆฌํฉ๋๋ค.
/* include/linux/hugetlb.h:49-67 */
struct resv_map {
struct kref refs; /* ์ฐธ์กฐ ์นด์ดํธ */
spinlock_t lock; /* ์ ๊ธ */
struct list_head regions; /* file_region ๋ฆฌ์คํธ */
long adds_in_progress; /* ์งํ ์ค์ธ ์ถ๊ฐ ์ */
struct list_head region_cache; /* ์ฌ์ฌ์ฉ ์บ์ */
long region_cache_count;
struct rw_semaphore rw_sema; /* ์ฝ๊ธฐ/์ฐ๊ธฐ ์ธ๋งํฌ์ด */
/* CONFIG_CGROUP_HUGETLB */
struct page_counter *reservation_counter; /* memcg ์์ฝ ์นด์ดํฐ */
unsigned long pages_per_hpage;
struct cgroup_subsys_state *css;
};
/* include/linux/hugetlb.h:88-101 */
struct file_region {
struct list_head link; /* ๋ฆฌ์คํธ ์ฐ๊ฒฐ */
long from; /* ์์ ์ธ๋ฑ์ค (ํฌํจ) */
long to; /* ์ข
๋ฃ ์ธ๋ฑ์ค (๋ถํฌํจ) โ [from, to) */
/* CONFIG_CGROUP_HUGETLB */
struct page_counter *reservation_counter;
struct cgroup_subsys_state *css;
};
struct hugetlb_vma_lock โ VMA๋ณ ์ ๊ธ
๊ณต์ ๋งคํ(VM_MAYSHARE)์์ PMD ์ ฐ์ด๋ง๊ณผ ํดํธ/ํธ๋ฐ์ผ์ด์ ๋๊ธฐํ๋ฅผ ์ํด VMA๋ณ rwsem์ ์ ๊ณตํฉ๋๋ค.
/* include/linux/hugetlb.h:103-107 */
struct hugetlb_vma_lock {
struct kref refs; /* ์ฐธ์กฐ ์นด์ดํธ */
struct rw_semaphore rw_sema; /* ์ฝ๊ธฐ/์ฐ๊ธฐ ์ธ๋งํฌ์ด */
struct vm_area_struct *vma; /* ์ฐ๊ฒฐ๋ VMA */
};
HUGETLB ํ์ด์ง ํ๋๊ทธ (HPG_*)
๊ฑฐ๋ ํ์ด์ง์ ํน์ ์ํ๋ฅผ folio->private ๋นํธ์ ์ ์ฅํฉ๋๋ค.
/* include/linux/hugetlb.h:593-602 */
enum hugetlb_page_flags {
HPG_restore_reserve = 0, /* ํ ๋น ์ ์์ฝ ์๋น โ ์ค๋ฅ ์ ๋ณต์ ํ์ */
HPG_migratable, /* ๋ง์ด๊ทธ๋ ์ด์
ํ๋ณด */
HPG_temporary, /* Buddy์์ ์์ ํ ๋น (์ด์ ์ฉ ํ๊ฒ) */
HPG_freed, /* ํ๋ฆฌ ๋ฆฌ์คํธ์ ์์ */
HPG_vmemmap_optimized, /* vmemmap ๋ฉ๋ชจ๋ฆฌ ํด์ ๋จ */
HPG_raw_hwp_unreliable, /* hwpoison ์๋ธํ์ด์ง ๋ฏธ์ถ์ */
HPG_cma, /* CMA ์์ญ์์ ํ ๋น๋จ */
__NR_HPAGEFLAGS,
};
struct hugetlbfs_sb_info โ ํ์ผ ์์คํ ์ ๋ณด
hugetlbfs์ superblock์ ์ฐ๊ฒฐ๋ ๊ฑฐ๋ ํ์ด์ง ํ์ผ ์์คํ ์ ๋ณด์ ๋๋ค.
/* include/linux/hugetlb.h:503-512 */
struct hugetlbfs_sb_info {
long max_inodes; /* ํ์ฉ inode ์ */
long free_inodes; /* ์ฌ์ inode ์ */
spinlock_t stat_lock;
struct hstate *hstate; /* ์ฐ๊ฒฐ๋ hstate */
struct hugepage_subpool *spool; /* ์๋ธํ */
kuid_t uid; /* ์์ ์ UID */
kgid_t gid; /* ์์ ์ GID */
umode_t mode; /* ๊ถํ */
};
ํต์ฌ ํจ์
hugetlb_fault() โ ํดํธ ์ง์ ์
HugeTLB ํ์ด์ง ํดํธ์ ๋ฉ์ธ ์ง์
์ ์
๋๋ค. ํ์ด์ง ํ
์ด๋ธ์ ๊ฑฐ๋ ํ์ด์ง PTE๊ฐ ์์ผ๋ฉด hugetlb_no_page()๋ก, COW๊ฐ ํ์ํ๋ฉด hugetlb_wp()๋ก ๋ถ๊ธฐํฉ๋๋ค.
/* mm/hugetlb.c:5972-6161 */
vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, unsigned int flags)
{
// 1. fault mutex๋ก ๋์ผ ํ์ด์ง ํ ๋น ์ง๋ ฌํ
hash = hugetlb_fault_mutex_hash(mapping, vmf.pgoff);
mutex_lock(&hugetlb_fault_mutex_table[hash]);
// 2. VMA lock ํ๋ ํ PTE ํ ๋น
hugetlb_vma_lock_read(vma);
vmf.pte = huge_pte_alloc(mm, vma, vmf.address, huge_page_size(h));
// 3. PTE ์ํ์ ๋ฐ๋ฅธ ๋ถ๊ธฐ
vmf.orig_pte = huge_ptep_get(mm, vmf.address, vmf.pte);
if (huge_pte_none(vmf.orig_pte))
return hugetlb_no_page(mapping, &vmf); /* ์ ํ์ด์ง ํ ๋น */
if (softleaf_is_migration(softleaf))
migration_entry_wait_huge(...); /* ๋ง์ด๊ทธ๋ ์ด์
๋๊ธฐ */
if (softleaf_is_hwpoison(softleaf))
return VM_FAULT_HWPOISON_LARGE; /* ํ๋์จ์ด ์ค๋ฅ */
// 4. ๊ธฐ์กด ํ์ด์ง์ ๋ํ COW ์ฒ๋ฆฌ
if ((flags & (FAULT_FLAG_WRITE|FAULT_FLAG_UNSHARE)) && ...)
ret = hugetlb_wp(&vmf); /* Copy-on-Write */
// 5. accessed bit ๊ฐฑ์
vmf.orig_pte = pte_mkyoung(vmf.orig_pte);
huge_ptep_set_access_flags(...);
}
hugetlb_no_page() โ ์ ๊ฑฐ๋ ํ์ด์ง ํ ๋น ๋ฐ ๋งคํ
PTE๊ฐ ๋น์ด์์ ๋ ์ ๊ฑฐ๋ ํ์ด์ง๋ฅผ ํ ๋นํ๊ณ ํ์ด์ง ํ ์ด๋ธ์ ๋งคํํฉ๋๋ค. ํ์ผ ๊ธฐ๋ฐ ๋งคํ์ page cache์, ์ต๋ช ๋งคํ์ anon_rmap์ ์ฐ๊ฒฐํฉ๋๋ค.
/* mm/hugetlb.c:5722-5946 */
static vm_fault_t hugetlb_no_page(struct address_space *mapping,
struct vm_fault *vmf)
{
// 1. ํ์ด์ง ์บ์์์ ๊ธฐ์กด folio ๊ฒ์
folio = filemap_lock_hugetlb_folio(h, mapping, vmf->pgoff);
if (IS_ERR(folio)) {
// 2. ์์ผ๋ฉด ์ folio ํ ๋น
folio = alloc_hugetlb_folio(vma, vmf->address, false);
folio_zero_user(folio, vmf->real_address);
__folio_mark_uptodate(folio);
// 3. ๊ณต์ ๋งคํ: page cache์ ์ถ๊ฐ
if (vma->vm_flags & VM_MAYSHARE)
hugetlb_add_to_page_cache(folio, mapping, vmf->pgoff);
else
new_anon_folio = true; /* ์ต๋ช
: rmap์ ์ถ๊ฐ */
}
// 4. PTE์ ์ ๊ฑฐ๋ ํ์ด์ง ๋งคํ
new_pte = make_huge_pte(vma, folio, vma->vm_flags & VM_SHARED);
set_huge_pte_at(mm, vmf->address, vmf->pte, new_pte, huge_page_size(h));
// 5. COW๊ฐ ํ์ํ ์ฌ์ ๋งคํ์ด๋ฉด ์ฆ์ ์ฒ๋ฆฌ
if ((vmf->flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED))
ret = hugetlb_wp(vmf);
}
alloc_hugetlb_folio() โ ๊ฑฐ๋ ํ์ด์ง ํ ๋น ํต์ฌ
VMA์ ์๋ธํ, memcg, ๊ธ๋ก๋ฒ ํ์์ ์์ฐจ์ ์ผ๋ก ํ ๋น ๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ folio๋ฅผ ํ ๋นํฉ๋๋ค.
/* mm/hugetlb.c:2908-3078 */
struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
unsigned long addr, bool cow_from_owner)
{
// 1. VMA ์์ฝ ํ์ธ (map_chg: REUSE/NEEDED/ENFORCED)
retval = vma_needs_reservation(h, vma, addr);
// 2. ์๋ธํ ๊ธ๋ก๋ฒ ํ ๋น ํ์ธ
if (map_chg)
gbl_chg = hugepage_subpool_get_pages(spool, 1);
// 3. memcg ์์ฝ ์ถฉ์
if (map_chg)
hugetlb_cgroup_charge_cgroup_rsvd(idx, ...);
// 4. memcg ์ผ๋ฐ ์ถฉ์
hugetlb_cgroup_charge_cgroup(idx, ...);
// 5. ๊ธ๋ก๋ฒ ํ์์ dequeue ๋๋ buddy ํ ๋น
spin_lock_irq(&hugetlb_lock);
folio = dequeue_hugetlb_folio_vma(h, vma, addr, gbl_chg);
if (!folio)
folio = alloc_buddy_hugetlb_folio_with_mpol(h, vma, addr);
// 6. ์์ฝ ์๋น ๋งํฌ
if (!gbl_chg)
folio_set_hugetlb_restore_reserve(folio);
// 7. memcg ์ปค๋ฐ
hugetlb_cgroup_commit_charge(idx, ...);
// 8. VMA ์์ฝ ์ปค๋ฐ
if (map_chg != MAP_CHG_ENFORCED)
vma_commit_reservation(h, vma, addr);
}
hugetlb_reserve_pages() โ ์์ฝ ์ฒ๋ฆฌ
mmap() ์ ํธ์ถ๋์ด ๊ฑฐ๋ ํ์ด์ง ์์ฝ์ ์ค์ ํฉ๋๋ค. ๊ณต์ ๋งคํ์ resv_map์ region์ผ๋ก, ์ฌ์ ๋งคํ์ ๋ณ๋ resv_map์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค.
/* mm/hugetlb.c:6570-6749 */
long hugetlb_reserve_pages(struct inode *inode,
long from, long to,
struct vm_area_desc *desc, vma_flags_t vma_flags)
{
// 1. VM_NORESERVE์ด๋ฉด ์์ฝ ์์
if (vma_flags_test(&vma_flags, VMA_NORESERVE_BIT))
return 0;
// 2. ๊ณต์ ๋งคํ: inode์ resv_map์ region_chg
if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT)) {
resv_map = inode_resv_map(inode);
chg = region_chg(resv_map, from, to, ®ions_needed);
} else {
// 3. ์ฌ์ ๋งคํ: ์ resv_map ํ ๋น
resv_map = resv_map_alloc();
chg = to - from;
set_vma_desc_resv_map(desc, resv_map);
}
// 4. memcg ์์ฝ ์ถฉ์
hugetlb_cgroup_charge_cgroup_rsvd(...);
// 5. ์๋ธํ ํ ๋น ํ์ธ
gbl_reserve = hugepage_subpool_get_pages(spool, chg);
// 6. ๊ธ๋ก๋ฒ ํ ์ฌ์ ํ์ธ
hugetlb_acct_memory(h, gbl_reserve);
// 7. ๊ณต์ : region_add๋ก ์์ฝ ์์ญ ํ์
if (๊ณต์ ๋งคํ)
add = region_add(resv_map, from, to, regions_needed, h, h_cg);
}
dequeue_hugetlb_folio_vma() โ VMA ๊ธฐ๋ฐ ํ๋ฆฌ ๋ฆฌ์คํธ dequeue
VMA์ NUMA ์ ์ฑ ์ ๋ฐ๋ผ ์ ์ ํ ๋ ธ๋์ ํ๋ฆฌ ๋ฆฌ์คํธ์์ folio๋ฅผ ๊บผ๋ด์ต๋๋ค.
/* mm/hugetlb.c:1373-1412 */
static struct folio *dequeue_hugetlb_folio_vma(struct hstate *h,
struct vm_area_struct *vma, unsigned long addr, bool gbl_chg)
{
// 1. NUMA ์ ์ฑ
์ ๋ฐ๋ฅธ ๋
ธ๋ ๊ฒฐ์
int nid = huge_node(vma, addr, htlb_alloc_mask(h), &mpol, &nodemask);
// 2. ์ง์ ๋
ธ๋์์ dequeue ์๋
folio = dequeue_hugetlb_folio_node_exact(h, nid, gfp_mask, gbl_chg);
// 3. ์คํจ ์ nodemask ๋ด ๋ค๋ฅธ ๋
ธ๋๋ก fallback
if (!folio)
folio = dequeue_hugetlb_folio_nodemask(h, gfp_mask, nodemask, gbl_chg);
return folio;
}
ํธ์ถ ํ๋ฆ
mmap(MAP_HUGETLB) โโโ hugetlb_file_setup() โโโ hugetlb_reserve_pages()
โ โ
โ region_chg() / resv_map_alloc()
โ hugepage_subpool_get_pages()
โ hugetlb_acct_memory()
โ
โผ
์ฒซ ์ ๊ทผ ์ Page Fault
โ
โผ
hugetlb_fault()
โ
โโโ huge_pte_none() โโโ hugetlb_no_page()
โ โ โ
โ โ โโโ filemap_lock_hugetlb_folio() [์บ์ ๊ฒ์]
โ โ โโโ alloc_hugetlb_folio() [ํ ๋น]
โ โ โ โ
โ โ โ โโโ vma_needs_reservation()
โ โ โ โโโ hugepage_subpool_get_pages()
โ โ โ โโโ hugetlb_cgroup_charge_cgroup()
โ โ โ โโโ dequeue_hugetlb_folio_vma()
โ โ โ โ โโโ dequeue_hugetlb_folio_node_exact()
โ โ โ โโโ alloc_buddy_hugetlb_folio_with_mpol()
โ โ โ
โ โ โโโ hugetlb_add_to_page_cache() [๊ณต์ ]
โ โ โโโ hugetlb_add_new_anon_rmap() [์ต๋ช
]
โ โ
โ โโโ set_huge_pte_at() โโโ COW ํ์ ์ hugetlb_wp()
โ
โโโ migration_entry_wait_huge() [๋ง์ด๊ทธ๋ ์ด์
๋๊ธฐ]
โ
โโโ hugetlb_wp() [COW ์ฒ๋ฆฌ]
โ
โโโ folio_ref_count==1 โ wp_page_reuse() [๋จ๋
์ฌ์ฉ โ ์ฌ์ฌ์ฉ]
โโโ folio_ref_count>1 โ wp_page_copy() [๊ณต์ โ ๋ณต์ฌ]
์กฐ๊ฑด๋ณ ๋น๊ต
๊ฑฐ๋ ํ์ด์ง ํ ๋น ๊ฒฝ๋ก ๋น๊ต
| ์กฐ๊ฑด | ํ ๋น ๊ฒฝ๋ก | ์ค๋ช |
|---|---|---|
| VMA ์์ฝ ์์ (REUSE) | `dequeue_hugetlb_folio_vma()` | ํ๋ฆฌ ๋ฆฌ์คํธ์์ ์ฆ์ ํ ๋น |
| VMA ์์ฝ ์์ (NEEDED) | `subpool โ buddy` | ์๋ธํ ํ์ธ ํ buddy ํ ๋น |
| COW from_owner | `MAP_CHG_ENFORCED` | ์์ฝ ์ฒดํฌ ๊ฑด๋๋ฐ๊ณ buddy ํ ๋น |
| Buddy ํ ๋น ์คํจ | `alloc_surplus_hugetlb_folio()` | ์ค๋ฒ์ปค๋ฐ์ผ๋ก ์ด๊ณผ ํ ๋น |
| NUMA ์ ์ฑ ์ ์ฉ | `huge_node()` โ ๋ ธ๋ ์ง์ | mpol์ ๋ฐ๋ผ ํน์ ๋ ธ๋ ์ฐ์ |
๋งคํ ์ ํ๋ณ ์ฒ๋ฆฌ ๋น๊ต
| ๋งคํ ์ ํ | ์์ฝ ๊ด๋ฆฌ | ํ์ด์ง ์บ์ | rmap | COW |
|---|---|---|---|---|
| ๊ณต์ (VM_MAYSHARE) | inode resv_map์ region | `__filemap_add_folio()` | `hugetlb_add_file_rmap()` | ์์ (๊ณต์ ) |
| ์ฌ์ (private) | VMA๋ณ ๋ณ๋ resv_map | ์์ | `hugetlb_add_new_anon_rmap()` | `hugetlb_wp()` |
| MAP_NORESERVE | ์์ฝ ์์ | - | - | ํ ๋น ์ ์์ฝ ๋ถํ์ |
| memcg ์ ์ฉ | reservation_counter | - | - | memcg ์ถฉ์ |
๊ฑฐ๋ ํ์ด์ง ํ ์๋น์ ๋น๊ต
| ์๋น์ | ์ญํ | ์ ๊ธ |
|---|---|---|
| `hstate.max_huge_pages` | ๋ชฉํ ํ ํฌ๊ธฐ | `hugetlb_lock` |
| `hstate.nr_huge_pages` | ํ์ฌ ํ ๋น ์ | `hugetlb_lock` |
| `hstate.free_huge_pages` | ์ฌ์ฉ ๊ฐ๋ฅ ์ | `hugetlb_lock` |
| `hstate.resv_huge_pages` | ์์ฝ ๋๊ธฐ ์ | `hugetlb_lock` |
| `hstate.surplus_huge_pages` | ์ค๋ฒ์ปค๋ฐ ์ด๊ณผ | `hugetlb_lock` |
| `hugepage_subpool.used_hpages` | ์๋ธํ ์ฌ์ฉ ์ | `spool->lock` |
| memcg `reservation_counter` | memcg ์์ฝ ์ | page_counter lock |
HPG ํ๋๊ทธ๋ณ ๋์ ๋น๊ต
| ํ๋๊ทธ | ์ค์ ์์ | ํด์ ์์ | ์๋ฏธ |
|---|---|---|---|
| `HPG_restore_reserve` | ์์ฝ ์๋น ํ ๋น ์ | ํ์ด์ง ์์ ์ธ์คํด์คํ ์ | ์ค๋ฅ ์ ์์ฝ ๋ณต์ ํ์ |
| `HPG_migratable` | page cache/tab์ ์ถ๊ฐ ํ | ๋ง์ด๊ทธ๋ ์ด์ ๊ฒฉ๋ฆฌ ์ | ๋ง์ด๊ทธ๋ ์ด์ ํ๋ณด |
| `HPG_temporary` | buddy์์ ์์ ํ ๋น ์ | ํ๋ฆฌ ์ ์ฆ์ buddy ๋ฐํ | ํ ํ์ด์ง ์๋ |
| `HPG_freed` | ํ๋ฆฌ ๋ฆฌ์คํธ enqueue ์ | dequeue ์ | ํ๋ฆฌ ์ํ ํ์ |
| `HPG_vmemmap_optimized` | vmemmap ํด์ ์ | - | vmemmap ์ต์ ํ ์ ์ฉ |
minzkn.com ๋น๊ต ์ฐธ๊ณ
minzkn.com์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๊ฐ์ ํ์ด์ง๋ HugeTLB/THP ์น์ ์์ ๋ค์ ๊ฐ๋ ์ ๋ค๋ฃน๋๋ค:
cat /proc/meminfo | grep Huge, hugepages= ์ปค๋ ํ๋ผ๋ฏธํฐ, hugetlbfs ๋ง์ดํธ ๋ฐฉ๋ฒ ๋ฑ์ minzkn๊ณผ ์ผ์นํฉ๋๋ค.hugepagesize, HugePages_Total/Free/Rsvd/Surplus ํ๋ ์ค๋ช
์ ํฌํจํ๋ฉฐ, ์ฐ๋ฆฌ ๋ฌธ์์ ๋น ๋ฅธ ์ ๊ฒ ๋ช
๋ น ์น์
์ ์ด๋ฏธ ํฌํจ๋์ด ์์ต๋๋ค.