๐งฎ zsmalloc
๊ด๋ จ ์์ค:mm/zsmalloc.c,mm/zpdesc.h,include/linux/zsmalloc.h
๊ด๋ จ ๋ฌธ์: Swap / zswap ยท SLUB ํ ๋น์ ยท Buddy Allocator
๊ฐ์ (Overview)
zsmalloc์ ๋ฆฌ๋ ์ค ์ปค๋์ ์์ถ ๋ฉ๋ชจ๋ฆฌ ์ ์ฉ ํ ๋น์์ ๋๋ค. zswap, zram ๋ฑ์์ ์์ถ๋ ํ์ด์ง ํ๋ ์์ ์ ์ฅํ ๋ ์ฌ์ฉํ๋ฉฐ, ์ผ๋ฐ์ ์ธ slab ํ ๋น์(SLUB)์ ๋ฌ๋ฆฌ ์ฌ๋ฌ ๋ฌผ๋ฆฌ ํ์ด์ง์ ๊ฑธ์ณ ๋ถ์ฐ๋ ๊ฐ์ฒด๋ฅผ ํ๋์ ๋ ผ๋ฆฌ์ ๋จ์๋ก ๊ด๋ฆฌํ๋ ๊ฒ์ด ํต์ฌ ํน์ง์ ๋๋ค.
์ผ๋ฐ slab ํ ๋น์๋ ํ๋์ ๊ฐ์ฒด๊ฐ ๋ฐ๋์ ํ๋์ ํ์ด์ง ์์ ์์ ํ ๋ค์ด๊ฐ์ผ ํ์ง๋ง, zsmalloc์ ์ฌ๋ฌ ํ์ด์ง์ ๊ฑธ์ณ ๋ถ์ฐ๋ ๊ฐ์ฒด๋ ํ๋์ zspage๋ก ๋ฌถ์ด ํ ๋น/ํด์ ํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์์ถ ๋ฐ์ดํฐ์ ํฌ๊ธฐ๊ฐ ํ์ด์ง ๊ฒฝ๊ณ๋ฅผ ๋๋๋ค ๋๋ ํจ์จ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
์ด์ ๊ด์ ์์๋ zsmalloc์ "์์ถ๋ ์ง ์์๋ฅผ ์ฌ๋ฌ ์นธ์ง๋ฆฌ ์ ๋ฐ์ ๋ผ์ ๋ฃ๊ณ , ์์ก์ด(handle)๋ง ๋ค๊ณ ์์น๋ฅผ ์ฐพ์๊ฐ๋ ์ฐฝ๊ณ "์ฒ๋ผ ๋ณด๋ฉด ์ดํด๊ฐ ์ฝ์ต๋๋ค. zswap์ด๋ zram์ ์์ถ ๊ฒฐ๊ณผ๋ฌผ๋ง ๋ณด๊ดํ๊ณ , ์ค์ ๋ฌผ๋ฆฌ ํ์ด์ง ๋ฌถ์๊ณผ ๋น ์ฌ๋กฏ ๊ด๋ฆฌ, compaction, migration ๊ฐ์ ์ ์ฅ์ ์ด์์ zsmalloc์ด ๋งก์ต๋๋ค.
์์ค ํ์ผ:
mm/zsmalloc.c โ ํต์ฌ ํ ๋น ๋ก์ง (2258์ค)
mm/zpdesc.h โ zpdesc ๊ตฌ์กฐ์ฒด (struct page ์ค๋ฒ๋ ์ด)
include/linux/zsmalloc.h โ ์ธ๋ถ API ์ ์ธ
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# zsmalloc ๋ชจ๋ ๋ก๋ ์ํ ํ์ธ
lsmod | grep zsmalloc
# zsmalloc ํต๊ณ (CONFIG_ZSMALLOC_STAT ํ์ฑํ ์)
cat /sys/kernel/debug/zsmalloc/*/classes
# zsmalloc ํ์์ ์ฌ์ฉ ์ค์ธ ํ์ด์ง ์
cat /sys/kernel/debug/zsmalloc/*/classes | awk '{sum += $14} END {print "total pages:", sum}'
# zswap์์ ์ฌ์ฉํ๋ zsmalloc ํ ํ์ธ
cat /sys/kernel/mm/zswap/mm_stat
# zsmalloc ๊ด๋ จ ์ปค๋ ์ค์ ํ์ธ
grep CONFIG_ZSMALLOC /boot/config-$(uname -r)
# ํ์ฌ ์์คํ
์ Zswap / Zswapped ๋ฉ๋ชจ๋ฆฌ๋ ํ์ธ
grep -E 'Zswap|Zswapped' /proc/meminfo
# zspage compaction ์ํ ํ์ธ (kern.msgbuf ๋๋ dmesg)
dmesg | grep -i "zsmalloc\|zspage"
# ํ์ฌ ์์คํ
์ zsmalloc pool ์
ls /sys/kernel/debug/zsmalloc/ 2>/dev/null || echo "debugfs not available"
# zram๊ณผ zsmalloc ์ฐ๊ฒฐ ํ์ธ
cat /sys/block/zram0/mm_stat 2>/dev/null
# ํด๋์ค๋ณ ํต๊ณ๋ฅผ ํ ํํ๋ก ๋ณด๊ธฐ ์ข๊ฒ ์ ๋ ฌ
cat /sys/kernel/debug/zsmalloc/*/classes 2>/dev/null | column -t
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
struct zpdesc โ ํ์ด์ง ์ค๋ช ์ (struct page ์ค๋ฒ๋ ์ด)
zpdesc๋ struct page์ ํ๋๋ฅผ ์ฌ์ฌ์ฉํ์ฌ zsmalloc์ด ๊ด๋ฆฌํ๋ ๋ฌผ๋ฆฌ ํ์ด์ง๋ฅผ ์ค๋ช ํฉ๋๋ค.
/* mm/zpdesc.h:32-50 */
struct zpdesc {
unsigned long flags; /* ํ์ด์ง ํ๋๊ทธ (PG_private: ์ฒซ ๋ฒ์งธ ํ์ด์ง ์๋ณ) */
struct list_head lru; /* ํ์ด์ง ๋ง์ด๊ทธ๋ ์ด์
์ฉ LRU */
unsigned long movable_ops; /* ๋ง์ด๊ทธ๋ ์ด์
๊ฐ๋ฅ ์คํผ๋ ์ด์
*/
union {
struct zpdesc *next; /* ๋ค์ zpdesc (zspage ๋ด ์ฐ๊ฒฐ) */
unsigned long handle; /* huge zspage์ ํ ๋น ํธ๋ค */
};
struct zspage *zspage; /* ์์ zspage ํฌ์ธํฐ */
unsigned int first_obj_offset; /* ์ฒซ ๋ฒ์งธ ๊ฐ์ฒด์ ํ์ด์ง ๋ด ์คํ์
(ํ์ 24๋นํธ) */
atomic_t _refcount; /* ์ฐธ์กฐ ์นด์ดํธ */
};
/* struct page์ ์ ํํ ๊ฐ์ ํฌ๊ธฐ/์คํ์
๋งคํ (static_assert๋ก ๊ฒ์ฆ) */
struct zspage โ zsmalloc ํ ๋น ๋จ์
์ฌ๋ฌ ๋ฌผ๋ฆฌ ํ์ด์ง(zpdesc)๋ก ๊ตฌ์ฑ๋ ๋ ผ๋ฆฌ์ ํ ๋น ๋จ์์ ๋๋ค.
/* mm/zsmalloc.c:261-274 */
struct zspage {
struct {
unsigned int huge:HUGE_BITS; /* 1: ํ๋์ zpdesc์ ํ๋์ ๊ฐ์ฒด (huge class) */
unsigned int fullness:FULLNESS_BITS;/* ํ์ฌ fullness ๊ทธ๋ฃน ์ธ๋ฑ์ค */
unsigned int class:CLASS_BITS + 1; /* ์์ size_class ์ธ๋ฑ์ค */
unsigned int magic:MAGIC_VAL_BITS; /* ZSPAGE_MAGIC (0x58) ๊ฒ์ฆ์ฉ */
};
unsigned int inuse; /* ํ์ฌ ์ฌ์ฉ ์ค์ธ ๊ฐ์ฒด ์ */
unsigned int freeobj; /* freelist์ ์ฒซ ๋ฒ์งธ ๊ฐ์ฒด ์ธ๋ฑ์ค */
struct zpdesc *first_zpdesc; /* ์ฒซ ๋ฒ์งธ zpdesc ํฌ์ธํฐ */
struct list_head list; /* size_class์ fullness_list ์ฐ๊ฒฐ์ฉ */
struct zs_pool *pool; /* ์์ ํ ํฌ์ธํฐ */
struct zspage_lock zsl; /* zspage๋ณ ๋ฝ */
};
struct zs_pool โ zsmalloc ํ
zsmalloc ํ ๋น์์ ์ต์์ ๊ด๋ฆฌ ๊ตฌ์กฐ์ฒด์ ๋๋ค.
/* mm/zsmalloc.c:199-220 */
struct zs_pool {
const char *name; /* ํ ์ด๋ฆ (์: "zswap") */
struct size_class *size_class[ZS_SIZE_CLASSES]; /* ํฌ๊ธฐ๋ณ ํด๋์ค ๋ฐฐ์ด */
atomic_long_t pages_allocated; /* ํ ๋น๋ ์ด ํ์ด์ง ์ */
struct zs_pool_stats stats; /* compaction ํต๊ณ */
struct shrinker *shrinker; /* ๋ฉ๋ชจ๋ฆฌ ํ์์ฉ shrinker */
rwlock_t lock; /* ๋ง์ด๊ทธ๋ ์ด์
/compaction ๋ณดํธ */
atomic_t compaction_in_progress; /* compaction ์งํ ์ค ํ๋๊ทธ */
#ifdef CONFIG_COMPACTION
struct work_struct free_work; /* ์ง์ฐ ํด์ ์ํฌํ */
#endif
};
struct size_class โ ํฌ๊ธฐ๋ณ ํด๋์ค
๋์ผํ ํฌ๊ธฐ์ ๊ฐ์ฒด๋ฅผ ๊ด๋ฆฌํ๋ zspage ๊ทธ๋ฃน์ ๋๋ค.
/* mm/zsmalloc.c:160-174 */
struct size_class {
spinlock_t lock; /* ํด๋์ค ๋ด ๋์์ฑ ์ ์ด */
struct list_head fullness_list[NR_FULLNESS_GROUPS]; /* fullness๋ณ freelist */
int size; /* ๊ฐ์ฒด ํฌ๊ธฐ (ZS_ALIGN ๋ฐฐ์) */
int objs_per_zspage; /* zspage๋น ์ต๋ ๊ฐ์ฒด ์ */
int pages_per_zspage; /* zspage๋ฅผ ๊ตฌ์ฑํ๋ ๋ฌผ๋ฆฌ ํ์ด์ง ์ */
unsigned int index; /* ํด๋์ค ์ธ๋ฑ์ค */
struct zs_size_stat stats; /* ํ ๋น/์ฌ์ฉ ํต๊ณ */
};
struct link_free โ free list ๋ ธ๋
zspage ๋ด๋ถ์ ๋น ๊ฐ์ฒด์ ์ฝ์ ๋์ด singly linked list๋ฅผ ๊ตฌ์ฑํฉ๋๋ค.
/* mm/zsmalloc.c:182-194 */
struct link_free {
union {
unsigned long next; /* ๋ค์ ๋น ๊ฐ์ฒด์ ์ธ๋ฑ์ค (OBJ_TAG_BITS ์ํํธ) */
unsigned long handle; /* ํ ๋น๋ ๊ฐ์ฒด์ ํธ๋ค */
};
};
Handle ์ธ์ฝ๋ฉ ๋ฐฉ์
๊ฐ์ฒด ์์น๋ (PFN, obj_idx) ์์ผ๋ก ํ๋์ unsigned long ํธ๋ค์ ์ธ์ฝ๋ฉ๋ฉ๋๋ค.
/* mm/zsmalloc.c:56-92 */
#define _PFN_BITS (MAX_POSSIBLE_PHYSMEM_BITS - PAGE_SHIFT)
/*
* ํ ๋น๋ ๊ฐ์ฒด์ ํค๋๋ OBJ_ALLOCATED_TAG๋ฅผ ๊ฐ์ ธ์ผ ํ๋ค.
* ์ตํ์ ๋นํธ์ ์ํ ๋นํธ๋ฅผ ๋ฃ์ด๋ ๋๋ ์ด์ ๋
* handle์ด ์ ๋ ฌ๋ ์ฃผ์๋ผ์ ํ์ ๋นํธ ์ฌ์ ๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
*/
#define OBJ_ALLOCATED_TAG 1
#define OBJ_TAG_BITS 1
#define OBJ_TAG_MASK OBJ_ALLOCATED_TAG
#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
enum fullness_group โ zspage ์ ์ ์จ ๊ตฌ๊ฐ
fullness_list๋ size_class ์์์ ๊ฐ์ ํฌ๊ธฐ ๊ฐ์ฒด๋ฅผ ๋ด๋ zspage๋ฅผ ์ ์ ์จ๋ณ๋ก ๋๋ ๊ด๋ฆฌํฉ๋๋ค. compaction์ ์ด ๊ตฌ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๊ฐ์ฅ ๋น์ด ์๋ zspage์ ๊ฐ์ฅ ์ฐจ ์๋ zspage๋ฅผ ๊ณจ๋ผ ๊ฐ์ฒด๋ฅผ ์ฎ๊น๋๋ค.
/* mm/zsmalloc.c:134-140 */
enum fullness_group {
ZS_INUSE_RATIO_0,
ZS_INUSE_RATIO_10,
/* 8๊ฐ์ fullness ๊ทธ๋ฃน์ด ์ค๊ฐ์ ๋ ์๋ค */
ZS_INUSE_RATIO_99 = 10,
ZS_INUSE_RATIO_100,
NR_FULLNESS_GROUPS,
};
ํต์ฌ ํจ์
zs_malloc โ ๊ฐ์ฒด ํ ๋น
/* mm/zsmalloc.c:1297-1354 */
unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp, const int nid);
์ญํ : ํ์์ ์ง์ ๋ ํฌ๊ธฐ์ ๊ฐ์ฒด๋ฅผ ํ ๋นํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
1. size == 0 โ ERR_PTR(-EINVAL) ๋ฐํ
2. size > ZS_MAX_ALLOC_SIZE โ ERR_PTR(-ENOSPC) ๋ฐํ
3. handle ์บ์์์ ํ ๋น ์คํจ โ ERR_PTR(-ENOMEM) ๋ฐํ
4. find_get_zspage()๋ก ๊ธฐ์กด zspage ํ์
- zspage ์กด์ฌ โ obj_malloc() + fix_fullness_group() ํ ๋ฐํ
- zspage ์์ โ alloc_zspage()๋ก ์๋ก ์์ฑ โ obj_malloc() + insert_zspage()
zs_free โ ๊ฐ์ฒด ํด์
/* mm/zsmalloc.c:1384-1417 */
void zs_free(struct zs_pool *pool, unsigned long handle);
์ญํ : ํ ๋น๋ ๊ฐ์ฒด๋ฅผ ํ์ ๋ฐํํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
1. handle์ด ERR_PTR ๋๋ NULL โ ์ฆ์ ๋ฐํ
2. obj_free()๋ก freelist์ ์ฝ์
3. fix_fullness_group()๋ก fullness ๊ทธ๋ฃน ๊ฐฑ์
4. fullness == ZS_INUSE_RATIO_0 โ free_zspage()๋ก zspage ์ ์ฒด ํด์
zs_compact โ ํ ์ปดํฉ์
/* mm/zsmalloc.c:1938-1964 */
unsigned long zs_compact(struct zs_pool *pool);
์ญํ : ๊ฐ ํฌ๊ธฐ ํด๋์ค์ zspage๋ฅผ ์์ถํ์ฌ ๋น ํ์ด์ง๋ฅผ ํ์ํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
1. compaction_in_progress๊ฐ ์ด๋ฏธ 1์ด๋ฉด ์ค๋ณต ์คํ ๋ฐฉ์ง (0 ๋ฐํ)
2. ํฐ ํฌ๊ธฐ ํด๋์ค๋ถํฐ ์ํํ๋ฉฐ __zs_compact() ํธ์ถ
3. __zs_compact() ๋ด๋ถ:
- isolate_dst_zspage()๋ก ๊ฐ์ฅ ๋ง์ด ์ฐฌ zspage๋ฅผ ๋์์ผ๋ก ์ ํ
- isolate_src_zspage()๋ก ๊ฐ์ฅ ์ ๊ฒ ์ฐฌ zspage๋ฅผ ์์ค๋ก ์ ํ
- migrate_zspage()๋ก ๊ฐ์ฒด๋ฅผ ๋ณต์ฌํ์ฌ ๋์ zspage์ ์ด๋
- ์์ค zspage๊ฐ ๋น๋ฉด free_zspage()๋ก ํด์
zs_shrinker_scan โ ๋ฉ๋ชจ๋ฆฌ ์๋ฐ ์ compaction ์ง์
/* mm/zsmalloc.c:1972-1985 */
static unsigned long zs_shrinker_scan(struct shrinker *shrinker,
struct shrink_control *sc);
์ญํ : shrinker ์ธํฐํ์ด์ค๋ฅผ ํตํด ๋ฉ๋ชจ๋ฆฌ ์๋ฐ ์ zsmalloc ํ์์ ํ์ ๊ฐ๋ฅํ ํ์ด์ง๋ฅผ ์ฐพ๊ณ zs_compact()๋ฅผ ํธ์ถํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
1. shrinker->private_data์์ ๋์ zs_pool ํ๋
2. zs_compact(pool) ์คํ
3. ํ์ํ ํ์ด์ง๊ฐ ์์ผ๋ฉด ๊ทธ ์๋ฅผ ๋ฐํ
4. ํ์ํ์ง ๋ชปํ๋ฉด SHRINK_STOP ๋ฐํ
zs_obj_read_begin / zs_obj_read_end โ ๊ฐ์ฒด ์ฝ๊ธฐ
/* mm/zsmalloc.c:1037-1085 */
void *zs_obj_read_begin(struct zs_pool *pool, unsigned long handle,
size_t mem_len, void *local_copy);
/* mm/zsmalloc.c:1087-1112 */
void zs_obj_read_end(struct zs_pool *pool, unsigned long handle,
size_t mem_len, void *handle_mem);
์ญํ : ๊ฐ์ฒด ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ์ฝ๊ธฐ ์ํด ๋งคํ/์ธ๋งคํํฉ๋๋ค.
๋ถ๊ธฐ ๋ก์ง:
1. pool->lock read_lock์ผ๋ก ํธ๋คโzpdesc ๋ณํ ๋ณดํธ
2. zspage_read_lock()์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์
์ค๋จ ๋ณด์ฅ
3. ๊ฐ์ฒด๊ฐ ํ ํ์ด์ง์ ์์ ํ ํฌํจ โ kmap_local_zpdesc()๋ก ์ง์ ๋งคํ
4. ๊ฐ์ฒด๊ฐ ๋ ํ์ด์ง์ ๊ฑธ์นจ โ local_copy์ ๋ณต์ฌํ์ฌ ๋ฐํ
zs_page_migrate โ ํ์ด์ง ๋ง์ด๊ทธ๋ ์ด์
/* mm/zsmalloc.c:1686-1777 */
static int zs_page_migrate(struct page *newpage, struct page *page,
enum migrate_mode mode);
์ญํ : zsmalloc ํ์ด์ง๋ฅผ ๋ค๋ฅธ ๋ฌผ๋ฆฌ ์์น๋ก ์ด๋ํฉ๋๋ค (compaction, NUMA balancing).
๋ถ๊ธฐ ๋ก์ง:
1. zpdesc->zspage == NULL โ ์ด๋ฏธ ํด์ ๋ ํ์ด์ง, ๋ง์ด๊ทธ๋ ์ด์
๋ถ๊ฐ
2. pool->lock write_lock + class->lock spin_lock ํ๋
3. zspage_write_trylock() ์คํจ โ -EINVAL ๋ฐํ
4. ์ ํ์ด์ง์ ์ ์ฒด ๋ฐ์ดํฐ ๋ณต์ฌ โ handle ์
๋ฐ์ดํธ โ replace_sub_page() ํธ์ถ
ํธ์ถ ํ๋ฆ
ํ ๋น ํ๋ฆ
zs_malloc(pool, size, gfp, nid)
โโโ cache_alloc_handle() โ handle ์บ์์์ ํ ๋น
โโโ get_size_class_index(size) โ ํฌ๊ธฐ โ ํด๋์ค ์ธ๋ฑ์ค ๋ณํ
โโโ [class->lock]
โโโ find_get_zspage(class) โ fullness_list์์ ๋น zspage ํ์
โ โโโ (ZS_INUSE_RATIO_99 โ 0 ์์)
โโโ [zspage ๋ฐ๊ฒฌ ์]
โ โโโ obj_malloc(pool, zspage, handle)
โ โ โโโ get_freeobj() โ freelist head
โ โ โโโ link->handle = handle โ handle ๊ธฐ๋ก
โ โ โโโ location_to_obj() โ (zpdesc, obj_idx) โ obj ์ธ์ฝ๋ฉ
โ โ โโโ record_obj(handle, obj) โ handle์ obj ์ ์ฅ
โ โโโ fix_fullness_group() โ fullness ๊ทธ๋ฃน ๊ฐฑ์
โโโ [zspage ๋ฏธ๋ฐ๊ฒฌ ์]
โ โโโ alloc_zspage(pool, class, gfp, nid)
โ โ โโโ cache_alloc_zspage() โ zspage ๊ตฌ์กฐ์ฒด ํ ๋น
โ โ โโโ alloc_zpdesc() ร N โ ๋ฌผ๋ฆฌ ํ์ด์ง ํ ๋น (N = pages_per_zspage)
โ โ โโโ create_page_chain() โ zpdesc๋ค ์ฐ๊ฒฐ
โ โ โโโ init_zspage() โ freelist ์ด๊ธฐํ (link_free ์ฐ๊ฒฐ)
โ โโโ obj_malloc()
โ โโโ insert_zspage(class, zspage, newfg)
โ โโโ SetZsPageMovable() โ ๋ง์ด๊ทธ๋ ์ด์
๊ฐ๋ฅ ํ๋๊ทธ ์ค์
โโโ [class->lock ํด์ ] โ handle ๋ฐํ
ํด์ ํ๋ฆ
zs_free(pool, handle)
โโโ [pool->lock read_lock]
โโโ handle_to_obj(handle) โ handle โ obj ๋์ฝ๋ฉ
โโโ obj_to_zpdesc(obj) โ obj โ zpdesc ๋ณํ
โโโ [class->lock]
โโโ class_stat_sub(ZS_OBJS_INUSE) โ ์ฌ์ฉ ์ค์ธ ๊ฐ์ฒด ์ ๊ฐ์
โโโ obj_free(class_size, obj)
โ โโโ obj_to_location() โ obj โ (zpdesc, obj_idx)
โ โโโ link->next = freeobj << BITS โ freelist์ ์ฝ์
โ โโโ mod_zspage_inuse(zspage, -1) โ inuse ์นด์ดํธ ๊ฐ์
โโโ fix_fullness_group() โ fullness ๊ทธ๋ฃน ๊ฐฑ์
โโโ [fullness == ZS_INUSE_RATIO_0]
โ โโโ free_zspage(pool, class, zspage)
โ โโโ trylock_zspage() โ ๋ชจ๋ zpdesc ์ ๊ธ ์๋
โ โ โโโ [์ ๊ธ ์คํจ ์] kick_deferred_free()
โ โโโ remove_zspage() โ fullness_list์์ ์ ๊ฑฐ
โ โโโ __free_zspage()
โ โโโ reset_zpdesc() ร N โ zpdesc ์ด๊ธฐํ
โ โโโ free_zpdesc() ร N โ ๋ฌผ๋ฆฌ ํ์ด์ง ํด์
โ โโโ cache_free_zspage() โ zspage ๊ตฌ์กฐ์ฒด ํด์
โโโ cache_free_handle() โ handle ํด์
Compaction ํ๋ฆ
zs_compact(pool)
โโโ [compaction_in_progress ํ์ธ]
โโโ [ํฐ ํฌ๊ธฐ ํด๋์ค โ ์์ ํฌ๊ธฐ ํด๋์ค ์ํ]
โโโ __zs_compact(pool, class)
โโโ [pool->lock write_lock + class->lock]
โโโ while (zs_can_compact(class))
โ โโโ isolate_dst_zspage() โ ๊ฐ์ฅ ์ฐฌ zspage ์ ํ
โ โโโ isolate_src_zspage() โ ๊ฐ์ฅ ๋น zspage ์ ํ
โ โโโ migrate_zspage()
โ โ โโโ while (์์ค์ ๊ฐ์ฒด ๋จ์)
โ โ โโโ find_alloced_obj() โ ํ ๋น๋ ๊ฐ์ฒด ์ฐพ๊ธฐ
โ โ โโโ obj_malloc() โ ๋์์ ์ ์์น ํ ๋น
โ โ โโโ zs_object_copy() โ ๋ฐ์ดํฐ ๋ณต์ฌ
โ โ โโโ obj_free() โ ์์ค ์์น ํด์
โ โโโ [์์ค zspage ๋น๋ฉด] free_zspage()
โ โโโ [๋์ zspage ์ฐจ๋ฉด] putback_zspage() + ์ ๋์ ์ ํ
โโโ [๋ฐ๋ณต ์ข
๋ฃ]
๋ฉ๋ชจ๋ฆฌ ์๋ฐ์์ compaction์ผ๋ก ๋ค์ด๊ฐ๋ ํ๋ฆ
๋ฉ๋ชจ๋ฆฌ ์๋ฐ
โโโ shrink_slab()/shrinker ํธ์ถ
โโโ zs_shrinker_scan(shrinker, sc)
โโโ pool = shrinker->private_data
โโโ pages_freed = zs_compact(pool)
โโโ [pages_freed == 0] SHRINK_STOP
์กฐ๊ฑด๋ณ ๋น๊ต
size_class ๊ฒฐ์ ๊ธฐ์ค
| ์กฐ๊ฑด | ๋์ | ๋น๊ณ |
|---|---|---|
| `size <= ZS_MIN_ALLOC_SIZE` | class index = 0 | ์ต์ 32๋ฐ์ดํธ |
| `size > ZS_MAX_ALLOC_SIZE` | ํ ๋น ์คํจ (ENOSPC) | PAGE_SIZE ์ด๊ณผ ๋ถ๊ฐ |
| `is_power_of_2(class_size)` | pages_per_zspage = 1 | ๋ญ๋น 0 |
| `class_size`๊ฐ 2์ ๊ฑฐ๋ญ์ ๊ณฑ ์๋ | `calculate_zspage_chain_size()` | ์ต์ ๋ญ๋น chain ์ ํ |
fullness ๊ทธ๋ฃน ๋ถ๋ฅ
| fullness ๊ทธ๋ฃน | inuse ๋น์จ | ์ค๋ช |
|---|---|---|
| ZS_INUSE_RATIO_0 | 0% | ์์ ํ ๋น zspage (ํด์ ๊ฐ๋ฅ) |
| ZS_INUSE_RATIO_10 | 1~10% | ๊ฑฐ์ ๋น zspage (compaction ๋์) |
| ... | ... | ... |
| ZS_INUSE_RATIO_99 | 90~99% | ๊ฑฐ์ ์ฐฌ zspage |
| ZS_INUSE_RATIO_100 | 100% | ์์ ํ ์ฐฌ zspage |
lock ๊ณ์ธต
| ๋ฝ | ๋ฒ์ | ํ๋ ์์ |
|---|---|---|
| `pool->lock` | ํ ์ ์ฒด ๋ง์ด๊ทธ๋ ์ด์ ๋ณดํธ | 1๋ฒ์งธ |
| `class->lock` | ํฌ๊ธฐ ํด๋์ค ๋ด zspage ํ ๋น/ํด์ | 2๋ฒ์งธ |
| `zspage->zsl` | ๊ฐ๋ณ zspage ์ฝ๊ธฐ/์ฐ๊ธฐ ์ ๊ทผ | 3๋ฒ์งธ |
| `zpdesc` (folio lock) | ๋ฌผ๋ฆฌ ํ์ด์ง ์ ๊ธ | 4๋ฒ์งธ |
huge vs non-huge zspage
| ์์ฑ | non-huge | huge |
|---|---|---|
| pages_per_zspage | > 1 ๋๋ objs > 1 | = 1์ด๊ณ objs = 1 |
| handle ์ ์ฅ ์์น | ์ฒซ ๋ฒ์งธ ๊ฐ์ฒด์ link_free | zpdesc->handle |
| freelist ๊ตฌ์กฐ | link_free singly linked list | ๋จ์ผ ๊ฐ์ฒด (freelist ๋ถํ์) |
| `ZsHugePage()` | false | true |