CMA ๋””๋ฒ„๊น… (CMA DebugFS)

๊ฐœ์š” (Overview)

CMA DebugFS๋Š” ๋Ÿฐํƒ€์ž„์— CMA ์˜์—ญ์˜ ์ƒํƒœ๋ฅผ ๊ด€์ฐฐํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋””๋ฒ„๊น… ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. CONFIG_CMA_DEBUGFS ์˜ต์…˜์ด ํ™œ์„ฑํ™”๋˜๋ฉด /sys/kernel/debug/cma/ ๋””๋ ‰ํ† ๋ฆฌ์— ๊ฐ CMA ์˜์—ญ๋ณ„ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ, ํ• ๋‹น/ํ•ด์ œ ํ…Œ์ŠคํŠธ, ๋น„ํŠธ๋งต ๋คํ”„, ์‚ฌ์šฉ๋Ÿ‰ ํ™•์ธ ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ฃผ๋กœ CMA ์˜์—ญ ์„ค๊ณ„ ์‹œ ๋ฉ€ํ‹ฐ ๋ ˆ์ธ์ง€ ๊ตฌ์„ฑ์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•˜๊ฑฐ๋‚˜, unmovable ํŽ˜์ด์ง€ ์นจํˆฌ๋กœ ์ธํ•œ ํ• ๋‹น ์‹คํŒจ๋ฅผ ์ง„๋‹จํ•  ๋•Œ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค.

Linux 7.0์—์„œ CMA DebugFS๋Š” ๋ฉ€ํ‹ฐ ๋ ˆ์ธ์ง€(multi-range) ์ง€์›์„ ๋ฐ˜์˜ํ•˜์—ฌ ๊ฐ ๋ ˆ์ธ์ง€๋ณ„ ๋น„ํŠธ๋งต๊ณผ base PFN์„ ๊ฐœ๋ณ„์ ์œผ๋กœ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ cma_alloc/cma_free ๋””๋ฒ„๊ทธ ํŒŒ์ผ์„ ํ†ตํ•ด ์ˆ˜๋™์œผ๋กœ ํ• ๋‹น/ํ•ด์ œ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด, ์‹ค์ œ ๋“œ๋ผ์ด๋ฒ„ ์—†์ด๋„ CMA ๋™์ž‘์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์†Œ์Šค ํŒŒ์ผ:
mm/cma_debug.c                 โ† DebugFS ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ (212์ค„)
mm/cma.h                       โ† ๋‚ด๋ถ€ ๊ตฌ์กฐ์ฒด (cma, cma_memrange)
include/linux/cma.h            โ† ์™ธ๋ถ€ API ํ—ค๋”
CMA DebugFS ๊ตฌ์กฐ์™€ ํ๋ฆ„

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

# CMA ์˜์—ญ ๋””๋ฒ„๊ทธ ๋””๋ ‰ํ† ๋ฆฌ ํ™•์ธ
sudo ls /sys/kernel/debug/cma/

# CMA ์˜์—ญ๋ณ„ ์ด ํŽ˜์ด์ง€ ์ˆ˜ / ์‚ฌ์šฉ ์ค‘์ธ ํŽ˜์ด์ง€ ์ˆ˜ / ์ตœ๋Œ€ ์—ฐ์† ๋นˆ ๋ธ”๋ก
cat /sys/kernel/debug/cma/cma-0/count
cat /sys/kernel/debug/cma/cma-0/used
cat /sys/kernel/debug/cma/cma-0/maxchunk

# order_per_bit ํ™•์ธ (๋น„ํŠธ๋งต ํ•ด์ƒ๋„)
cat /sys/kernel/debug/cma/cma-0/order_per_bit

# ๋ฉ€ํ‹ฐ ๋ ˆ์ธ์ง€ ๊ฐ ๋ฒ”์œ„์˜ base PFN ํ™•์ธ
cat /sys/kernel/debug/cma/cma-0/ranges/0/base_pfn
cat /sys/kernel/debug/cma/cma-0/ranges/1/base_pfn

# ๋ฉ€ํ‹ฐ ๋ ˆ์ธ์ง€ ๋น„ํŠธ๋งต ํ™•์ธ (ํ…์ŠคํŠธ๋กœ ์ถœ๋ ฅ)
cat /sys/kernel/debug/cma/cma-0/ranges/0/bitmap

# ์ˆ˜๋™ ํ• ๋‹น ํ…Œ์ŠคํŠธ (16 ํŽ˜์ด์ง€ ํ• ๋‹น)
echo 16 | sudo tee /sys/kernel/debug/cma/cma-0/alloc

# ์ˆ˜๋™ ํ•ด์ œ ํ…Œ์ŠคํŠธ (16 ํŽ˜์ด์ง€ ํ•ด์ œ)
echo 16 | sudo tee /sys/kernel/debug/cma/cma-0/free

# /proc/meminfo์—์„œ CMA ํ˜„ํ™ฉ ํ™•์ธ
cat /proc/meminfo | grep -i cma

# CMA pageblock ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํƒ€์ž… ํ™•์ธ
cat /proc/pagetypeinfo | grep CMA

# dmesg์—์„œ CMA ๊ด€๋ จ ๋ฉ”์‹œ์ง€ ํ™•์ธ
dmesg | grep -i cma

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

struct cma_mem โ€” ๋””๋ฒ„๊ทธ ํ• ๋‹น ์ถ”์  (`mm/cma_debug.c:18-22`)

struct cma_mem {
struct hlist_node node;   // ํ•ด์‹œ ๋ฆฌ์ŠคํŠธ ๋…ธ๋“œ (mem_head ์—ฐ๊ฒฐ)
struct page *p;           // ํ• ๋‹น๋œ ํŽ˜์ด์ง€ ์‹œ์ž‘ ์ฃผ์†Œ
unsigned long n;          // ํ• ๋‹น๋œ ํŽ˜์ด์ง€ ์ˆ˜
};

์„ค๋ช…: cma_alloc/cma_free ๋””๋ฒ„๊ทธ ํŒŒ์ผ์„ ํ†ตํ•ด ์ˆ˜๋™ ํ• ๋‹น๋œ ํŽ˜์ด์ง€ ๋ธ”๋ก์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. cma ๊ตฌ์กฐ์ฒด์˜ mem_head ํ•ด์‹œ ๋ฆฌ์ŠคํŠธ์— ์—ฐ๊ฒฐ๋˜๋ฉฐ, free ํ˜ธ์ถœ ์‹œ ์ด ๋ฆฌ์ŠคํŠธ์—์„œ ๊บผ๋‚ด์–ด ์ˆœ์ฐจ์ ์œผ๋กœ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

struct cma โ€” CMA ์˜์—ญ ๊ด€๋ฆฌ์ž (`mm/cma.h:39-65`)

struct cma {
unsigned long   count;            // ์ด ํŽ˜์ด์ง€ ์ˆ˜
unsigned long   available_count;  // ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€ ์ˆ˜
unsigned int order_per_bit;       // ๋น„ํŠธ๋งต 1๋น„ํŠธ๋‹น ํŽ˜์ด์ง€ ์ˆ˜ (2^order)
spinlock_t      lock;             // ๋น„ํŠธ๋งต ๋™์‹œ์„ฑ ์ œ์–ด
struct mutex    alloc_mutex;      // ํ• ๋‹น ์‹œ ์ง๋ ฌํ™”
struct hlist_head mem_head;       // ๋””๋ฒ„๊ทธ ํ• ๋‹น ๋ฆฌ์ŠคํŠธ (CONFIG_CMA_DEBUGFS)
spinlock_t      mem_head_lock;    // mem_head ๋™์‹œ์„ฑ ์ œ์–ด
char name[CMA_MAX_NAME];         // ์˜์—ญ ์ด๋ฆ„
int nranges;                      // ์‹ค์ œ ๋ ˆ์ธ์ง€ ์ˆ˜ (1~8)
struct cma_memrange ranges[CMA_MAX_RANGES]; // ๋ฉ€ํ‹ฐ ๋ ˆ์ธ์ง€ ๋ฐฐ์—ด
unsigned long flags;              // CMA_ACTIVATED ๋“ฑ ํ”Œ๋ž˜๊ทธ
int nid;                          // NUMA ๋…ธ๋“œ ID
};

์„ค๋ช…: mem_head์™€ mem_head_lock์€ CONFIG_CMA_DEBUGFS๊ฐ€ ํ™œ์„ฑํ™”๋  ๋•Œ๋งŒ ์กด์žฌํ•˜๋ฉฐ, ์ˆ˜๋™ ํ• ๋‹น๋œ cma_mem ํ•ญ๋ชฉ๋“ค์˜ ํ•ด์‹œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. available_count๋Š” count - used๋กœ ๊ณ„์‚ฐ๋˜๋ฉฐ, cma_used_get()์ด ์ด ๊ฐ’์„ ์ฝ์Šต๋‹ˆ๋‹ค.

struct cma_memrange โ€” ๊ฐœ๋ณ„ ๋ฌผ๋ฆฌ ๋ฒ”์œ„ (`mm/cma.h:26-36`)

struct cma_memrange {
unsigned long base_pfn;    // ๋ฒ”์œ„ ์‹œ์ž‘ PFN
unsigned long count;       // ๋ฒ”์œ„ ๋‚ด ํŽ˜์ด์ง€ ์ˆ˜
union {
unsigned long early_pfn;  // cma_reserve_early()์—์„œ ์‚ฌ์šฉ
unsigned long *bitmap;    // ํ™œ์„ฑํ™” ํ›„ ํ• ๋‹น ๋น„ํŠธ๋งต
};
struct debugfs_u32_array dfs_bitmap;  // debugfs ๋น„ํŠธ๋งต ๋…ธ์ถœ์šฉ
};

์„ค๋ช…: dfs_bitmap์€ cma_debugfs_add_one()์—์„œ bitmap ํ•„๋“œ๋ฅผ ์ง์ ‘ ํ• ๋‹นํ•˜์—ฌ debugfs์— u32 ๋ฐฐ์—ด๋กœ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. array๋Š” bitmap์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋ฅผ, n_elements๋Š” cma_bitmap_maxno() ๊ณ„์‚ฐ๊ฐ’์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

cma_debugfs_fops โ€” debugfs ํŒŒ์ผ ์šด์˜ ์ฒด๊ณ„ (`mm/cma_debug.c:24-32`)

static int cma_debugfs_get(void *data, u64 *val)
{
unsigned long *p = data;
*val = *p;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(cma_debugfs_fops, cma_debugfs_get, NULL, "%llu\n");

์„ค๋ช…: count, order_per_bit, base_pfn ๊ฐ™์€ ์ฝ๊ธฐ ์ „์šฉ ๊ฐ’์„ ํ‘œ์‹œํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ์ผ๋ฐ˜ ๋””๋ฒ„๊ทธ ํŒŒ์ผ ์šด์˜ ์ฒด๊ณ„์ž…๋‹ˆ๋‹ค. DEFINE_DEBUGFS_ATTRIBUTE ๋งคํฌ๋กœ๋กœ open, read, write ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.


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

1. `cma_debugfs_init()` โ€” ์ „์ฒด ์ดˆ๊ธฐํ™” (`mm/cma_debug.c:200-211`)

static int __init cma_debugfs_init(void)
{
struct dentry *cma_debugfs_root;
int i;

cma_debugfs_root = debugfs_create_dir("cma", NULL);

for (i = 0; i < cma_area_count; i++)
cma_debugfs_add_one(&cma_areas[i], cma_debugfs_root);

return 0;
}
late_initcall(cma_debugfs_init);

์—ญํ• : /sys/kernel/debug/cma/ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋“ฑ๋ก๋œ ๋ชจ๋“  CMA ์˜์—ญ์— ๋Œ€ํ•ด cma_debugfs_add_one()์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

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

1. late_initcall์—์„œ ํ˜ธ์ถœ โ€” ๋ชจ๋“  CMA ์˜์—ญ์ด ์ดˆ๊ธฐํ™”๋œ ํ›„ ์‹คํ–‰

2. cma_area_count๋งŒํผ ๋ฐ˜๋ณตํ•˜๋ฉฐ ๊ฐ cma_areas[i]์— ๋Œ€ํ•œ ๋””๋ฒ„๊ทธ ํŒŒ์ผ ์ƒ์„ฑ

2. `cma_debugfs_add_one()` โ€” ์˜์—ญ๋ณ„ ๋””๋ฒ„๊ทธ ํŒŒ์ผ ์ƒ์„ฑ (`mm/cma_debug.c:161-198`)

static void cma_debugfs_add_one(struct cma *cma, struct dentry *root_dentry)
{
struct dentry *tmp, *dir, *rangedir;
int r;
char rdirname[12];
struct cma_memrange *cmr;

tmp = debugfs_create_dir(cma->name, root_dentry);

debugfs_create_file("alloc", 0200, tmp, cma, &cma_alloc_fops);
debugfs_create_file("free", 0200, tmp, cma, &cma_free_fops);
debugfs_create_file("count", 0444, tmp, &cma->count, &cma_debugfs_fops);
debugfs_create_file("order_per_bit", 0444, tmp,
&cma->order_per_bit, &cma_debugfs_fops);
debugfs_create_file("used", 0444, tmp, cma, &cma_used_fops);
debugfs_create_file("maxchunk", 0444, tmp, cma, &cma_maxchunk_fops);

rangedir = debugfs_create_dir("ranges", tmp);
for (r = 0; r < cma->nranges; r++) {
cmr = &cma->ranges[r];
snprintf(rdirname, sizeof(rdirname), "%d", r);
dir = debugfs_create_dir(rdirname, rangedir);
debugfs_create_file("base_pfn", 0444, dir,
&cmr->base_pfn, &cma_debugfs_fops);
cmr->dfs_bitmap.array = (u32 *)cmr->bitmap;
cmr->dfs_bitmap.n_elements =
DIV_ROUND_UP(cma_bitmap_maxno(cma, cmr),
BITS_PER_BYTE * sizeof(u32));
debugfs_create_u32_array("bitmap", 0444, dir,
&cmr->dfs_bitmap);
}

debugfs_create_symlink("base_pfn", tmp, "ranges/0/base_pfn");
debugfs_create_symlink("bitmap", tmp, "ranges/0/bitmap");
}

์—ญํ• : ํ•˜๋‚˜์˜ CMA ์˜์—ญ์— ๋Œ€ํ•ด 6๊ฐœ์˜ ๋””๋ฒ„๊ทธ ํŒŒ์ผ๊ณผ ranges/ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ํ•˜์œ„ ํ˜ธํ™˜์„ ์œ„ํ•ด base_pfn๊ณผ bitmap์˜ ์‹ฌ๋ณผ๋ฆญ ๋งํฌ๋„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

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

1. alloc/free: ์“ฐ๊ธฐ ์ „์šฉ (0200) โ€” ์ˆ˜๋™ ํ• ๋‹น/ํ•ด์ œ

2. count/order_per_bit: ์ง์ ‘ &cma->count ๋“ฑ์— ์—ฐ๊ฒฐ (์ฝ๊ธฐ ์ „์šฉ)

3. used: cma_used_get() ์‚ฌ์šฉ โ€” count - available_count ๊ณ„์‚ฐ

4. maxchunk: cma_maxchunk_get() ์‚ฌ์šฉ โ€” ๋ชจ๋“  ๋ ˆ์ธ์ง€์˜ ๋น„ํŠธ๋งต์„ ์ˆœํšŒํ•˜์—ฌ ์ตœ๋Œ€ ์—ฐ์† ๋นˆ ๋ธ”๋ก ๊ณ„์‚ฐ

5. ranges/N/: ๊ฐ ๋ ˆ์ธ์ง€๋ณ„ base_pfn๊ณผ bitmap u32 ๋ฐฐ์—ด ๋…ธ์ถœ

3. `cma_used_get()` โ€” ์‚ฌ์šฉ๋Ÿ‰ ๊ณ„์‚ฐ (`mm/cma_debug.c:34-43`)

static int cma_used_get(void *data, u64 *val)
{
struct cma *cma = data;

spin_lock_irq(&cma->lock);
*val = cma->count - cma->available_count;
spin_unlock_irq(&cma->lock);

return 0;
}

์—ญํ• : count(์ „์ฒด)์—์„œ available_count(์‚ฌ์šฉ ๊ฐ€๋Šฅ)๋ฅผ ๋นผ์„œ ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ํŽ˜์ด์ง€ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

4. `cma_maxchunk_get()` โ€” ์ตœ๋Œ€ ์—ฐ์† ๋นˆ ๋ธ”๋ก ๊ณ„์‚ฐ (`mm/cma_debug.c:46-66`)

static int cma_maxchunk_get(void *data, u64 *val)
{
struct cma *cma = data;
struct cma_memrange *cmr;
unsigned long maxchunk = 0;
unsigned long start, end;
unsigned long bitmap_maxno;
int r;

spin_lock_irq(&cma->lock);
for (r = 0; r < cma->nranges; r++) {
cmr = &cma->ranges[r];
bitmap_maxno = cma_bitmap_maxno(cma, cmr);
for_each_clear_bitrange(start, end, cmr->bitmap, bitmap_maxno)
maxchunk = max(end - start, maxchunk);
}
spin_unlock_irq(&cma->lock);
*val = (u64)maxchunk << cma->order_per_bit;

return 0;
}

์—ญํ• : ๋ชจ๋“  ๋ ˆ์ธ์ง€์˜ ๋น„ํŠธ๋งต์„ ์ˆœํšŒํ•˜๋ฉฐ ๊ฐ€์žฅ ํฐ ์—ฐ์† ๋นˆ ์˜์—ญ(0 ๋น„ํŠธ ๋ฒ”์œ„)์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. CMA ํ• ๋‹น์ด ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€ ๋ธ”๋ก ํฌ๊ธฐ๋ฅผ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

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

1. cma->nranges๋งŒํผ ๋ฐ˜๋ณต

2. for_each_clear_bitrange()๋กœ ๊ฐ ๋ ˆ์ธ์ง€์˜ ๋นˆ ๋น„ํŠธ ๋ฒ”์œ„ ํƒ์ƒ‰

3. maxchunk = max(end - start, maxchunk)์œผ๋กœ ์ตœ๋Œ€๊ฐ’ ๊ฐฑ์‹ 

4. << cma->order_per_bit๋กœ ํŽ˜์ด์ง€ ์ˆ˜๋กœ ๋ณ€ํ™˜

5. `cma_alloc_mem()` / `cma_free_mem()` โ€” ์ˆ˜๋™ ํ• ๋‹น/ํ•ด์ œ (`mm/cma_debug.c:90-158`)

static int cma_alloc_mem(struct cma *cma, int count)
{
struct cma_mem *mem;
struct page *p;

mem = kzalloc_obj(*mem);
if (!mem)
return -ENOMEM;

p = cma_alloc(cma, count, 0, false);
if (!p) {
kfree(mem);
return -ENOMEM;
}

mem->p = p;
mem->n = count;

cma_add_to_cma_mem_list(cma, mem);

return 0;
}

์—ญํ• : alloc ๋””๋ฒ„๊ทธ ํŒŒ์ผ์— ํŽ˜์ด์ง€ ์ˆ˜๋ฅผ ์“ฐ๋ฉด cma_alloc()์œผ๋กœ ์‹ค์ œ ํ• ๋‹น ํ›„ cma_mem ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

static int cma_free_mem(struct cma *cma, int count)
{
struct cma_mem *mem = NULL;

while (count) {
mem = cma_get_entry_from_list(cma);
if (mem == NULL)
return 0;

if (mem->n <= count) {
cma_release(cma, mem->p, mem->n);
count -= mem->n;
kfree(mem);
} else if (cma->order_per_bit == 0) {
cma_release(cma, mem->p, count);
mem->p += count;
mem->n -= count;
count = 0;
cma_add_to_cma_mem_list(cma, mem);
} else {
pr_debug("cma: cannot release partial block when order_per_bit != 0\n");
cma_add_to_cma_mem_list(cma, mem);
break;
}
}

return 0;
}

์—ญํ• : free ๋””๋ฒ„๊ทธ ํŒŒ์ผ์— ํŽ˜์ด์ง€ ์ˆ˜๋ฅผ ์“ฐ๋ฉด ํ• ๋‹น ๋ฆฌ์ŠคํŠธ์—์„œ ์ˆœ์ฐจ์ ์œผ๋กœ ๊บผ๋‚ด ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

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

1. mem->n <= count: ๋ธ”๋ก ์ „์ฒด๋ฅผ ํ•ด์ œ ํ›„ kfree(mem)

2. order_per_bit == 0์ด๊ณ  mem->n > count: ๋ถ€๋ถ„ ํ•ด์ œ ๊ฐ€๋Šฅ โ€” mem->p์™€ mem->n ๊ฐฑ์‹  ํ›„ ๋ฆฌ์ŠคํŠธ์— ๋‹ค์‹œ ์ถ”๊ฐ€

3. order_per_bit != 0์ด๊ณ  ๋ถ€๋ถ„ ํ•ด์ œ ๋ถˆ๊ฐ€: ๋””๋ฒ„๊ทธ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ํ›„ ์ค‘๋‹จ


ํ˜ธ์ถœ ํ๋ฆ„

DebugFS ์ดˆ๊ธฐํ™” ํ๋ฆ„

๋ถ€ํŒ… (late_initcall)
โ”‚
โ–ผ
cma_debugfs_init()
โ”‚
โ”œโ”€โ”€ debugfs_create_dir("cma", NULL)    โ† /sys/kernel/debug/cma/ ์ƒ์„ฑ
โ”‚
โ””โ”€โ”€ for (i = 0; i < cma_area_count; i++)
โ”‚
โ””โ”€โ”€ cma_debugfs_add_one(&cma_areas[i], root)
โ”‚
โ”œโ”€โ”€ debugfs_create_dir(cma->name)     โ† cma-0/, cma-1/, ...
โ”‚
โ”œโ”€โ”€ debugfs_create_file("alloc")      โ† ์“ฐ๊ธฐ ์ „์šฉ
โ”œโ”€โ”€ debugfs_create_file("free")       โ† ์“ฐ๊ธฐ ์ „์šฉ
โ”œโ”€โ”€ debugfs_create_file("count")      โ† ์ฝ๊ธฐ ์ „์šฉ
โ”œโ”€โ”€ debugfs_create_file("order_per_bit")
โ”œโ”€โ”€ debugfs_create_file("used")       โ† cma_used_get()
โ”œโ”€โ”€ debugfs_create_file("maxchunk")   โ† cma_maxchunk_get()
โ”‚
โ””โ”€โ”€ ranges/ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ
โ””โ”€โ”€ for (r = 0; r < nranges; r++)
โ”œโ”€โ”€ base_pfn ํŒŒ์ผ
โ””โ”€โ”€ bitmap u32 ๋ฐฐ์—ด

์ˆ˜๋™ ํ• ๋‹น/ํ•ด์ œ ํ๋ฆ„

์‚ฌ์šฉ์ž: echo 16 > /sys/kernel/debug/cma/cma-0/alloc
โ”‚
โ–ผ
cma_alloc_write(data=cma, val=16)
โ”‚
โ””โ”€โ”€ cma_alloc_mem(cma, 16)
โ”‚
โ”œโ”€โ”€ kzalloc_obj(*mem)           โ† cma_mem ํ• ๋‹น
โ”œโ”€โ”€ cma_alloc(cma, 16, 0, false) โ† ์‹ค์ œ CMA ํ• ๋‹น
โ”‚      โ””โ”€โ”€ cma_range_alloc()
โ”‚             โ”œโ”€โ”€ bitmap_find_next_zero_area_off()
โ”‚             โ”œโ”€โ”€ page_range_contiguous()
โ”‚             โ”œโ”€โ”€ bitmap_set()
โ”‚             โ””โ”€โ”€ alloc_contig_frozen_range()
โ”‚
โ””โ”€โ”€ cma_add_to_cma_mem_list()   โ† mem_head์— ์ถ”๊ฐ€

์‚ฌ์šฉ์ž: echo 16 > /sys/kernel/debug/cma/cma-0/free
โ”‚
โ–ผ
cma_free_write(data=cma, val=16)
โ”‚
โ””โ”€โ”€ cma_free_mem(cma, 16)
โ”‚
โ””โ”€โ”€ while (count)
โ”œโ”€โ”€ cma_get_entry_from_list()  โ† mem_head์—์„œ ๊บผ๋‚ด๊ธฐ
โ”‚
โ”œโ”€โ”€ mem->n <= count โ†’ cma_release() + kfree()
โ”œโ”€โ”€ order_per_bit == 0 โ†’ ๋ถ€๋ถ„ ํ•ด์ œ ๊ฐ€๋Šฅ
โ””โ”€โ”€ order_per_bit != 0 โ†’ ๋ถ€๋ถ„ ํ•ด์ œ ๋ถˆ๊ฐ€, ์ค‘๋‹จ

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

DebugFS ํŒŒ์ผ ์œ ํ˜• ๋น„๊ต

ํŒŒ์ผ๊ถŒํ•œ๋™์ž‘ํ•จ์ˆ˜
`alloc`0200 (์“ฐ๊ธฐ)ํŽ˜์ด์ง€ ์ˆ˜ ํ• ๋‹น`cma_alloc_write()` โ†’ `cma_alloc_mem()`
`free`0200 (์“ฐ๊ธฐ)ํŽ˜์ด์ง€ ์ˆ˜ ํ•ด์ œ`cma_free_write()` โ†’ `cma_free_mem()`
`count`0444 (์ฝ๊ธฐ)์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜์ง์ ‘ `&cma->count` ์ฝ๊ธฐ
`order_per_bit`0444 (์ฝ๊ธฐ)๋น„ํŠธ๋งต ํ•ด์ƒ๋„์ง์ ‘ `&cma->order_per_bit` ์ฝ๊ธฐ
`used`0444 (์ฝ๊ธฐ)์‚ฌ์šฉ ์ค‘์ธ ํŽ˜์ด์ง€ ์ˆ˜`cma_used_get()`
`maxchunk`0444 (์ฝ๊ธฐ)์ตœ๋Œ€ ์—ฐ์† ๋นˆ ๋ธ”๋ก`cma_maxchunk_get()`
`ranges/N/base_pfn`0444 (์ฝ๊ธฐ)๋ฒ”์œ„ ์‹œ์ž‘ PFN์ง์ ‘ `&cmr->base_pfn` ์ฝ๊ธฐ
`ranges/N/bitmap`0444 (์ฝ๊ธฐ)ํ• ๋‹น ๋น„ํŠธ๋งต (u32 ๋ฐฐ์—ด)`debugfs_create_u32_array()`

cma_free_mem() ๋ถ„๊ธฐ ๋น„๊ต

์กฐ๊ฑด๋™์ž‘๊ฒฐ๊ณผ
`mem->n <= count`๋ธ”๋ก ์ „์ฒด ํ•ด์ œ + `kfree(mem)`์™„์ „ ํ•ด์ œ
`order_per_bit == 0`ไธ” `mem->n > count`๋ถ€๋ถ„ ํ•ด์ œ (mem->p ๊ฐฑ์‹ )๋ถ€๋ถ„ ํ•ด์ œ ํ›„ ๋ฆฌ์ŠคํŠธ ๋ณต๊ท€
`order_per_bit != 0`ไธ” `mem->n > count`๋””๋ฒ„๊ทธ ๋ฉ”์‹œ์ง€ + ์ค‘๋‹จํ•ด์ œ ๋ถˆ๊ฐ€

CMA ๋””๋ฒ„๊น… ์ ‘๊ทผ ๋น„๊ต

์ ‘๊ทผ๋„๊ตฌ์šฉ๋„
**DebugFS**`/sys/kernel/debug/cma/`๋Ÿฐํƒ€์ž„ ์ƒํƒœ ๊ด€์ฐฐ, ์ˆ˜๋™ ํ…Œ์ŠคํŠธ
**sysfs**`/sys/sys/kernel/mm/cma/`ํ†ต๊ณ„ (์„ฑ๊ณต/์‹คํŒจ/ํ•ด์ œ ์นด์šดํ„ฐ)
**tracepoint**`cma:cma_alloc_start/finish`, `cma:cma_release`ํ• ๋‹น/ํ•ด์ œ ์ด๋ฒคํŠธ ์ถ”์ 
**dmesg**`dmesg \grep cma`์ดˆ๊ธฐํ™” ๋ฉ”์‹œ์ง€, ์—๋Ÿฌ ๋กœ๊ทธ

๊ด€๋ จ ๋ฌธ์„œ

  • 18-cma.html โ€” CMA ํ•ต์‹ฌ ๊ตฌํ˜„ (ํ• ๋‹น/ํ•ด์ œ/์ดˆ๊ธฐํ™”)
  • 01-page_alloc.html โ€” Buddy Allocator (CMA์˜ ํ•˜์œ„ ํ• ๋‹น์ž)
  • 11-compaction.html โ€” Memory Compaction (CMA ํ• ๋‹น ์‹œ ํŽ˜์ด์ง€ ์žฌ๋ฐฐ์น˜)
  • 20-migrate.html โ€” ํŽ˜์ด์ง€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (CMA์˜ ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜)

  • ์ฐธ๊ณ : DebugFS vs sysfs ํ†ต๊ณ„ ๋น„๊ต

    CMA๋Š” ๋‘ ๊ฐ€์ง€ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋Ÿฐํƒ€์ž„ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  • DebugFS (/sys/kernel/debug/cma/): ๋””๋ฒ„๊น…์šฉ. ์ˆ˜๋™ ํ• ๋‹น/ํ•ด์ œ, ๋น„ํŠธ๋งต ๋คํ”„, ๋ฉ€ํ‹ฐ ๋ ˆ์ธ์ง€ ์ƒ์„ธ ์ •๋ณด ์ œ๊ณต. CONFIG_CMA_DEBUGFS ํ•„์š”.
  • sysfs (/sys/sys/kernel/mm/cma/): ์šด์˜์šฉ. nr_pages_succeeded, nr_pages_failed, nr_pages_released ์นด์šดํ„ฐ๋งŒ ์ œ๊ณต. CONFIG_CMA_SYSFS ํ•„์š”.
  • ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” sysfs๋ฅผ, ๊ฐœ๋ฐœ/๋””๋ฒ„๊น… ํ™˜๊ฒฝ์—์„œ๋Š” DebugFS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.

    # sysfs ํ†ต๊ณ„ ํ™•์ธ (CONFIG_CMA_SYSFS)
    cat /sys/kernel/mm/cma/cma-0/nr_pages_succeeded
    cat /sys/kernel/mm/cma/cma-0/nr_pages_failed
    cat /sys/kernel/mm/cma/cma-0/nr_pages_released