Folio / Page Cache

๊ด€๋ จ ์†Œ์Šค: mm/filemap.c, mm/folio-compat.c, mm/page-writeback.c
๊ด€๋ จ ๋ฌธ์„œ: ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š” ยท Buddy Allocator ยท ํŽ˜์ด์ง€ ํšŒ์ˆ˜ ยท VMA / mmap ยท tmpfs / shmem

๊ฐœ์š” (Overview)

Folio๋Š” Linux 5.16์—์„œ ๋„์ž…๋œ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์˜ ํ•ต์‹ฌ ๋‹จ์œ„๋กœ, ๊ธฐ์กด struct page์˜ ๋‹จ์ ์„ ๋ณด์™„ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด ํŽ˜์ด์ง€ ์บ์‹œ๋Š” ๊ฐœ๋ณ„ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๊ด€๋ฆฌ๋˜์–ด large folio(THP ๋“ฑ) ์ง€์›์— ๋น„ํšจ์œจ์ ์ด์—ˆ์œผ๋‚˜, folio๋Š” compound page ์ „์ฒด๋ฅผ ํ•˜๋‚˜์˜ ๋‹จ์œ„๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ์บ์‹œ(Page Cache)๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ๋ธ”๋ก ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์บ์‹ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, address_space ๊ตฌ์กฐ์ฒด๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

folio์˜ ํ•ต์‹ฌ ์žฅ์ ์€ compound page์˜ head page๋งŒ ์ถ”์ ํ•˜๋ฉด ๋˜์–ด lock ๊ด€๋ฆฌ, dirty/writeback ์ถ”์ , reference counting์ด ๋‹จ์ˆœํ•ด์ง„๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ธฐ์กด page API์™€์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด folio-compat.c์— ๋ ˆ๊ฑฐ์‹œ ๋ž˜ํผ ํ•จ์ˆ˜๊ฐ€ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. Linux 7.0์—์„œ๋Š” _mm_id ๊ธฐ๋ฐ˜ rmap ์ตœ์ ํ™”, _deferred_list๋ฅผ ํ†ตํ•œ ๋Œ€๊ธฐ ๋ถ„ํ• (split under pressure), HugeTLB ์ „์šฉ ํ•„๋“œ ๋“ฑ์ด ์ถ”๊ฐ€๋˜์–ด ๊ตฌ์กฐ์ ์œผ๋กœ ๋” ์ •๊ตํ•ด์กŒ์Šต๋‹ˆ๋‹ค.

์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ:
mm/filemap.c          โ€” ํŽ˜์ด์ง€ ์บ์‹œ ํ•ต์‹ฌ ์—ฐ์‚ฐ (์กฐํšŒ, ์ถ”๊ฐ€, ์ฝ๊ธฐ, ์“ฐ๊ธฐ, ํดํŠธ)
mm/folio-compat.c     โ€” ๊ธฐ์กด page API โ†’ folio ๋ž˜ํผ (unlock_page, mark_page_accessed ๋“ฑ)
mm/page-writeback.c   โ€” ๋”ํ‹ฐ ํŽ˜์ด์ง€ writeback ๋ฐ dirty throttling
include/linux/mm_types.h  โ€” struct folio ์ •์˜ (Linux 7.0: _mm_id, _deferred_list ํฌํ•จ)
include/linux/fs.h        โ€” struct address_space, address_space_operations ์ •์˜
include/linux/pagemap.h   โ€” folio_lock, folio_trylock ๋“ฑ ์ž ๊ธˆ API

๋น ๋ฅธ ์ ๊ฒ€ ๋ช…๋ น

# 1. ํŽ˜์ด์ง€ ์บ์‹œ์— ์บ์‹ฑ๋œ ํŽ˜์ด์ง€ ์ˆ˜ ํ™•์ธ
cat /proc/meminfo | grep -i "Cached"

# 2. ํ˜„์žฌ ์‹œ์Šคํ…œ์˜ Active/Inactive(file) ํŽ˜์ด์ง€ ์ˆ˜ ํ™•์ธ
cat /proc/meminfo | grep -E "Active\(file\)|Inactive\(file\)"

# 3. writeback ์ค‘์ธ ํŽ˜์ด์ง€ ์ˆ˜ ํ™•์ธ
cat /proc/meminfo | grep -i "Dirty\|Writeback"

# 4. ํŽ˜์ด์ง€ ์บ์‹œ ๊ด€๋ จ slab ์บ์‹œ ํ™•์ธ (radix_tree_node โ†’ xarray)
slabtop -o | grep -i "xarray\|inode_cache\|dentry"

# 5. vm.dirty_ratio / vm.dirty_background_ratio ํŒŒ๋ผ๋ฏธํ„ฐ ํ™•์ธ
sysctl vm.dirty_ratio vm.dirty_background_ratio vm.dirty_writeback_interval vm.dirty_expire_interval

# 6. ํŠน์ • inode์˜ ํŽ˜์ด์ง€ ์บ์‹œ ํฌ๊ธฐ ํ™•์ธ (debugfs)
cat /proc/<pid>/smaps | grep -A 5 "file" | grep -i "size"

# 7. ํŒŒ์ผ ์บ์‹œ ํžˆํŠธ์œจ ํ™•์ธ (perf ๋˜๋Š” sar)
sar -B 1 5  # pgscank/s (page reclaim), pgscand/s (direct reclaim) ๊ด€์ฐฐ

# 8. ํŒŒ์ผ ์‹œ์Šคํ…œ๋ณ„ ํŽ˜์ด์ง€ ์บ์‹œ ํ†ต๊ณ„ ํ™•์ธ
cat /proc/meminfo | grep -E "Cached|Buffers|SwapCached"

# 9. folio lock ๋Œ€๊ธฐ ๊ณต์ •์„ฑ ํ™•์ธ
sysctl vm.page_lock_unfairness  # ๊ธฐ๋ณธ๊ฐ’: 5

# 10. writeback ์Šค๋ ˆ๋“œ ๋™์ž‘ ํ™•์ธ
cat /proc/vmstat | grep -E "nr_dirty|nr_writeback|nr_congested"

# 11. mmap๋œ ํŒŒ์ผ ํŽ˜์ด์ง€ ํดํŠธ ํ†ต๊ณ„
cat /proc/vmstat | grep -E "pgmajfault|pgfault"

# 12. ์ฃผ์š” ํ”„๋กœ์„ธ์Šค์˜ ํŽ˜์ด์ง€ ์บ์‹œ ์‚ฌ์šฉ๋Ÿ‰ ํ™•์ธ
cat /proc/<pid>/smaps_rollup | grep -E "RSS|PSS"

ํ•ต์‹ฌ ์ž๋ฃŒ๊ตฌ์กฐ

struct folio

folio๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ์—ฐ์†๋œ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ํ•˜๋‚˜์˜ ๋…ผ๋ฆฌ์  ๋‹จ์œ„๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. struct page์™€์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด union์œผ๋กœ ๊ฒน์ณ์ ธ ์žˆ์œผ๋ฉฐ, Linux 7.0์—์„œ๋Š” _mm_id ๊ธฐ๋ฐ˜ rmap ์ตœ์ ํ™”, _deferred_list ๋“ฑ ์ƒˆ๋กœ์šด ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

// include/linux/mm_types.h:401-506 (Linux 7.0)
struct folio {
union {
struct {
memdesc_flags_t flags;           // Atomic ํ”Œ๋ž˜๊ทธ (locked, uptodate, dirty ๋“ฑ)
union {
struct list_head lru;        // LRU ๋ฆฌ์ŠคํŠธ (active/inactive)
struct { void *__filler; unsigned long mlock_count; }; // Unevictable
struct dev_pagemap *pgmap;   // ZONE_DEVICE์šฉ
};
struct address_space *mapping;   // ์†Œ์œ  address_space ํฌ์ธํ„ฐ
union {
pgoff_t index;               // ํŒŒ์ผ ๋‚ด ์˜คํ”„์…‹ (ํŽ˜์ด์ง€ ์ธ๋ฑ์Šค)
unsigned long share;         // fsdax์šฉ share count
};
union {
void *private;               // ํŒŒ์ผ ์‹œ์Šคํ…œ ์ „์šฉ ๋ฐ์ดํ„ฐ (buffer_head ๋“ฑ)
swp_entry_t swap;            // swap ์บ์‹œ์—์„œ์˜ swap entry
};
atomic_t _mapcount;              // RMAP์—์„œ์˜ ๋งคํ•‘ ์นด์šดํŠธ (-1 = ๋งคํ•‘ ์•ˆ๋จ)
atomic_t _refcount;              // ์ฐธ์กฐ ์นด์šดํŠธ
unsigned long memcg_data;        // memcgroup ๋ฐ์ดํ„ฐ
};
struct page page;  // ๊ธฐ์กด struct page์™€ ํ˜ธํ™˜์„ฑ
};
// 2๋ฒˆ์งธ struct page ์˜์—ญ (large folio์šฉ)
union {
struct {
atomic_t _large_mapcount;        // large folio ์ „์ฒด ๋งคํ•‘ ์นด์šดํŠธ
atomic_t _nr_pages_mapped;       // ์‹ค์ œ๋กœ ๋งคํ•‘๋œ ํŽ˜์ด์ง€ ์ˆ˜
atomic_t _entire_mapcount;       // ์ „์ฒด ๋งคํ•‘ ์นด์šดํŠธ (64bit)
atomic_t _pincount;              // DMA ํ•€ ์นด์šดํŠธ
mm_id_mapcount_t _mm_id_mapcount[2]; // rmap์šฉ MM ID๋ณ„ ๋งคํ•‘ ์นด์šดํŠธ
union {
mm_id_t _mm_id[2];           // rmap์šฉ MM ID
unsigned long _mm_ids;       // ๋น„ํŠธ ํ”Œ๋ž˜๊ทธ (์ž ๊ธˆ ํฌํ•จ)
};
unsigned int _nr_pages;          // folio ๋‚ด ์ด ํŽ˜์ด์ง€ ์ˆ˜
};
struct page __page_1;
};
// 3๋ฒˆ์งธ struct page ์˜์—ญ (deferred split์šฉ)
union {
struct {
struct list_head _deferred_list; // ๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ• ์‹œ ๋ถ„ํ•  ๋Œ€๊ธฐ folio ๋ฆฌ์ŠคํŠธ
};
struct page __page_2;
};
// 4๋ฒˆ์งธ struct page ์˜์—ญ (HugeTLB ์ „์šฉ)
union {
struct {
void *_hugetlb_subpool;          // HugeTLB ์„œ๋ธŒํ’€
void *_hugetlb_cgroup;           // HugeTLB memcg
void *_hugetlb_cgroup_rsvd;      // HugeTLB memcg ์˜ˆ์•ฝ
void *_hugetlb_hwpoison;         // HugeTLB ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜
};
struct page __page_3;
};
};

Linux 7.0 FOLIO_MATCH ์ •์  ๊ฒ€์ฆ (mm_types.h:508-547):

// struct folio์™€ struct page์˜ ํ•„๋“œ ์˜คํ”„์…‹์ด ์ผ์น˜ํ•˜๋Š”์ง€ ์ปดํŒŒ์ผ ํƒ€์ž„ ๊ฒ€์ฆ
FOLIO_MATCH(flags, flags);           // folio->flags == page->flags
FOLIO_MATCH(lru, lru);               // folio->lru == page->lru (compound_head)
FOLIO_MATCH(mapping, mapping);       // folio->mapping == page->mapping
FOLIO_MATCH(__folio_index, index);   // folio->index == page->__folio_index
FOLIO_MATCH(_mapcount, _mapcount);   // folio->_mapcount == page->_mapcount
FOLIO_MATCH(_refcount, _refcount);   // folio->_refcount == page->_refcount

ํ•ต์‹ฌ ํ•„๋“œ ์„ค๋ช…:

ํ•„๋“œ์—ญํ• 
`flags`ํŽ˜์ด์ง€ ์ƒํƒœ ํ”Œ๋ž˜๊ทธ (locked, uptodate, dirty, writeback, lru ๋“ฑ). `include/linux/page-flags.h`์—์„œ `PG_locked`, `PG_dirty`, `PG_uptodate` ๋“ฑ ์ •์˜
`mapping`์ด folio๊ฐ€ ์†ํ•œ `address_space` ํฌ์ธํ„ฐ. `NULL`์ด๋ฉด unlinked. LSB๊ฐ€ 1์ด๋ฉด anonymous page (`FOLIO_MAPPING_ANON`)
`index`ํŒŒ์ผ ๋‚ด ํŽ˜์ด์ง€ ์ธ๋ฑ์Šค (page offset). `address_space->i_pages` xarray์—์„œ์˜ ํ‚ค
`private`ํŒŒ์ผ ์‹œ์Šคํ…œ ์ „์šฉ ๋ฐ์ดํ„ฐ. buffer_head ํฌ์ธํ„ฐ, swap entry ๋“ฑ์œผ๋กœ ์‚ฌ์šฉ
`_mapcount`์ด ํŽ˜์ด์ง€๊ฐ€ ๋ช‡ ๊ฐœ์˜ PTE์— ๋งคํ•‘๋˜์–ด ์žˆ๋Š”์ง€ ์ถ”์ . `-1`์ด๋ฉด ๋งคํ•‘ ์—†์Œ
`_refcount`์ด folio์— ๋Œ€ํ•œ ์ฐธ์กฐ ์นด์šดํŠธ. 0์ด ๋˜๋ฉด free ๊ฐ€๋Šฅ
`_large_mapcount`large folio์—์„œ ์ „์ฒด ๋งคํ•‘ ์นด์šดํŠธ (2๋ฒˆ์งธ page ์˜์—ญ)
`_nr_pages_mapped`large folio์—์„œ ์‹ค์ œ๋กœ ๋งคํ•‘๋œ ํŽ˜์ด์ง€ ์ˆ˜
`_entire_mapcount`large folio ์ „์ฒด ๋งคํ•‘ ์นด์šดํŠธ (64bit ์‹œ์Šคํ…œ)
`_mm_id`Linux 7.0 rmap ์ตœ์ ํ™”: MM ID ๊ธฐ๋ฐ˜ ๋งคํ•‘ ์ถ”์ . ๊ธฐ์กด anon_vma ์ฒด์ธ ์ˆœํšŒ ๋Œ€๋น„ O(1) ์ ‘๊ทผ ๊ฐ€๋Šฅ
`_deferred_list`๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ• ์‹œ large folio๋ฅผ splitํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๊ธฐํ•˜๋Š” ๋ฆฌ์ŠคํŠธ
`_nr_pages`folio๊ฐ€ ํฌํ•จํ•˜๋Š” ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€ ์ˆ˜ (large folio)
`_hugetlb_*`HugeTLB ์ „์šฉ ํ•„๋“œ: ์„œ๋ธŒํ’€, memcg, ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ์ถ”์ 

struct address_space

ํŒŒ์ผ ์บ์‹œ์˜ ๋ฃจํŠธ ๊ตฌ์กฐ์ฒด์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์บ์‹ฑ๋œ ํŽ˜์ด์ง€๋Š” ์ด ๊ตฌ์กฐ์ฒด์˜ i_pages xarray์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

// include/linux/fs.h:470-490
struct address_space {
struct inode            *host;           // ์†Œ์œ  inode (ํŒŒ์ผ ๋˜๋Š” block device)
struct xarray           i_pages;         // ํŽ˜์ด์ง€ ์บ์‹œ (XArray ๊ธฐ๋ฐ˜)
struct rw_semaphore     invalidate_lock; // invalidate ์‹œ coherency ๋ณด์žฅ
gfp_t                   gfp_mask;        // ํ• ๋‹น ์‹œ ์‚ฌ์šฉํ•  GFP ํ”Œ๋ž˜๊ทธ
atomic_t                i_mmap_writable; // VM_SHARED writable ๋งคํ•‘ ์ˆ˜
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
atomic_t                nr_thps;         // non-shmem THP ์ˆ˜
#endif
struct rb_root_cached   i_mmap;          // mmap๋œ VMA ํŠธ๋ฆฌ (private/shared)
unsigned long           nrpages;         // ์ด ์บ์‹ฑ๋œ ํŽ˜์ด์ง€ ์ˆ˜
pgoff_t                 writeback_index; // writeback ์‹œ์ž‘ ์˜คํ”„์…‹
const struct address_space_operations *a_ops;  // ํŒŒ์ผ ์‹œ์Šคํ…œ ์—ฐ์‚ฐ ํ…Œ์ด๋ธ”
unsigned long           flags;           // AS_EIO, AS_ENOSPC, AS_DIRTY ๋“ฑ
errseq_t                wb_err;          // ์ตœ๊ทผ writeback ์—๋Ÿฌ
spinlock_t              i_private_lock;  // i_private_list ๋ณดํ˜ธ
struct list_head        i_private_list;  // ํŒŒ์ผ ์‹œ์Šคํ…œ ์ „์šฉ ๋ฆฌ์ŠคํŠธ
struct rw_semaphore     i_mmap_rwsem;    // i_mmap ๋ณดํ˜ธ
void                   *i_private_data;  // ํŒŒ์ผ ์‹œ์Šคํ…œ ์ „์šฉ ๋ฐ์ดํ„ฐ
} __attribute__((aligned(sizeof(long))));

struct address_space_operations

ํŒŒ์ผ ์‹œ์Šคํ…œ์ด ๊ตฌํ˜„ํ•ด์•ผ ํ•  ํŽ˜์ด์ง€ ์บ์‹œ ์—ฐ์‚ฐ ํ…Œ์ด๋ธ”์ž…๋‹ˆ๋‹ค.

// include/linux/fs.h:403-444
struct address_space_operations {
int (*read_folio)(struct file *, struct folio *);           // ๋‹จ์ผ folio ์ฝ๊ธฐ
int (*writepages)(struct address_space *, struct writeback_control *); // ๋”ํ‹ฐ ํŽ˜์ด์ง€ writeback
bool (*dirty_folio)(struct address_space *, struct folio *); // folio๋ฅผ dirty๋กœ ํ‘œ์‹œ
void (*readahead)(struct readahead_control *);              // readahead ์—ฐ์‚ฐ
int (*write_begin)(const struct kiocb *, struct address_space *,
loff_t pos, unsigned len,
struct folio **foliop, void **fsdata);  // ์“ฐ๊ธฐ ์‹œ์ž‘
int (*write_end)(const struct kiocb *, struct address_space *,
loff_t pos, unsigned len, unsigned copied,
struct folio *folio, void *fsdata);       // ์“ฐ๊ธฐ ์™„๋ฃŒ
bool (*release_folio)(struct folio *, gfp_t);              // folio ํ•ด์ œ ๊ฒ€์‚ฌ
void (*free_folio)(struct folio *folio);                   // folio ์™„์ „ ํ•ด์ œ
// ... swap, direct_IO, migrate ๋“ฑ
};

ํ•ต์‹ฌ ํ•จ์ˆ˜

1. `__filemap_get_folio_mpol` โ€” ํŽ˜์ด์ง€ ์บ์‹œ ์กฐํšŒ/์ƒ์„ฑ

// mm/filemap.c:1940-2057
struct folio *__filemap_get_folio_mpol(struct address_space *mapping,
pgoff_t index, fgf_t fgp_flags, gfp_t gfp, struct mempolicy *policy)

์—ญํ• : ์ง€์ •๋œ mapping๊ณผ index์— ํ•ด๋‹นํ•˜๋Š” folio๋ฅผ ํŽ˜์ด์ง€ ์บ์‹œ์—์„œ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค. ์—†์œผ๋ฉด FGP_CREAT ํ”Œ๋ž˜๊ทธ์— ๋”ฐ๋ผ ์ƒˆ folio๋ฅผ ํ• ๋‹นํ•˜์—ฌ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋ถ„๊ธฐ ๋กœ์ง:

1. filemap_get_entry(mapping, index)๋กœ XArray์—์„œ folio/shadow entry ๊ฒ€์ƒ‰

2. ์ฐพ์€ folio๊ฐ€ ์žˆ๊ณ  FGP_LOCK์ด๋ฉด:

- FGP_NOWAIT: folio_trylock() ์‹คํŒจ ์‹œ -EAGAIN ๋ฐ˜ํ™˜

- ์ผ๋ฐ˜: folio_lock() (๋ธ”๋กœํ‚น)

- truncate ํ™•์ธ: folio->mapping != mapping์ด๋ฉด unlock ํ›„ ์žฌ์‹œ๋„

3. FGP_ACCESSED์ด๋ฉด folio_mark_accessed() ํ˜ธ์ถœ

4. ์ฐพ์ง€ ๋ชปํ•˜๊ณ  FGP_CREAT์ด๋ฉด:

- order ๊ฒฐ์ •: mapping_min_folio_order(mapping) ~ FGF_GET_ORDER(fgp_flags)

- filemap_alloc_folio()๋กœ ํ• ๋‹น

- filemap_add_folio()๋กœ XArray์— ์ถ”๊ฐ€

- ์‹คํŒจ ์‹œ order๋ฅผ ์ค„์—ฌ์„œ ์žฌ์‹œ๋„ (์ตœ์†Œ min_order๊นŒ์ง€)

2. `__filemap_add_folio` โ€” XArray์— folio ์ถ”๊ฐ€

// mm/filemap.c:848-946
noinline int __filemap_add_folio(struct address_space *mapping,
struct folio *folio, pgoff_t index, gfp_t gfp, void **shadowp)

์—ญํ• : ํ• ๋‹น๋œ folio๋ฅผ mapping->i_pages XArray์— ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด shadow entry์™€ ์ถฉ๋Œ ์‹œ ๋ถ„๊ธฐํ•ฉ๋‹ˆ๋‹ค.

๋ถ„๊ธฐ ๋กœ์ง:

1. XA_STATE_ORDER๋กœ XArray ์ƒํƒœ ์ดˆ๊ธฐํ™”

2. xas_lock_irq() ํ›„ ์ถฉ๋Œ ํ•ญ๋ชฉ ๋ฐ˜๋ณต (xas_for_each_conflict)

3. ์ถฉ๋Œ ํ•ญ๋ชฉ์ด ์ผ๋ฐ˜ folio(!xa_is_value)์ด๋ฉด -EEXIST ๋ฐ˜ํ™˜ (์ด๋ฏธ ์กด์žฌ)

4. shadow entry์ด๋ฉด ๊ธฐ์กด entry์˜ order ํ™•์ธ

5. ๊ธฐ์กด entry๊ฐ€ ๋” ํฌ๋ฉด(order > forder): xas_try_split()๋กœ large entry๋ฅผ smaller pieces๋กœ ๋ถ„ํ• 

6. xas_store(&xas, folio)๋กœ ์ตœ์ข… ์‚ฝ์ž…

7. ํ†ต๊ณ„ ์—…๋ฐ์ดํŠธ: mapping->nrpages += nr, NR_FILE_PAGES, NR_FILE_THPS

3. `filemap_add_folio` โ€” memcgroup ํฌํ•จ folio ์ถ”๊ฐ€

// mm/filemap.c:949-990
int filemap_add_folio(struct address_space *mapping, struct folio *folio,
pgoff_t index, gfp_t gfp)

์—ญํ• : memcgroup ์ฒดํฌ ํ›„ __filemap_add_folio()๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์„ฑ๊ณต ์‹œ LRU์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

ํ๋ฆ„:

1. mem_cgroup_charge(folio, ...) โ€” memcgroup ๊ณผ๊ธˆ

2. __filemap_set_locked(folio) โ€” folio ์ž ๊ธˆ

3. __filemap_add_folio() โ€” ์‹ค์ œ XArray ์‚ฝ์ž…

4. ์‹คํŒจ ์‹œ memcgroup uncharge

5. ์„ฑ๊ณต ์‹œ workingset_refault()๋กœ recently-evicted folio ํ™œ์„ฑํ™”

6. folio_add_lru(folio)๋กœ LRU ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€

4. `filemap_read` โ€” ํŒŒ์ผ ์ฝ๊ธฐ

// mm/filemap.c:2768-2880
ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter, ssize_t already_read)

์—ญํ• : ํŽ˜์ด์ง€ ์บ์‹œ์—์„œ ํŒŒ์ผ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์œผ๋กœ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค.

ํ๋ฆ„:

1. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ (์œ„์น˜, ํฌ๊ธฐ)

2. do-while ๋ฃจํ”„์—์„œ ๋ฐ˜๋ณต:

- filemap_get_pages() โ€” ์ฝ์„ folio ๋ฐฐ์น˜ ๊ฐ€์ ธ์˜ค๊ธฐ (readahead ํฌํ•จ)

- folio_mark_accessed() โ€” ์ ‘๊ทผ ํ‘œ์‹œ (LRU ํ™œ์„ฑํ™”)

- copy_folio_to_iter() โ€” ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ

- folio_put() โ€” ์ฐธ์กฐ ํ•ด์ œ

3. file_accessed(filp) โ€” atime ์—…๋ฐ์ดํŠธ

5. `filemap_fault` โ€” mmap ํŽ˜์ด์ง€ ํดํŠธ ์ฒ˜๋ฆฌ

// mm/filemap.c:3512-3670
vm_fault_t filemap_fault(struct vm_fault *vmf)

์—ญํ• : mmap๋œ ํŒŒ์ผ ์˜์—ญ์— ๋Œ€ํ•œ ํŽ˜์ด์ง€ ํดํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ์บ์‹œ์—์„œ folio๋ฅผ ์ฐพ๊ณ , ์—†์œผ๋ฉด I/O๋กœ ์ฝ์–ด์˜ต๋‹ˆ๋‹ค.

ํ๋ฆ„:

1. ํŽ˜์ด์ง€ ์บ์‹œ์— folio ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ (filemap_get_folio)

2. ์กด์žฌํ•˜๋ฉด async readahead ์‹œ๋„ (do_async_mmap_readahead)

3. ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด:

- PGMAJFAULT ์นด์šดํŠธ ์ฆ๊ฐ€ (major fault)

- sync readahead ํŠธ๋ฆฌ๊ฑฐ (do_sync_mmap_readahead)

- __filemap_get_folio(FGP_CREAT|FGP_FOR_MMAP)๋กœ ์ƒˆ folio ์ƒ์„ฑ

4. lock_folio_maybe_drop_mmap() โ€” folio ์ž ๊ธˆ

5. folio_test_uptodate() ํ™•์ธ:

- Uptodate์ด๋ฉด vmf->page ์„ค์ • ํ›„ ๋ฐ˜ํ™˜

- ์•„๋‹ˆ๋ฉด filemap_read_folio()๋กœ ์ง์ ‘ ์ฝ๊ธฐ

6. VM_FAULT_MAJOR ๋˜๋Š” VM_FAULT_LOCKED ํ”Œ๋ž˜๊ทธ ๋ฐ˜ํ™˜

6. `filemap_write_and_wait_range` โ€” ๋”ํ‹ฐ ํŽ˜์ด์ง€ writeback

// mm/filemap.c:675-698
int filemap_write_and_wait_range(struct address_space *mapping,
loff_t lstart, loff_t lend)

์—ญํ• : ์ง€์ •๋œ ๋ฒ”์œ„์˜ ๋”ํ‹ฐ ํŽ˜์ด์ง€๋ฅผ ๋””์Šคํฌ์— ๊ธฐ๋กํ•˜๊ณ  ์™„๋ฃŒ๋ฅผ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค.

ํ๋ฆ„:

1. mapping_needs_writeback(mapping) ํ™•์ธ

2. ๋”ํ‹ฐ ํŽ˜์ด์ง€๊ฐ€ ์žˆ์œผ๋ฉด filemap_fdatawrite_range()๋กœ writeback ์‹œ์ž‘

3. -EIO๊ฐ€ ์•„๋‹ˆ๋ฉด __filemap_fdatawait_range()๋กœ ์™„๋ฃŒ ๋Œ€๊ธฐ

4. filemap_check_errors()๋กœ ์—๋Ÿฌ ํ™•์ธ

7. `filemap_remove_folio` โ€” ํŽ˜์ด์ง€ ์บ์‹œ์—์„œ folio ์ œ๊ฑฐ

// mm/filemap.c:250-264
void filemap_remove_folio(struct folio *folio)

์—ญํ• : ์ž ๊ธˆ์ด ๊ฑธ๋ฆฐ folio๋ฅผ ํŽ˜์ด์ง€ ์บ์‹œ์—์„œ ์ œ๊ฑฐํ•˜๊ณ  ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

ํ๋ฆ„:

1. BUG_ON(!folio_test_locked(folio)) โ€” ์ž ๊ธˆ ํ™•์ธ

2. spin_lock(&mapping->host->i_lock) โ€” inode ์ž ๊ธˆ

3. xa_lock_irq(&mapping->i_pages) โ€” XArray ์ž ๊ธˆ

4. __filemap_remove_folio(folio, NULL) โ€” XArray์—์„œ ์ œ๊ฑฐ

5. mapping_shrinkable(mapping) โ†’ inode_lru_list_add() โ€” inode LRU ์ถ”๊ฐ€

6. filemap_free_folio(mapping, folio) โ€” a_ops->free_folio + folio_put_refs

filemap ์ž ๊ธˆ ์ˆœ์„œ (Lock Ordering)

// mm/filemap.c:81-127 โ€” ์ปค๋„์ด ์ง€ํ‚ค๋Š” ์ž ๊ธˆ ์ˆœ์„œ
// i_mmap_rwsem > page_table_lock > i_pages lock (์ผ๋ฐ˜ ๊ฒฝ๋กœ)
// mmap_lock > invalidate_lock > lock_page (ํดํŠธ ๊ฒฝ๋กœ)
// i_rwsem > mmap_lock (์“ฐ๊ธฐ ๊ฒฝ๋กœ)
๊ฒฝ๋กœ์ž ๊ธˆ ์ˆœ์„œ
truncate`i_mmap_rwsem` โ†’ `private_lock` โ†’ `swap_lock` โ†’ `i_pages lock`
mmap fault`mmap_lock` โ†’ `invalidate_lock` โ†’ `lock_page(folio)`
์ผ๋ฐ˜ ์“ฐ๊ธฐ`i_rwsem` โ†’ `mmap_lock` โ†’ `page_table_lock` โ†’ `i_pages lock`
ํŽ˜์ด์ง€ ํดํŠธ`mmap_lock` โ†’ `page_table_lock` โ†’ `i_pages lock`

folio ์ž ๊ธˆ ๊ณต์ •์„ฑ (Page Lock Unfairness)

// mm/filemap.c:1076 โ€” sysctl_page_lock_unfairness ๊ธฐ๋ณธ๊ฐ’
static int sysctl_page_lock_unfairness = 5;

folio lock ๋Œ€๊ธฐ ์‹œ unfairness ์นด์šดํ„ฐ๊ฐ€ 0 ์ดํ•˜๊ฐ€ ๋˜๋ฉด WQ_FLAG_CUSTOM ํ”Œ๋ž˜๊ทธ๊ฐ€ ์„ค์ •๋˜์–ด ๊ณต์ •ํ•œ ์ž ๊ธˆ ์–‘๋„(fair lock handoff)๊ฐ€ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด thundering herd ๋ฌธ์ œ๋ฅผ ์™„ํ™”ํ•ฉ๋‹ˆ๋‹ค.

// mm/filemap.c:1267-1273
repeat:
wait->flags = 0;
if (behavior == EXCLUSIVE) {
wait->flags = WQ_FLAG_EXCLUSIVE;
if (--unfairness < 0)
wait->flags |= WQ_FLAG_CUSTOM;  // ๊ณต์ •ํ•œ ์–‘๋„ ํ™œ์„ฑํ™”
}
  • EXCLUSIVE ๋Œ€๊ธฐ: ํ•˜๋‚˜์˜ ๋Œ€๊ธฐ์ž๋งŒ ๊นจ์›€ (๊ธฐ๋ณธ)
  • WQ_FLAG_CUSTOM: ์ž ๊ธˆ ์†Œ์œ ์ž๊ฐ€ ์ง์ ‘ ์–‘๋„ (๊ณต์ •์„ฑ ๋ณด์žฅ)
  • sysctl vm.page_lock_unfairness๋กœ ๋Ÿฐํƒ€์ž„ ์กฐ์ • ๊ฐ€๋Šฅ
  • ํ˜ธ์ถœ ํ๋ฆ„

    ํŒŒ์ผ ์ฝ๊ธฐ ํ๋ฆ„

    generic_file_read_iter()
    โ””โ”€ filemap_read()
    โ”œโ”€ filemap_get_pages()
    โ”‚    โ”œโ”€ filemap_get_read_batch()     โ† XArray์—์„œ folio ๋ฐฐ์น˜ ์กฐํšŒ
    โ”‚    โ”œโ”€ page_cache_sync_ra()          โ† ์—†์œผ๋ฉด sync readahead
    โ”‚    โ”œโ”€ filemap_create_folio()        โ† ๊ทธ๋ž˜๋„ ์—†์œผ๋ฉด ์ƒˆ folio ์ƒ์„ฑ
    โ”‚    โ””โ”€ filemap_readahead()            โ† readahead ํŠธ๋ฆฌ๊ฑฐ
    โ”œโ”€ folio_mark_accessed()              โ† LRU ํ™œ์„ฑํ™”
    โ””โ”€ copy_folio_to_iter()               โ† ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์œผ๋กœ ๋ณต์‚ฌ

    mmap ํดํŠธ ์ฒ˜๋ฆฌ ํ๋ฆ„

    do_read_fault() / do_fault()
    โ””โ”€ filemap_fault()
    โ”œโ”€ filemap_get_folio()                โ† ํŽ˜์ด์ง€ ์บ์‹œ ์กฐํšŒ
    โ”‚    โ”œโ”€ [hit] do_async_mmap_readahead()
    โ”‚    โ””โ”€ [miss] do_sync_mmap_readahead()
    โ”‚         โ””โ”€ __filemap_get_folio(FGP_CREAT)  โ† ์ƒˆ folio ์ƒ์„ฑ
    โ”œโ”€ lock_folio_maybe_drop_mmap()       โ† folio ์ž ๊ธˆ
    โ”œโ”€ folio_test_uptodate() ๊ฒ€์‚ฌ
    โ”‚    โ”œโ”€ [uptodate] โ†’ vmf->page ์„ค์ •
    โ”‚    โ””โ”€ [not uptodate] filemap_read_folio() โ† ์ง์ ‘ I/O
    โ””โ”€ VM_FAULT_MAJOR | VM_FAULT_LOCKED ๋ฐ˜ํ™˜

    ํŽ˜์ด์ง€ ์บ์‹œ ์ถ”๊ฐ€ ํ๋ฆ„

    __filemap_get_folio_mpol()
    โ””โ”€ filemap_add_folio()
    โ”œโ”€ mem_cgroup_charge()                โ† memcgroup ๊ณผ๊ธˆ
    โ”œโ”€ __filemap_set_locked()             โ† folio ์ž ๊ธˆ
    โ”œโ”€ __filemap_add_folio()              โ† XArray ์‚ฝ์ž…
    โ”‚    โ”œโ”€ xas_for_each_conflict()       โ† ์ถฉ๋Œ ๊ฒ€์‚ฌ
    โ”‚    โ”‚    โ””โ”€ xas_try_split()          โ† large entry ๋ถ„ํ• 
    โ”‚    โ””โ”€ xas_store(folio)              โ† ์ตœ์ข… ์‚ฝ์ž…
    โ”œโ”€ workingset_refault()               โ† recently-evicted ํ™œ์„ฑํ™”
    โ””โ”€ folio_add_lru()                    โ† LRU์— ์ถ”๊ฐ€

    Writeback ํ๋ฆ„

    balance_dirty_pages_ratelimited()
    โ””โ”€ balance_dirty_pages()
    โ”œโ”€ balance_domain_limits()            โ† global/memcg ๋„๋ฉ”์ธ ์ œํ•œ ๊ณ„์‚ฐ
    โ”œโ”€ wb_start_background_writeback()    โ† bg_thresh ์ดˆ๊ณผ ์‹œ writeback ์‹œ์ž‘
    โ”œโ”€ balance_wb_limits()                โ† pos_ratio ๊ณ„์‚ฐ
    โ””โ”€ throttle ๋กœ์ง                       โ† task_ratelimit์— ๋”ฐ๋ผ ์“ฐ๊ธฐ throttling

    ์กฐ๊ฑด๋ณ„ ๋น„๊ต

    folio vs ๊ธฐ์กด struct page

    ํ•ญ๋ชฉstruct pagestruct folio
    ํฌ๊ธฐ64 bytes (๊ธฐ๋ณธ)64 bytes ร— N (compound)
    ๊ด€๋ฆฌ ๋‹จ์œ„๊ฐœ๋ณ„ ํŽ˜์ด์ง€ํ•˜๋‚˜ ์ด์ƒ์˜ ์—ฐ์† ํŽ˜์ด์ง€
    page cache ํ‚คpage indexfolio index
    lock ๋ฒ”์œ„๊ฐœ๋ณ„ ํŽ˜์ด์ง€folio ์ „์ฒด (head page lock)
    dirty ์ถ”์ ๊ฐœ๋ณ„ page flagfolio flag (์ „์ฒด dirty ์ถ”์ )
    compatibility๋ชจ๋“  ์ปค๋„5.16+ (๊ธฐ์กด API ๋ž˜ํผ ์ œ๊ณต)
    large folio์ œํ•œ์  (compound_page)๊ธฐ๋ณธ ์ง€์›
    rmap ์ถ”์ anon_vma ์ฒด์ธ ์ˆœํšŒ_mm_id ๊ธฐ๋ฐ˜ O(1) ๋งคํ•‘ ์นด์šดํŠธ (Linux 7.0)
    memcg ๊ณผ๊ธˆ๊ฐœ๋ณ„ pagefolio ๋‹จ์œ„ (large folio๋„ 1ํšŒ ๊ณผ๊ธˆ)

    FOLIO_MAPPING_ANON ํ”Œ๋ž˜๊ทธ (Linux 7.0):

    // folio->mapping์˜ LSB๊ฐ€ 1์ด๋ฉด anonymous page
    // folio->mapping์—์„œ ์‹ค์ œ address_space๋Š” ~1๋กœ ๋งˆ์Šคํ‚นํ•˜์—ฌ ์–ป์Œ
    // anon_vma๋Š” address_space ๋Œ€์‹  ์‚ฌ์šฉ

    ํŒŒ์ผ ์ฝ๊ธฐ ๊ฒฝ๋กœ ๋น„๊ต

    ์‹œ๋‚˜๋ฆฌ์˜ค๊ฒฝ๋กœํŠน์ง•
    ์ผ๋ฐ˜ read`filemap_read()` โ†’ `filemap_get_pages()`ํŽ˜์ด์ง€ ์บ์‹œ ํžˆํŠธ ์‹œ I/O ์—†์Œ
    mmap fault (hit)`filemap_fault()` โ†’ `folio_test_uptodate()`async readahead ๊ฐ€๋Šฅ
    mmap fault (miss)`filemap_fault()` โ†’ `do_sync_mmap_readahead()`major fault, sync I/O
    direct I/O`generic_file_read_iter()` โ†’ `mapping->a_ops->direct_IO()`ํŽ˜์ด์ง€ ์บ์‹œ ์šฐํšŒ

    writeback ํŠธ๋ฆฌ๊ฑฐ ์กฐ๊ฑด

    ์กฐ๊ฑด๋™์ž‘ํŒŒ๋ผ๋ฏธํ„ฐ
    `nr_dirty > bg_thresh`๋ฐฑ๊ทธ๋ผ์šด๋“œ writeback ์‹œ์ž‘`vm.dirty_background_ratio` (๊ธฐ๋ณธ 10%)
    `nr_dirty > dirty_thresh`์“ฐ๊ธฐ ํ”„๋กœ์„ธ์Šค throttling`vm.dirty_ratio` (๊ธฐ๋ณธ 20%)
    `dirty_expire_interval` ์ดˆ๊ณผ๋งŒ๋ฃŒ๋œ ๋”ํ‹ฐ ํŽ˜์ด์ง€ ์ฆ‰์‹œ writeback`vm.dirty_expire_interval` (๊ธฐ๋ณธ 30s)
    `dirty_writeback_interval`kupdate ์Šคํƒ€์ผ ์ฃผ๊ธฐ์  writeback`vm.dirty_writeback_interval` (๊ธฐ๋ณธ 5s)
    `ratelimit_pages` ์ดˆ๊ณผper-CPU throttling ์ฒดํฌ`vm.dirty_writeback_interval` (๊ธฐ๋ณธ 32 pages)
    // mm/page-writeback.c:68,75,92,103,110
    static long ratelimit_pages = 32;           // per-CPU throttling ์ž„๊ณ„๊ฐ’
    static int dirty_background_ratio = 10;     // ๋ฐฑ๊ทธ๋ผ์šด๋“œ writeback ์‹œ์ž‘ ๋น„์œจ
    static int vm_dirty_ratio = 20;             // ์“ฐ๊ธฐ throttling ์‹œ์ž‘ ๋น„์œจ
    unsigned int dirty_writeback_interval = 5 * 100;  // centiseconds (5์ดˆ)
    unsigned int dirty_expire_interval = 30 * 100;    // centiseconds (30์ดˆ)

    folio lock ์ƒํƒœ

    ํ”Œ๋ž˜๊ทธ์˜๋ฏธ๊ด€๋ จ ํ•จ์ˆ˜
    `PG_locked`folio lock ํš๋“๋จ`folio_lock()`, `folio_trylock()`
    `PG_uptodate`๋ฐ์ดํ„ฐ๊ฐ€ ๋””์Šคํฌ์™€ ์ผ์น˜`folio_end_read()`, `folio_mark_uptodate()`
    `PG_dirty`์ˆ˜์ •๋œ ๋ฐ์ดํ„ฐ ์กด์žฌ`folio_mark_dirty()`, `folio_clear_dirty_for_io()`
    `PG_writeback`writeback ์ง„ํ–‰ ์ค‘`folio_start_writeback()`, `folio_end_writeback()`
    `PG_lru`LRU ๋ฆฌ์ŠคํŠธ์— ์žˆ์Œ`folio_add_lru()`, `folio_del_lru()`
    `PG_active`ํ™œ์„ฑ LRU์— ์žˆ์Œ`folio_set_active()`, `folio_clear_active()`

    ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„

    Folio / Page Cache ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„

    ํ˜ธ์ถœ ํ๋ฆ„ ๋‹ค์ด์–ด๊ทธ๋žจ

    Filemap Read / Fault ํ˜ธ์ถœ ํ๋ฆ„

    ๊ด€๋ จ ๋ฌธ์„œ

  • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š” โ€” ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์กฐ๊ฐ๋„
  • Buddy Allocator โ€” ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€ ํ• ๋‹น
  • SLUB ํ• ๋‹น์ž โ€” slab ๊ธฐ๋ฐ˜ ์ž‘์€ ๊ฐ์ฒด ํ• ๋‹น
  • VMA / mmap โ€” ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ ๊ด€๋ฆฌ
  • ํŽ˜์ด์ง€ ํšŒ์ˆ˜ โ€” LRU ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€ ํšŒ์ˆ˜
  • vmalloc โ€” ๊ฐ€์ƒ ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น
  • Swap / zswap โ€” ์Šค์™‘ ๋ฐ ์••์ถ• ์บ์‹œ
  • tmpfs / shmem โ€” ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ํŒŒ์ผ ์‹œ์Šคํ…œ
  • Workingset โ€” Workingset ์ถ”์  (shadow entry)
  • Readahead โ€” ํŽ˜์ด์ง€ ์บ์‹œ readahead
  • minzkn.com ๋น„๊ต

    minzkn.com ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ฐœ์š” ํŽ˜์ด์ง€์—์„œ struct page, folio ๊ด€๋ จ ๋‚ด์šฉ์„ ํ™•์ธํ•œ ๊ฒฐ๊ณผ:

    minzkn ํ•ต์‹ฌ ๋‚ด์šฉ:

  • struct page์˜ ๊ธฐ๋ณธ ํ•„๋“œ ์„ค๋ช… (flags, lru, mapping, index, private, _refcount, _mapcount)
  • ์ฃผ์š” ํŽ˜์ด์ง€ ํ”Œ๋ž˜๊ทธ (PG_locked, PG_referenced, PG_uptodate, PG_dirty, PG_lru, PG_active, PG_slab, PG_compound)
  • folio ์ปจ์…‰: "์ปค๋„ 5.16+์—์„œ compound page๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ๋„์ž…๋œ ์ถ”์ƒํ™”"
  • ์ต๋ช… ํŽ˜์ด์ง€ vs ํŒŒ์ผ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€ ๊ตฌ๋ถ„
  • ์šฐ๋ฆฌ ๋ฌธ์„œ์—์„œ ๋ณด๊ฐ•๋œ ๋‚ด์šฉ:

  • minzkn์˜ struct page ์„ค๋ช…์„ folio ๊ด€์ ์—์„œ ํ™•์žฅํ•˜์—ฌ Linux 7.0์˜ _mm_id, _deferred_list, _hugetlb_* ํ•„๋“œ๊นŒ์ง€ ํฌํ•จ
  • minzkn์˜ ํ”Œ๋ž˜๊ทธ ์„ค๋ช…์„ folio_mark_accessed(), folio_clear_dirty_for_io() ๊ฐ™์€ folio API์™€ ์—ฐ๊ฒฐ
  • minzkn์˜ "folio = head page ๋Œ€ํ‘œ" ์„ค๋ช…์„ FOLIO_MATCH ์ •์  ๊ฒ€์ฆ ์ฝ”๋“œ๋กœ ๊ฒ€์ฆ
  • filemap ์ž ๊ธˆ ์ˆœ์„œ, folio lock ๊ณต์ •์„ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ minzkn์—์„œ ๋‹ค๋ฃจ์ง€ ์•Š๋Š” ์‹ฌํ™” ๋‚ด์šฉ