๏ปฟ# List LRU (List-based Least Recently Used)
Linux 7.0 ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋ถ์ ์๋ฆฌ์ฆ
๊ฐ์ (Overview)
List LRU๋ ๋ฆฌ๋
์ค ์ปค๋์์ ๋ฒ์ฉ LRU(Least Recently Used) ์ธํ๋ผ๋ฅผ ์ ๊ณตํ๋ ํ์ ์์คํ
์
๋๋ค. dentry ์บ์, inode ์บ์, shmem ํ์ด์ง ๋ฑ ๋ค์ํ ์ปค๋ ์บ์ ํญ๋ชฉ๋ค์ LRU ์์๋ก ๊ด๋ฆฌํ๊ณ , ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์ ํจ๊ณผ์ ์ผ๋ก ํ์ํ ์ ์๋๋ก ํฉ๋๋ค. List LRU๋ struct list_head ๊ธฐ๋ฐ์ ๋จ์ผ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํ๋๋ฉฐ, NUMA ๋
ธ๋๋ณ, ๋ฉ๋ชจ๋ฆฌ cgroup๋ณ๋ก ๋
๋ฆฝ์ ์ธ ๋ฆฌ์คํธ๋ฅผ ์ ์งํฉ๋๋ค.
์ด ์ธํ๋ผ์ ํต์ฌ์ shrinker์์ ํตํฉ์
๋๋ค. list_lru_walk_one()๊ณผ ๊ฐ์ ํจ์๋ฅผ ํตํด ์ฝ๋ฐฑ ๊ธฐ๋ฐ์ผ๋ก ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ฉด์ ํ์ ๊ฐ๋ฅํ ํญ๋ชฉ์ ๊ฒฉ๋ฆฌ(isolate)ํ๊ฑฐ๋ ์ ๊ฑฐํฉ๋๋ค. CONFIG_MEMCG๊ฐ ํ์ฑํ๋ ์์คํ
์์๋ ๋ฉ๋ชจ๋ฆฌ cgroup๋ณ๋ก ๋ณ๋์ LRU ๋ฆฌ์คํธ๋ฅผ ํ ๋นํ์ฌ ์ปจํ
์ด๋ ๊ฐ ๋ฉ๋ชจ๋ฆฌ ๊ฒฉ๋ฆฌ๋ฅผ ๋ณด์ฅํฉ๋๋ค.
page reclaim์์ ๋งํ๋ active/inactive anon/file LRU์๋ ์ญํ ์ด ๋ค๋ฆ
๋๋ค. List LRU๋ ํ์ด์ง ์์ฒด๋ฅผ ๊ด๋ฆฌํ์ง ์๊ณ , dentry๋ inode์ฒ๋ผ shrinker๊ฐ ํ์ํ ์ปค๋ ์ค๋ธ์ ํธ๋ฅผ ๋ชจ์ ๋๋ ๋ณด์กฐ ๋ชฉ๋ก์
๋๋ค. ๊ทธ๋์ shrink_slab() ๊ฒฝ๋ก์์ ํธ์ถ๋์ด ์ฌ๋ฉ ๊ณ์ด ํ์์ ํจ๊ป ์์ง์ด๋ฉฐ, ํ์ด์ง ํ์ LRU์๋ ๋์๊ณผ ๋จ์๊ฐ ๊ตฌ๋ถ๋ฉ๋๋ค.
์ผ์ ๋น์
List LRU๋ ๋์๊ด์์ ์ค๋๋ ์ก์ง๋ฅผ ์ ๋ฆฌํ๋ ์์คํ ๊ณผ ๋น์ทํฉ๋๋ค. ๊ฐ ์ฃผ์ (๋ฉ๋ชจ๋ฆฌ cgroup)๋ณ๋ก ๋ณ๋์ ์๊ฐ(NUMA ๋ ธ๋)๊ฐ ์๊ณ , ๊ฐ ์๊ฐ์์๋ ์ฝํ ์ง ์ค๋๋ ์ก์ง๋ถํฐ ์ ๋ฆฌ ๋์์ผ๋ก ํ์ํฉ๋๋ค. ์ ๋ฆฌํ ๋๋ ๋จผ์ ์ก์ง๋ฅผ ๋นผ์(isolate) ๋ชฉ๋ก์์ ์ง์ฐ๊ณ , ํ์ํ๋ฉด ๋ค๋ฅธ ์๊ฐ๋ก ์ฎ๊น๋๋ค.
์์ค ํ์ผ
mm/list_lru.c โ LRU ํต์ฌ ๋ก์ง (618์ค)
include/linux/list_lru.h โ ๊ตฌ์กฐ์ฒด ์ ์, API ์ ์ธ (289์ค)
mm/slab.h โ ๋ด๋ถ ํฌํผ
mm/internal.h โ set_shrinker_bit() ๋ฑ
include/linux/memcontrol.h โ memcg ์ฐ๋
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# 1. list_lru ๊ด๋ จ ์ปค๋ ์ฌ๋ณผ ํ์ธ
cat /proc/kallsyms | grep -E "list_lru_add|list_lru_del|list_lru_walk" | head -10
# 2. CONFIG_MEMCG ์ปดํ์ผ ์ต์
ํ์ธ
grep CONFIG_MEMCG /boot/config-$(uname -r) 2>/dev/null || zcat /proc/config.gz 2>/dev/null | grep CONFIG_MEMCG
# 3. slab ์บ์ ํต๊ณ์์ dentry/inode ์บ์ ํ์ธ (list_lru ์ฌ์ฉ์ฒ)
cat /proc/slabinfo | grep -E "dentry|inode_cache|shmem_inode_cache"
# 4. ๋ฉ๋ชจ๋ฆฌ cgroup๋ณ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ํ์ธ
cat /sys/fs/cgroup/memory/memory.limit_in_bytes 2>/dev/null || cat /sys/fs/cgroup/memory.max 2>/dev/null
# 5. shrinker ๋ฑ๋ก ์ ๋ณด ํ์ธ
cat /sys/kernel/mm/leak_debug/objects 2>/dev/null || echo "leak_debug not available"
# 6. /proc/vmstat์์ ์บ์ ํ์ ๊ด๋ จ ์นด์ดํฐ
cat /proc/vmstat | grep -E "pgscan|pgsteal|nr_slab|nr_dentry|nr_inode"
# 7. list_lru ๊ด๋ จ ๋ชจ๋ ์ ๋ณด
modinfo list_lru 2>/dev/null || echo "Built-in module"
# 8. memcg slab ํต๊ณ
cat /sys/fs/cgroup/memory/memory.stat 2>/dev/null | grep -E "slab|dentry|inode" | head -10
# 9. ์ปค๋ ๋น๋ ์ต์
์์ list_lru ๊ด๋ จ ํ์ธ
grep -r "CONFIG_LIST_LRU" /boot/config-$(uname -r) 2>/dev/null
# 10. list_lru ์ฌ์ฉ ์ฝ๋ ์์น ์ถ์
grep -rn "list_lru_add\|list_lru_del\|list_lru_walk" /usr/src/linux-*/fs/ 2>/dev/null | head -10
# 11. ํ์ด์ง ํ์ ์๋ ฅ๊ณผ ์ฐ๊ณ ์งํ ํ์ธ
cat /proc/vmstat | grep -E "pgscan|pgsteal|allocstall|kswapd"
# 12. ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์๋ ฅ ํ์ธ
cat /proc/pressure/memory
# 13. ์ค์ ์ํ ํ์ธ
swapon --show
# 14. ์ค์ ์ ์ฑ
ํ์ธ
cat /proc/sys/vm/swappiness
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
1. `struct list_lru_one` โ ๊ฐ๋ณ LRU ๋ฆฌ์คํธ
๊ฐ memcg + NUMA node ์กฐํฉ์ ํ๋์ฉ ์กด์ฌํ๋ ๊ธฐ๋ณธ LRU ๋ฆฌ์คํธ์ ๋๋ค.
// include/linux/list_lru.h:31-37
struct list_lru_one {
struct list_head list; // ์ฐ๊ฒฐ ๋ฆฌ์คํธ ํค๋
// memcg reparenting ์ค ์์๊ฐ ๋ ์ ์์
long nr_items; // ํ์ฌ ๋ฆฌ์คํธ์ ์์ดํ
์
// ๋ชจ๋ ํ๋๋ฅผ ๋ณดํธํ๋ ์คํ๋ฝ
spinlock_t lock;
};
2. `struct list_lru_node` โ NUMA ๋ ธ๋๋ณ LRU
NUMA ์์คํ ์์ ๊ฐ ๋ ธ๋๋ง๋ค ํ๋์ฉ ์กด์ฌํ๋ฉฐ, ๋ฃจํธ cgroup์ฉ ๊ธ๋ก๋ฒ LRU์ ์นด์ดํฐ๋ฅผ ํฌํจํฉ๋๋ค.
// include/linux/list_lru.h:45-49
struct list_lru_node {
// ๋ฃจํธ cgroup์ฉ ๊ธ๋ก๋ฒ ๋ฆฌ์คํธ
struct list_lru_one lru;
atomic_long_t nr_items; // ์ ์ฒด ์์ดํ
์ (atomic)
} ____cacheline_aligned_in_smp;
3. `struct list_lru_memcg` โ memcg๋ณ LRU
๋ฉ๋ชจ๋ฆฌ cgroup์ด ํ ๋น๋ ๋๋ง๋ค ๋์ ์ผ๋ก ํ ๋น๋๋ per-memcg LRU์ ๋๋ค.
// include/linux/list_lru.h:39-43
struct list_lru_memcg {
struct rcu_head rcu; // RCU ํด์ ์ฉ
// ๋
ธ๋๋ณ per-cgroup ๋ฆฌ์คํธ (์ ์ฐํ ๋ฐฐ์ด)
struct list_lru_one node[];
};
4. `struct list_lru` โ ์ต์์ LRU ๊ตฌ์กฐ์ฒด
List LRU์ ์ต์์ ๊ตฌ์กฐ์ฒด๋ก, ๋ชจ๋ NUMA ๋ ธ๋์ memcg ์ ๋ณด๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
// include/linux/list_lru.h:51-62
struct list_lru {
struct list_lru_node *node; // NUMA ๋
ธ๋๋ณ LRU ๋ฐฐ์ด
#ifdef CONFIG_MEMCG
struct list_head list; // memcg_list_lrus ์ฐ๊ฒฐ์ฉ
int shrinker_id; // ์ฐ๊ฒฐ๋ shrinker ID
bool memcg_aware; // memcg ์ธ์ ์ฌ๋ถ
struct xarray xa; // memcg ID โ list_lru_memcg ๋งคํ
#endif
#ifdef CONFIG_LOCKDEP
struct lock_class_key *key; // lockdep ํด๋์ค ํค
#endif
};
5. `enum lru_status` โ walk ์ฝ๋ฐฑ ๋ฐํ ๊ฐ
list_lru_walk_one()์ ์ฝ๋ฐฑ ํจ์๊ฐ ๋ฐํํ๋ ์ํ ๊ฐ์
๋๋ค.
// include/linux/list_lru.h:19-29
enum lru_status {
LRU_REMOVED, // ์์ดํ
์ด ๋ฆฌ์คํธ์์ ์ ๊ฑฐ๋จ
LRU_REMOVED_RETRY, // ์ ๊ฑฐ๋จ, ์ ๊ธ ํด์ ํ ๋ค์ ์๋
LRU_ROTATE, // ์์ดํ
์ด ์ฐธ์กฐ๋จ, ๋ค์ ์ํ
LRU_SKIP, // ์์ดํ
์ ๊ธ ๋ถ๊ฐ, ๊ฑด๋๋
LRU_RETRY, // ์์ดํ
ํด์ ๋ถ๊ฐ, ๋ค์ ์๋
LRU_STOP, // ์ํ ์ค์ง
};
ํต์ฌ ํจ์
1. `list_lru_add()` / `list_lru_add_obj()`
LRU ๋ฆฌ์คํธ์ ์์ดํ
์ ์ถ๊ฐํฉ๋๋ค. list_lru_add()๋ ๋ช
์์ ์ผ๋ก nid์ memcg๋ฅผ ์ง์ ํ๊ณ , list_lru_add_obj()๋ ์์ดํ
์ ๋ฌผ๋ฆฌ ์ฃผ์์์ ์๋์ผ๋ก ๊ฒฐ์ ํฉ๋๋ค.
// mm/list_lru.c:161-181
bool list_lru_add(struct list_lru *lru, struct list_head *item, int nid,
struct mem_cgroup *memcg)
{
struct list_lru_node *nlru = &lru->node[nid];
struct list_lru_one *l;
l = lock_list_lru_of_memcg(lru, nid, memcg, false, false);
if (!l)
return false;
if (list_empty(item)) {
list_add_tail(item, &l->list);
// ์ฒซ ๋ฒ์งธ ์์ ์ถ๊ฐ ์ shrinker ๋นํธ ์ค์
if (!l->nr_items++)
set_shrinker_bit(memcg, nid, lru_shrinker_id(lru));
unlock_list_lru(l, false);
atomic_long_inc(&nlru->nr_items);
return true;
}
unlock_list_lru(l, false);
return false;
}
๋ถ๊ธฐ ๋ก์ง:
lock_list_lru_of_memcg()๋ก memcg๋ณ ๋ฆฌ์คํธ ํ๋ ์คํจ ์ false ๋ฐํlist_empty() ์คํจ) ์ถ๊ฐํ์ง ์์set_shrinker_bit()๋ก shrinker์ ์๋ฆผ2. `list_lru_del()` / `list_lru_del_obj()`
LRU ๋ฆฌ์คํธ์์ ์์ดํ ์ ์ญ์ ํฉ๋๋ค.
// mm/list_lru.c:201-218
bool list_lru_del(struct list_lru *lru, struct list_head *item, int nid,
struct mem_cgroup *memcg)
{
struct list_lru_node *nlru = &lru->node[nid];
struct list_lru_one *l;
l = lock_list_lru_of_memcg(lru, nid, memcg, false, false);
if (!l)
return false;
if (!list_empty(item)) {
list_del_init(item);
l->nr_items--;
unlock_list_lru(l, false);
atomic_long_dec(&nlru->nr_items);
return true;
}
unlock_list_lru(l, false);
return false;
}
๋ถ๊ธฐ ๋ก์ง:
list_empty()๊ฐ true์ธ ๊ฒฝ์ฐ)์ ์ญ์ ํ์ง ์์list_del_init()์ผ๋ก ์ ๊ฑฐ ํ ์ด๊ธฐํ3. `__list_lru_walk_one()` โ ํต์ฌ ์ํ ๋ก์ง
LRU ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ฉด์ ์ฝ๋ฐฑ ํจ์๋ฅผ ํธ์ถํ์ฌ ํญ๋ชฉ์ ๊ฒฉ๋ฆฌํ๊ฑฐ๋ ์ ๊ฑฐํฉ๋๋ค.
// mm/list_lru.c:279-334
static unsigned long
__list_lru_walk_one(struct list_lru *lru, int nid, struct mem_cgroup *memcg,
list_lru_walk_cb isolate, void *cb_arg,
unsigned long *nr_to_walk, bool irq_off)
{
struct list_lru_node *nlru = &lru->node[nid];
struct list_lru_one *l = NULL;
struct list_head *item, *n;
unsigned long isolated = 0;
restart:
l = lock_list_lru_of_memcg(lru, nid, memcg, irq_off, true);
if (!l)
return isolated;
list_for_each_safe(item, n, &l->list) {
enum lru_status ret;
if (!*nr_to_walk)
break;
--*nr_to_walk;
ret = isolate(item, l, cb_arg);
switch (ret) {
case LRU_RETRY:
goto restart;
case LRU_REMOVED_RETRY:
fallthrough;
case LRU_REMOVED:
isolated++;
atomic_long_dec(&nlru->nr_items);
if (ret == LRU_REMOVED_RETRY)
goto restart;
break;
case LRU_ROTATE:
list_move_tail(item, &l->list);
break;
case LRU_SKIP:
break;
case LRU_STOP:
goto out;
default:
BUG();
}
}
unlock_list_lru(l, irq_off);
out:
return isolated;
}
๋ถ๊ธฐ ๋ก์ง:
LRU_RETRY: ์ ๊ธ ํด์ ํ ์ฒ์๋ถํฐ ๋ค์ ์ํLRU_REMOVED_RETRY: ์์ดํ
์ ๊ฑฐ ํ ๋ค์ ์ํLRU_REMOVED: ์์ดํ
์ ๊ฑฐ, ๋ค์ ํญ๋ชฉ์ผ๋ก ์ด๋LRU_ROTATE: ์์ดํ
์ ๋ฆฌ์คํธ ๋์ผ๋ก ์ด๋LRU_SKIP: ๊ฑด๋๋LRU_STOP: ์ํ ์ค์ง4. `list_lru_walk_node()` โ ๋ ธ๋ ์ ์ฒด ์ํ
ํน์ NUMA ๋ ธ๋์ ๋ชจ๋ memcg์ ๋ํด LRU ์ํ๋ฅผ ์ํํฉ๋๋ค.
// mm/list_lru.c:355-391
unsigned long list_lru_walk_node(struct list_lru *lru, int nid,
list_lru_walk_cb isolate, void *cb_arg,
unsigned long *nr_to_walk)
{
long isolated = 0;
isolated += list_lru_walk_one(lru, nid, NULL, isolate, cb_arg,
nr_to_walk);
#ifdef CONFIG_MEMCG
if (*nr_to_walk > 0 && list_lru_memcg_aware(lru)) {
struct list_lru_memcg *mlru;
struct mem_cgroup *memcg;
unsigned long index;
xa_for_each(&lru->xa, index, mlru) {
rcu_read_lock();
memcg = mem_cgroup_from_private_id(index);
if (!mem_cgroup_tryget(memcg)) {
rcu_read_unlock();
continue;
}
rcu_read_unlock();
isolated += __list_lru_walk_one(lru, nid, memcg,
isolate, cb_arg,
nr_to_walk, false);
mem_cgroup_put(memcg);
if (*nr_to_walk <= 0)
break;
}
}
#endif
return isolated;
}
๋ถ๊ธฐ ๋ก์ง:
5. `__list_lru_init()` / `list_lru_destroy()`
List LRU์ ์ด๊ธฐํ์ ์๋ฉธ์ ๋ด๋นํฉ๋๋ค.
// mm/list_lru.c:574-600
int __list_lru_init(struct list_lru *lru, bool memcg_aware, struct shrinker *shrinker)
{
int i;
#ifdef CONFIG_MEMCG
if (shrinker)
lru->shrinker_id = shrinker->id;
else
lru->shrinker_id = -1;
if (mem_cgroup_kmem_disabled())
memcg_aware = false;
#endif
lru->node = kzalloc_objs(*lru->node, nr_node_ids);
if (!lru->node)
return -ENOMEM;
for_each_node(i)
init_one_lru(lru, &lru->node[i].lru);
memcg_init_list_lru(lru, memcg_aware);
list_lru_register(lru);
return 0;
}
ํธ์ถ ํ๋ฆ
LRU ์ถ๊ฐ/์ญ์ ํ๋ฆ
list_lru_add_obj() / list_lru_del_obj()
โโ virt_to_page() โ page_to_nid() โ NUMA ๋
ธ๋ ๊ฒฐ์
โโ mem_cgroup_from_virt() โ memcg ๊ฒฐ์ (memcg_aware์ธ ๊ฒฝ์ฐ)
โโ list_lru_add() / list_lru_del()
โโ lock_list_lru_of_memcg()
โ โโ list_lru_from_memcg_idx() โ memcg๋ณ list_lru_one ํ๋
โ โโ lock_list_lru() โ ์คํ๋ฝ ํ๋
โโ list_add_tail() / list_del_init()
โโ set_shrinker_bit() (์ฒซ ์ถ๊ฐ ์)
โโ unlock_list_lru()
LRU ์ํ ํ๋ฆ
list_lru_walk_node()
โโ list_lru_walk_one(NULL memcg)
โ โโ __list_lru_walk_one()
โ โโ lock_list_lru_of_memcg()
โ โโ list_for_each_safe() ์ํ
โ โ โโ isolate() ์ฝ๋ฐฑ ํธ์ถ
โ โ โโ lru_status์ ๋ฐ๋ฅธ ๋ถ๊ธฐ
โ โโ unlock_list_lru()
โโ xa_for_each() (memcg_aware์ธ ๊ฒฝ์ฐ)
โโ __list_lru_walk_one() (๊ฐ memcg๋ณ)
shrinker ์ฐ๋ ํ๋ฆ
try_to_free_pages() / kswapd
โโ shrink_slab()
โโ list_lru_shrink_walk()
โโ list_lru_walk_one()
โโ __list_lru_walk_one()
โโ isolate() ์ฝ๋ฐฑ โ LRU_REMOVED / LRU_ROTATE / LRU_STOP
list_lru_shrink_walk()๋ struct shrink_control์ nid, memcg, nr_to_scan์ ๊ทธ๋๋ก ๋ฐ์ list_lru_walk_one()์ผ๋ก ๋๊น๋๋ค. ์ด ๋๋ฌธ์ ์ฌ๋ฉ ํ์๋์ ํ์ด์ง ํ์๋๊ณผ ๋ฐ๋ก ์์ง์ด์ง๋ง, ๋ฉ๋ชจ๋ฆฌ ์๋ ฅ์ด ๋์ ๋๋ ๋ ๊ฒฝ๋ก๊ฐ ํจ๊ป ๊ด์ธก๋ฉ๋๋ค.
์ด๊ธฐํ/์๋ฉธ ํ๋ฆ
__list_lru_init()
โโ kzalloc_objs() โ node ๋ฐฐ์ด ํ ๋น
โโ for_each_node() โ init_one_lru() ๊ฐ ๋
ธ๋ ์ด๊ธฐํ
โโ memcg_init_list_lru() โ Xarray ์ด๊ธฐํ
โโ list_lru_register() โ memcg_list_lrus์ ์ถ๊ฐ
list_lru_destroy()
โโ list_lru_unregister() โ memcg_list_lrus์์ ์ ๊ฑฐ
โโ memcg_destroy_list_lru() โ Xarray ํญ๋ชฉ ํด์
โโ kfree(node)
์กฐ๊ฑด๋ณ ๋น๊ต
List LRU API ๋น๊ต
| ํจ์ | ์ญํ | memcg ์ฒ๋ฆฌ | NUMA ์ฒ๋ฆฌ |
|---|---|---|---|
| `list_lru_add()` | ์์ดํ ์ถ๊ฐ | ๋ช ์์ memcg ์ง์ | ๋ช ์์ nid ์ง์ |
| `list_lru_add_obj()` | ์์ดํ ์ถ๊ฐ | virt์์ ์๋ ๊ฒฐ์ | virt์์ ์๋ ๊ฒฐ์ |
| `list_lru_del()` | ์์ดํ ์ญ์ | ๋ช ์์ memcg ์ง์ | ๋ช ์์ nid ์ง์ |
| `list_lru_del_obj()` | ์์ดํ ์ญ์ | virt์์ ์๋ ๊ฒฐ์ | virt์์ ์๋ ๊ฒฐ์ |
| `list_lru_walk_one()` | ์ํ | ๋ช ์์ memcg | ๋ช ์์ nid |
| `list_lru_walk_node()` | ๋ ธ๋ ์ ์ฒด ์ํ | ๋ชจ๋ memcg ์ํ | ๋ช ์์ nid |
LRU Walk ์ฝ๋ฐฑ ๋ฐํ๊ฐ ๋์
| ๋ฐํ๊ฐ | ๋์ | ์ ๊ธ ์ํ | ์ฌ์๋ |
|---|---|---|---|
| `LRU_REMOVED` | ์์ดํ ์ ๊ฑฐ, ๋ค์์ผ๋ก ์ด๋ | ์ ์ง | ์๋ |
| `LRU_REMOVED_RETRY` | ์์ดํ ์ ๊ฑฐ, ์ฒ์๋ถํฐ ๋ค์ | ํด์ ํ ์ฌํ๋ | ์ |
| `LRU_ROTATE` | ๋ฆฌ์คํธ ๋์ผ๋ก ์ด๋ | ์ ์ง | ์๋ |
| `LRU_SKIP` | ๊ฑด๋๋ | ์ ์ง | ์๋ |
| `LRU_RETRY` | ์ฒ์๋ถํฐ ๋ค์ | ํด์ ํ ์ฌํ๋ | ์ |
| `LRU_STOP` | ์ํ ์ค์ง | ์ ์ง | ์๋ |
memcg ์ฒ๋ฆฌ ๋ฐฉ์ ๋น๊ต
| ์กฐ๊ฑด | ๋์ |
|---|---|
| `memcg_aware = true` | Xarray์ memcg๋ณ list_lru_memcg ํ ๋น |
| `memcg_aware = false` | ๋ฃจํธ memcg์ list_lru_node.lru๋ง ์ฌ์ฉ |
| memcg reparenting | ๋ถ๋ชจ memcg์ LRU๋ก ์์ดํ ์ด๋, src๋ `LONG_MIN`์ผ๋ก ํ์ |
| memcg ํด์ | RCU๋ฅผ ํตํด list_lru_memcg ์์ ํ๊ฒ ํด์ |
List LRU์ page reclaim LRU ๋น๊ต
| ๊ตฌ๋ถ | ๊ด๋ฆฌ ๋์ | ๋ํ ๊ฒฝ๋ก | ํ์ ๋จ์ | ๊ด์ฐฐ ์งํ |
|---|---|---|---|---|
| List LRU | dentry, inode, shmem ๊ฐ์ ์ปค๋ ์ค๋ธ์ ํธ | `shrink_slab()` โ `list_lru_shrink_walk()` | ์ค๋ธ์ ํธ ๊ฐ์ | `list_lru_count_one()`, `list_lru_count_node()` |
| page reclaim LRU | anon/file ํ์ด์ง | `try_to_free_pages()` โ `shrink_node()` โ `shrink_lruvec()` | ํ์ด์ง ํ๋ ์ | `pgscan`, `pgsteal`, `allocstall`, `kswapd` |
| ์ฐ๊ฒฐ์ | shrinker๊ฐ drainํ ๋์์ ์ ๊ณต | `list_lru_walk_node()`๊ฐ ์ฝ๋ฐฑ ๊ธฐ๋ฐ ์ํ | memcg/nid ๋จ์ | `cat /proc/pressure/memory`, `swapon --show` |