๏ปฟ# Reverse Mapping (rmap)
๊ด๋ จ ์์ค:mm/rmap.c,include/linux/rmap.h
๊ฐ์ (Overview)
Reverse Mapping(rmap)์ ๋ฌผ๋ฆฌ ํ์ด์ง(folio)๋ก๋ถํฐ ๊ทธ ํ์ด์ง๊ฐ ๋งคํ๋ ๋ชจ๋ ๊ฐ์ ์ฃผ์๋ฅผ ์ฐพ๋ ๋ฉ์ปค๋์ฆ์ ๋๋ค. Linux ์ปค๋์์ ํ์ด์ง ํ์(reclaim), KSM(Kernel Samepage Merging), ํ์ด์ง ๋ง์ด๊ทธ๋ ์ด์ , ํ์ด์ง ์ ๊ฑฐ(zap) ๋ฑ ํต์ฌ ๋์์ "๋ฌผ๋ฆฌ ํ์ด์ง โ ์ด๋ค VMA์ ๋งคํ๋์ด ์๋๊ฐ?"๋ฅผ ์ถ์ ํด์ผ ํ๋ฉฐ, rmap์ด ์ด๋ฅผ ๋ด๋นํฉ๋๋ค.
rmap์ ๋ ๊ฐ์ง ์ ํ์ ๋งคํ์ ๊ตฌ๋ถํฉ๋๋ค: ์ต๋ช
(anon) ํ์ด์ง๋ anon_vma ์ฒด์ธ์ ํตํด ์ถ์ ํ๊ณ , ํ์ผ(file) ๊ธฐ๋ฐ ํ์ด์ง๋ address_space->i_mmap interval tree๋ฅผ ํตํด ์ถ์ ํฉ๋๋ค. ๊ฐ folio์ mapping ํ๋๊ฐ anon_vma ๋๋ address_space๋ฅผ ๊ฐ๋ฆฌํค๋ฉฐ, rmap walk ์ ํด๋น ๊ตฌ์กฐ์ฒด๋ฅผ ์ํํ์ฌ ๋ชจ๋ ๋งคํ VMA๋ฅผ ์ฐพ์ต๋๋ค.
์ผ์ ๋น์ ๋ก ๋ณด๋ฉด rmap์ ๋์๊ด์ ๋์ถ ์นด๋ ๋ชฉ๋ก๊ณผ ๋น์ทํฉ๋๋ค. ์ฑ ํ ๊ถ(folio)์ ์ค์ ๋ก ์ฌ๋ฌ ์ฌ๋์ ์์ ๊ฑด๋ค์ง ์ ์๊ณ , ๋ฐ๋ฉยท์ด๋ยทํ๊ธฐ ์์ ์๋ "์ด ์ฑ ์ ๋๊ฐ ์ด๋์์ ๋น๋ ค ๊ฐ๋๊ฐ"๋ฅผ ๋ฐ๋ก ์ฐพ์์ผ ํฉ๋๋ค. rmap์ ๋ฐ๋ก ๊ทธ ์ญ๋ฐฉํฅ ์์ธ์ ๋๋ค.
์ด ๋ฌธ์์์ ๋ณด๋ rmap์ ํ์ด์ง ํดํธ์ COW๊น์ง ์ด์ด์ง๋๋ค. ์ฒ์ ์ ๊ทผํ ์ฃผ์๋ ํ์ด์ง ํดํธ๋ก ๋ฌผ๋ฆฌ ํ์ด์ง๋ฅผ ๋ง๋ค๊ณ , fork() ๋ค ์ฐ๊ธฐ ์์ ์๋ COW๋ก ์ ํ์ด์ง๋ฅผ ๋ณต์ฌํฉ๋๋ค. ์ดํ ํ์๋ ๋ง์ด๊ทธ๋ ์ด์
์ด ์ค๋ฉด rmap์ด ๊ฐ VMA๋ฅผ ๋ค์ ์ฐพ์ mapcount์ PTE๋ฅผ ์ ๋ฆฌํฉ๋๋ค.
์์ค ํ์ผ ๊ฒฝ๋ก:
mm/rmap.c โ rmap ํต์ฌ ๊ตฌํ (3147์ค)
include/linux/rmap.h โ rmap ๊ณต๊ฐ API, ๊ตฌ์กฐ์ฒด ์ ์ (995์ค)
mm/internal.h โ ๋ด๋ถ ์ ํธ๋ฆฌํฐ
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
rmap๋ง ๋จ๋ ์ผ๋ก ๋ณด์ง ๋ง๊ณ , ์ ์ฒด ๋ฉ๋ชจ๋ฆฌ ์๋ ฅ๊ณผ ํ์ด์ง ํดํธ ์ถ์ธ๋ฅผ ๊ฐ์ด ๋ณด๋ฉด ์์ธ์ ์ก๊ธฐ ์ฝ์ต๋๋ค.
# anon_vma ์บ์ ํต๊ณ
grep -i "anon_vma" /proc/slabinfo
# ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ ๋งต์์ rmap ๊ด๋ จ ์ ๋ณด ํ์ธ
cat /proc/<pid>/smaps | head -50
# ํ์ด์ง ๋งคํ ์นด์ดํธ ํ์ธ (mapcount)
cat /proc/kpagecount | head -20
# rmap ๊ด๋ จ ํธ๋ ์ด์ค ์ด๋ฒคํธ ํ์ธ
ls /sys/kernel/debug/tracing/events/rmap/ 2>/dev/null
# folio mapcount ๋๋ฒ๊ทธ (CONFIG_DEBUG_VM ๋น๋)
cat /sys/kernel/debug/rmap_stats 2>/dev/null
# KSM์ด rmap์ ์ฌ์ฉํ๋์ง ํ์ธ
cat /sys/kernel/mm/ksm/pages_shared
cat /sys/kernel/mm/ksm/pages_sharing
# ํ์ด์ง ํ
์ด๋ธ walk๋ฅผ ํตํ ๋งคํ ํ์ธ
cat /proc/<pid>/pagemap | head -20
# ๋ฉ๋ชจ๋ฆฌ ํ์ ์ rmap walk ๋์ ํ์ธ
echo 1 > /proc/sys/vm/drop_caches
dmesg | tail -20
# ํ์ด์ง ํดํธ์ ์ต๋ช
/ํ์ผ ํ์ด์ง ๊ท๋ชจ ํ์ธ
cat /proc/vmstat | grep -E 'pgfault|pgmajfault|nr_anon_pages|nr_file_pages|nr_page_table_pages'
cat /proc/meminfo | grep -E 'AnonPages|Mapped|Cached|SwapCached|PageTables'
# ์ ์ฒด ๋ฉ๋ชจ๋ฆฌ ์๋ ฅ๊ณผ ๋ถํฌ ํ์ธ
cat /proc/pressure/memory
cat /proc/buddyinfo
cat /proc/slabinfo | grep -E 'anon_vma|anon_vma_chain|vm_area_struct'
๊ฐ์ด ๋ณด๋ ์งํ
| ์งํ | ์๋ฏธ | ํจ๊ป ๋ณด๋ ์ด์ |
|---|---|---|
| `AnonPages` | ์ต๋ช ํ์ด์ง ๊ท๋ชจ | `rmap_walk_anon()`๊ณผ COW ํ๋์ด ๋ง์์๋ก ๊ฐ์ด ์ปค์ง๊ธฐ ์ฝ์ต๋๋ค. |
| `Cached` | ํ์ผ ํ์ด์ง ๊ท๋ชจ | `rmap_walk_file()` ๊ฒฝ๋ก์ page cache ํ์๊ฐ ์์ฃผ ์ผ์ด๋๋์ง ๋ณด๊ธฐ์ ์ข์ต๋๋ค. |
| `pgfault` / `pgmajfault` | ํ์ด์ง ํดํธ ์ถ์ธ | ์ ๋งคํ๊ณผ ์ค์ I/O๊ฐ ์ผ๋ง๋ ์์ฃผ ๋ฐ์ํ๋์ง ํ์ธํฉ๋๋ค. |
| `PageTables` | ํ์ด์ง ํ ์ด๋ธ ๋น์ฉ | mapcount ๋ณํ์ PTE ์ ๋ฆฌ ๋ถ๋ด์ ๊ฐ์ด ๊ฐ๋ ํ ์ ์์ต๋๋ค. |
| `anon_vma` / `anon_vma_chain` | rmap ๋ฉํ๋ฐ์ดํฐ | fork, COW, ์ต๋ช ํ์ด์ง ์๊ฐ ๋ ๋ slab ์ฌ์ฉ๋์ด ํจ๊ป ์ปค์ง๋๋ค. |
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
struct anon_vma
์ต๋ช ํ์ด์ง์ ์ญ๋ฐฉํฅ ๋งคํ์ ๊ด๋ฆฌํ๋ ํต์ฌ ๊ตฌ์กฐ์ฒด์ ๋๋ค. fork๋ ํ๋ก์ธ์ค ๊ฐ์ ํธ๋ฆฌ ํํ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
// include/linux/rmap.h:32-68
struct anon_vma {
struct anon_vma *root; // ์ด anon_vma ํธ๋ฆฌ์ ๋ฃจํธ
struct rw_semaphore rwsem; // ์์ : ์ฐ๊ธฐ์ ๊ธ, ์ํ: ์ฝ๊ธฐ์ ๊ธ
atomic_t refcount; // ์ฐธ์กฐ ์นด์ดํธ
unsigned long num_children; // ์์ anon_vma ์ (์๊ธฐ ํฌํจ)
unsigned long num_active_vmas; // ์ด anon_vma๋ฅผ ๊ฐ๋ฆฌํค๋ VMA ์
struct anon_vma *parent; // ๋ถ๋ชจ anon_vma
struct rb_root_cached rb_root; // ๊ด๋ จ VMA์ interval tree
};
struct anon_vma_chain (AVC)
VMA์ anon_vma๋ฅผ ์ฐ๊ฒฐํ๋ ์ฒด์ธ ๊ตฌ์กฐ์ฒด์ ๋๋ค. ํ๋์ VMA๋ ์ฌ๋ฌ anon_vma์ ์ฐ๊ฒฐ๋ ์ ์๊ณ , ํ๋์ anon_vma๋ ์ฌ๋ฌ VMA๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค.
// include/linux/rmap.h:83-92
struct anon_vma_chain {
struct vm_area_struct *vma; // ์ฐ๊ฒฐ๋ VMA
struct anon_vma *anon_vma; // ์ฐ๊ฒฐ๋ anon_vma
struct list_head same_vma; // ๊ฐ์ VMA์ ๋ค๋ฅธ AVC ๋ชฉ๋ก
struct rb_node rb; // anon_vma interval tree ๋
ธ๋
unsigned long rb_subtree_last; // interval tree ์๋ธํธ๋ฆฌ ๋ง์ง๋ง ๊ฐ
};
struct rmap_walk_control
rmap walk๋ฅผ ์ ์ดํ๋ ์ปจํธ๋กค ๊ตฌ์กฐ์ฒด์ ๋๋ค. ๊ฐ walk ์ ํ์ ๋ง๋ ์ฝ๋ฐฑ์ ์ค์ ํฉ๋๋ค.
// include/linux/rmap.h:951-965
struct rmap_walk_control {
void *arg; // ์ฝ๋ฐฑ์ ์ ๋ฌ๋๋ ์ธ์
bool try_lock; // ๋ฝ ํ๋ ์คํจ ์ ์ฆ์ ๋ฐํ
bool contended; // ๋ฝ ๊ฒฝ์์ผ๋ก ์ค๋จ๋จ ํ๋๊ทธ
bool (*rmap_one)(struct folio *folio, struct vm_area_struct *vma,
unsigned long addr, void *arg); // ๋งค VMA์์ ํธ์ถ๋ ์ฝ๋ฐฑ
int (*done)(struct folio *folio); // ์ํ ์ข
๋ฃ ์กฐ๊ฑด ๊ฒ์ฌ
struct anon_vma *(*anon_lock)(const struct folio *folio,
struct rmap_walk_control *rwc); // anon ๋ฝ ํ๋
bool (*invalid_vma)(struct vm_area_struct *vma, void *arg); // ๊ฑด๋๋ธ VMA ํ๋ณ
};
struct page_vma_mapped_walk (PVMW)
ํน์ ํ์ด์ง๊ฐ ์ด๋ค VMA์ ๋งคํ๋์ด ์๋์ง ์ํํ๋ ๊ตฌ์กฐ์ฒด์ ๋๋ค.
// include/linux/rmap.h:864-874
struct page_vma_mapped_walk {
unsigned long pfn; // ์ฐพ๋ ํ์ด์ง์ PFN
unsigned long nr_pages; // folio์ ํ์ด์ง ์
pgoff_t pgoff; // folio์ ํ์ด์ง ์คํ์
struct vm_area_struct *vma; // ๋์ VMA
unsigned long address; // ํ์ฌ ๊ฐ์ ์ฃผ์
pmd_t *pmd; // ๋งคํ๋ PMD ์ํธ๋ฆฌ
pte_t *pte; // ๋งคํ๋ PTE ์ํธ๋ฆฌ
spinlock_t *ptl; // ํ์ด์ง ํ
์ด๋ธ ์ ๊ธ
unsigned int flags; // PVMW_SYNC, PVMW_MIGRATION ๋ฑ
};
enum ttu_flags (Try To Unmap ํ๋๊ทธ)
// include/linux/rmap.h:94-105
enum ttu_flags {
TTU_USE_SHARED_ZEROPAGE = 0x2, // large folio ๋ฏธ์ฌ์ฉ ํ์ด์ง์ฉ
TTU_SPLIT_HUGE_PMD = 0x4, // THP PMD๋ฅผ PTE๋ก ๋ถํ
TTU_IGNORE_MLOCK = 0x8, // mlock ๋ฌด์
TTU_SYNC = 0x10, // racy ๊ฒ์ฌ ํํผ (๋๊ธฐํ)
TTU_HWPOISON = 0x20, // hwpoison ์ํธ๋ฆฌ๋ก ๋ณํ
TTU_BATCH_FLUSH = 0x40, // TLB flush ๋ฐฐ์น ์ฒ๋ฆฌ
TTU_RMAP_LOCKED = 0x80, // rmap ๋ฝ ๋ฏธํ๋ (ํธ์ถ์๊ฐ ๋ณด์ )
};
ํต์ฌ ํจ์
1. rmap_walk โ rmap ์ํ ์ํธ๋ฆฌ ํฌ์ธํธ
folio์ ๋ชจ๋ ๋งคํ VMA๋ฅผ ์ํํฉ๋๋ค. folio ์ ํ์ ๋ฐ๋ผ anon, file, KSM ์ํ๋ก ๋ถ๊ธฐํฉ๋๋ค.
// mm/rmap.c:3093-3101
void rmap_walk(struct folio *folio, struct rmap_walk_control *rwc)
{
if (unlikely(folio_test_ksm(folio)))
rmap_walk_ksm(folio, rwc); // KSM folio ์ฒ๋ฆฌ
else if (folio_test_anon(folio))
rmap_walk_anon(folio, rwc, false); // ์ต๋ช
ํ์ด์ง ์ฒ๋ฆฌ
else
rmap_walk_file(folio, rwc, false); // ํ์ผ ๊ธฐ๋ฐ ํ์ด์ง ์ฒ๋ฆฌ
}
๋ถ๊ธฐ ๋ก์ง:
rmap_walk_ksm(): KSM stable/unstable tree ์ํrmap_walk_anon(): anon_vma->rb_root interval tree ์ํrmap_walk_file(): mapping->i_mmap interval tree ์ํ2. rmap_walk_anon โ ์ต๋ช ํ์ด์ง rmap ์ํ
anon_vma ํธ๋ฆฌ์์ ๋ชจ๋ ๊ด๋ จ VMA๋ฅผ ์ฐพ์ rmap_one ์ฝ๋ฐฑ์ ์คํํฉ๋๋ค.
// mm/rmap.c:2956-3000
static void rmap_walk_anon(struct folio *folio,
struct rmap_walk_control *rwc, bool locked)
{
struct anon_vma *anon_vma;
pgoff_t pgoff_start, pgoff_end;
struct anon_vma_chain *avc;
/* folio lock์ด ์์ด์ผ mapping์ด ๋ฐ๋์ง ์์ต๋๋ค. */
VM_WARN_ON_FOLIO(!folio_test_locked(folio), folio);
if (locked) {
anon_vma = folio_anon_vma(folio); // ์ด๋ฏธ ๋ฝ๋ ๊ฒฝ์ฐ
/* anon_vma๊ฐ ์ฌ๋ผ์ก๋ค๋ฉด ์ ๋ฉ๋๋ค. */
VM_BUG_ON_FOLIO(!anon_vma, folio);
} else {
anon_vma = rmap_walk_anon_lock(folio, rwc); // ๋ฝ ํ๋
}
if (!anon_vma) return;
pgoff_start = folio_pgoff(folio);
pgoff_end = pgoff_start + folio_nr_pages(folio) - 1;
/* interval tree์์ ๊ฒน์น๋ ๋ชจ๋ VMA๋ฅผ ์ํํฉ๋๋ค. */
anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root,
pgoff_start, pgoff_end) {
struct vm_area_struct *vma = avc->vma;
unsigned long address = vma_address(vma, pgoff_start,
folio_nr_pages(folio));
VM_BUG_ON_VMA(address == -EFAULT, vma);
cond_resched();
if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
continue; // ๊ฑด๋๋ธ VMA
if (!rwc->rmap_one(folio, vma, address, rwc->arg))
break; // ์ฝ๋ฐฑ์ด false ๋ฐํ ์ ์ํ ์ค๋จ
if (rwc->done && rwc->done(folio))
break; // ์ข
๋ฃ ์กฐ๊ฑด ์ถฉ์กฑ
}
if (!locked)
anon_vma_unlock_read(anon_vma);
}
3. try_to_unmap โ ํ์ด์ง ๋งคํ ์ ๊ฑฐ
folio์ ๋ชจ๋ ํ์ด์ง ํ ์ด๋ธ ๋งคํ์ ์ ๊ฑฐํฉ๋๋ค. ํ์ด์ง ํ์(swap out), OOM kill ์ ์ฌ์ฉ๋ฉ๋๋ค.
// mm/rmap.c:2386-2399
void try_to_unmap(struct folio *folio, enum ttu_flags flags)
{
struct rmap_walk_control rwc = {
.rmap_one = try_to_unmap_one, // ๋งค VMA์์ PTE ์ ๊ฑฐ
.arg = (void *)flags,
.done = folio_not_mapped, // ๋ชจ๋ ๋งคํ ์ ๊ฑฐ ์ ์ข
๋ฃ
.anon_lock = folio_lock_anon_vma_read,
};
if (flags & TTU_RMAP_LOCKED)
rmap_walk_locked(folio, &rwc); // ์ด๋ฏธ rmap ๋ฝ ๋ณด์
else
rmap_walk(folio, &rwc); // ๋ฝ ์์ด ์ํ
}
try_to_unmap_one ํต์ฌ ๋ถ๊ธฐ:
VM_LOCKED VMA โ mlock ๋ณต์ ํ ์ค๋จTTU_SPLIT_HUGE_PMD ํ๋๊ทธ ์ PTE๋ก ๋ถํ page_swap_entry())4. try_to_migrate โ ํ์ด์ง ๋ง์ด๊ทธ๋ ์ด์ ์ ์ํ ๋งคํ ๊ต์ฒด
๋ชจ๋ PTE๋ฅผ migration entry๋ก ๊ต์ฒดํฉ๋๋ค. ์ค์ ๋ฉ๋ชจ๋ฆฌ ๋ณต์ฌ ์ ์ ์ฌ์ฉ๋ฉ๋๋ค.
// mm/rmap.c:2731-2767
void try_to_migrate(struct folio *folio, enum ttu_flags flags)
{
struct rmap_walk_control rwc = {
.rmap_one = try_to_migrate_one, // ๋งค VMA์์ migration entry ์ค์น
.arg = (void *)flags,
.done = folio_not_mapped,
.anon_lock = folio_lock_anon_vma_read,
};
// ์ ํจํ์ง ์์ ํ๋๊ทธ ๊ฒ์ฆ
if (WARN_ON_ONCE(flags & ~(TTU_RMAP_LOCKED | TTU_SPLIT_HUGE_PMD |
TTU_SYNC | TTU_BATCH_FLUSH)))
return;
// ๋๋ฐ์ด์ค ์ ์ฉ folio ์ฒ๋ฆฌ ์ ํ
if (folio_is_zone_device(folio) &&
(!folio_is_device_private(folio) && !folio_is_device_coherent(folio)))
return;
// exec() ์ค ์์ VMA ๊ฑด๋๋ฐ๊ธฐ
if (!folio_test_ksm(folio) && folio_test_anon(folio))
rwc.invalid_vma = invalid_migration_vma;
if (flags & TTU_RMAP_LOCKED)
rmap_walk_locked(folio, &rwc);
else
rmap_walk(folio, &rwc);
}
5. folio_referenced โ ํ์ด์ง ์ฐธ์กฐ ๊ฒ์ฌ
folio๊ฐ ์ฐธ์กฐ(referenced)๋์๋์ง ๋ชจ๋ ๋งคํ์์ ๊ฒ์ฌํฉ๋๋ค. ํ์ด์ง ํ์ ์ ์ ํด(idle) ํ๋จ์ ์ฌ์ฉ๋ฉ๋๋ค.
// mm/rmap.c:1059-1094
int folio_referenced(struct folio *folio, int is_locked,
struct mem_cgroup *memcg, vm_flags_t *vm_flags)
{
bool we_locked = false;
struct folio_referenced_arg pra = {
.mapcount = folio_mapcount(folio),
.memcg = memcg,
};
struct rmap_walk_control rwc = {
.rmap_one = folio_referenced_one, // ๋งค VMA์์ referenced ๊ฒ์ฌ
.arg = (void *)&pra,
.anon_lock = folio_lock_anon_vma_read,
.try_lock = true, // ๋ฝ ๊ฒฝ์ ์ ํํผ
.invalid_vma = invalid_folio_referenced_vma,
};
*vm_flags = 0;
if (!pra.mapcount)
return 0;
if (!folio_raw_mapping(folio))
return 0;
/* folio_trylock์ผ๋ก ์์ ํ๊ฒ ์ ๊ธ์ ํ๋ํฉ๋๋ค. */
if (!is_locked) {
we_locked = folio_trylock(folio);
if (!we_locked) return 1;
}
rmap_walk(folio, &rwc);
*vm_flags = pra.vm_flags;
if (we_locked)
folio_unlock(folio);
return rwc.contended ? -1 : pra.referenced;
}
ํธ์ถ ํ๋ฆ
try_to_unmap(folio, flags)
โโ rmap_walk(folio, &rwc)
โโ [anon] rmap_walk_anon(folio, rwc, false)
โ โโ rmap_walk_anon_lock(folio, rwc) โ anon_vma ๋ฝ ํ๋
โ โโ anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root)
โ โ โโ rwc->invalid_vma(vma, arg) โ ๊ฑด๋๋ธ VMA ํ์ธ
โ โ โโ rwc->rmap_one(folio, vma, address, arg)
โ โ โ โโ try_to_unmap_one(folio, vma, address, arg)
โ โ โ โโ page_vma_mapped_walk(&pvmw) โ PTE ์ํ
โ โ โ โ โโ [THP] split_huge_pmd_locked() โ ์ฌ์ํ
โ โ โ โ โโ [anon] folio_try_share_anon_rmap_pte()
โ โ โ โ โโ get_and_clear_ptes() โ PTE ์ ๊ฑฐ
โ โ โ โ โโ set_pte_at(swp_pte) โ swap entry ์ค์น
โ โ โ โ โโ folio_remove_rmap_ptes() โ mapcount ๊ฐ์
โ โ โ โโ mmu_notifier_invalidate_range_end()
โ โ โโ rwc->done(folio) โ folio_not_mapped() ํ์ธ
โ โโ anon_vma_unlock_read(anon_vma)
โโ [file] rmap_walk_file(folio, rwc, false)
โ โโ i_mmap_lock_read(mapping)
โ โโ vma_interval_tree_foreach(vma, &mapping->i_mmap)
โ โ โโ rwc->rmap_one(folio, vma, address, arg)
โ โโ i_mmap_unlock_read(mapping)
โโ [KSM] rmap_walk_ksm(folio, rwc)
์กฐ๊ฑด๋ณ ๋น๊ต
rmap walk ์ ํ ๋น๊ต
| ํญ๋ชฉ | rmap_walk_anon | rmap_walk_file | rmap_walk_ksm |
|---|---|---|---|
| **๋์** | ์ต๋ช ํ์ด์ง (malloc ๋ฑ) | ํ์ผ ๋งคํ (mmap ๋ฑ) | KSM ๋ณํฉ ํ์ด์ง |
| **๋ฐ์ดํฐ ๊ตฌ์กฐ** | anon_vma->rb_root (interval tree) | address_space->i_mmap (interval tree) | stable_node tree |
| **๋ฝ** | anon_vma->root->rwsem (์ฝ๊ธฐ) | mapping->i_mmap_rwsem (์ฝ๊ธฐ) | KSM lock |
| **์ํ ๋์** | anon_vma_chain โ VMA | VMA interval tree โ VMA | stable_node โ rmap_item โ VMA |
| **ํธ์ถ ๊ฒฝ๋ก** | ํ์, OOM, KSM ์ค์บ | ํ์, truncate, fsync | KSM ๋ณํฉ |
try_to_unmap vs try_to_migrate ๋น๊ต
| ํญ๋ชฉ | try_to_unmap | try_to_migrate |
|---|---|---|
| **๋ชฉ์ ** | ํ์ด์ง ๋งคํ ์์ ์ ๊ฑฐ | PTE๋ฅผ migration entry๋ก ๊ต์ฒด |
| **PTE ํ์ ์ฒ๋ฆฌ** | hwpoison/swap entry ๋๋ ์ ๊ฑฐ | writable/readable/exclusive migration entry |
| **VM_LOCKED ์ฒ๋ฆฌ** | mlock ๋ณต์ ํ ์ค๋จ | ๋ฌด์ (mlock ๋ถํ์) |
| **TTU_HWPOISON** | ์ง์ | ๋ฏธ์ง์ |
| **TTU_IGNORE_MLOCK** | ์ง์ | ํด๋น ์์ |
| **ํธ์ถ ์์ ** | ํ์ด์ง ํ์(swap out), OOM | ํ์ด์ง ๋ง์ด๊ทธ๋ ์ด์ ์์ ์ |
anon ํ์ด์ง ๋งคํ ์ถ๊ฐ API ๋น๊ต
| ํจ์ | ์๋๋ฆฌ์ค | ๋ ๋ฒจ | mapcount ์ฒ๋ฆฌ |
|---|---|---|---|
| `folio_add_anon_rmap_ptes()` | ๊ธฐ์กด folio์ PTE ๋งคํ ์ถ๊ฐ | PTE | atomic_inc_and_test |
| `folio_add_anon_rmap_pmd()` | ๊ธฐ์กด folio์ PMD ๋งคํ ์ถ๊ฐ | PMD | atomic_inc (entire_mapcount) |
| `folio_add_new_anon_rmap()` | ์ folio์ ์ฒซ ๋งคํ | PTE/PMD | atomic_set(0) (์๋ก ์์) |
| `folio_add_file_rmap_ptes()` | ํ์ผ ๋งคํ PTE ์ถ๊ฐ | PTE | atomic_inc_and_test |
| `folio_add_file_rmap_pmd()` | ํ์ผ ๋งคํ PMD ์ถ๊ฐ | PMD | atomic_inc (entire_mapcount) |
TTU ํ๋๊ทธ ์ฌ์ฉ ์๋๋ฆฌ์ค ๋น๊ต
| ํ๋๊ทธ | try_to_unmap | try_to_migrate | ๋น๊ณ |
|---|---|---|---|
| TTU_SPLIT_HUGE_PMD | THP PMD๋ฅผ PTE๋ก ๋ถํ ํ ์ฌ์ํ | migration entry ์ค์น ์ ๋ถํ | |
| TTU_SYNC | PTE ์ ๊ฑฐ ํ ๋๊ธฐํ ๋๊ธฐ | ๋ง์ด๊ทธ๋ ์ด์ ๋๊ธฐ | |
| TTU_HWPOISON | hwpoison swap entry ์ค์น | ๋ฏธ์ง์ | |
| TTU_BATCH_FLUSH | TLB flush ๋ฐฐ์น ์ฒ๋ฆฌ | ๋ฏธ์ง์ | |
| TTU_RMAP_LOCKED | rmap ๋ฝ ๋ฏธํ๋ | rmap ๋ฝ ๋ฏธํ๋ | |
| TTU_IGNORE_MLOCK | VM_LOCKED ๋ฌด์ | ํด๋น ์์ |
lock ordering
rmap ๊ด๋ จ ์ ๊ธ ์์ (mm/rmap.c ์ฃผ์์์ ๋ฐ์ท):
inode->i_rwsem (์ฐ๊ธฐ/ํธ๋ ์ผ์ดํธ ์)
mm->mmap_lock
mapping->invalidate_lock
folio_lock
hugetlbfs_i_mmap_rwsem_key
vma_start_write
mapping->i_mmap_rwsem
anon_vma->rwsem
mm->page_table_lock or pte_lock
swap_lock
mmlist_lock