ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ์ฃผ์ž… (HWPoison)

๊ฐœ์š” (Overview)

Linux ์ปค๋„์˜ ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ์ฃผ์ž… ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜(MCE: Machine Check Exception)๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. hwpoison-inject.c ๋ชจ๋“ˆ์€ debugfs ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ์ž„์˜์˜ ํŽ˜์ด์ง€ ํ”„๋ ˆ์ž„ ๋ฒˆํ˜ธ(PFN)์— ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜๋ฅผ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋ฉฐ, ์ด๋Š” ์ฃผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฅ˜ ๋ณต๊ตฌ ์‹œ์Šคํ…œ์˜ ํ…Œ์ŠคํŠธ ๋ฐ ๋””๋ฒ„๊น…์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์‹ค์ œ ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ปค๋„์ด ์–ด๋–ป๊ฒŒ ๋Œ€์‘ํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์ค‘์š”ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. memory_failure() ํ•จ์ˆ˜๋Š” ์‹ค์ œ ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ์˜ ํ•ต์‹ฌ์œผ๋กœ, ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ํŽ˜์ด์ง€๋ฅผ ๋ณต๊ตฌํ•˜๊ฑฐ๋‚˜ ๊ด€๋ จ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒํ•˜๋Š” ๋“ฑ์˜ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

corrupt-pfn๊ณผ unpoison-pfn์€ ํ•˜๋“œ์›จ์–ด ์ƒํƒœ๋ฅผ ์ง์ ‘ ๋ฐ”๊พธ์ง€ ์•Š๋Š” ์†Œํ”„ํŠธ์›จ์–ด ์ˆ˜์ค€ ์ธํ„ฐํŽ˜์ด์Šค๋ผ์„œ, ์žฅ์น˜ ์˜ค๋ฅ˜๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ ๋„ ์ฃผ์ž…๊ณผ ํ•ด์ œ๋ฅผ ๋ฐ˜๋ณตํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ:
โ”œโ”€โ”€ mm/hwpoison-inject.c      โ† ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ์ฃผ์ž… ๋ชจ๋“ˆ
โ”œโ”€โ”€ mm/memory-failure.c       โ† ์‹ค์ œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ์ฝ”์–ด
โ”œโ”€โ”€ mm/internal.h             โ† ๋‚ด๋ถ€ ํ•จ์ˆ˜ ์„ ์–ธ
โ””โ”€โ”€ include/linux/page-flags.h โ† PG_hwpoison ํ”Œ๋ž˜๊ทธ ์ •์˜

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

# hwpoison ๋ชจ๋“ˆ ์ƒํƒœ ํ™•์ธ
lsmod | grep hwpoison

# debugfs hwpoison ๋””๋ ‰ํ† ๋ฆฌ ํ™•์ธ
ls -la /sys/kernel/debug/hwpoison/

# ํ˜„์žฌ ํ•„ํ„ฐ ์„ค์ •๊ฐ’ ํ™•์ธ
cat /sys/kernel/debug/hwpoison/corrupt-filter-enable
cat /sys/kernel/debug/hwpoison/corrupt-filter-dev-major
cat /sys/kernel/debug/hwpoison/corrupt-filter-dev-minor
cat /sys/kernel/debug/hwpoison/corrupt-filter-flags-mask
cat /sys/kernel/debug/hwpoison/corrupt-filter-flags-value
cat /sys/kernel/debug/hwpoison/corrupt-filter-memcg

# ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ์ฃผ์ž… (PFN 0x12345์— ์˜ค๋ฅ˜ ์ฃผ์ž…)
echo 0x12345 > /sys/kernel/debug/hwpoison/corrupt-pfn

# ์˜ค๋ฅ˜ ์ฃผ์ž… ํ•„ํ„ฐ ํ™œ์„ฑํ™”
echo 1 > /sys/kernel/debug/hwpoison/corrupt-filter-enable

# ๋””๋ฐ”์ด์Šค ํ•„ํ„ฐ ์„ค์ • (๋ฉ”์ด์ € ๋ฒˆํ˜ธ 8)
echo 8 > /sys/kernel/debug/hwpoison/corrupt-filter-dev-major

# ๋ฉ”๋ชจ๋ฆฌ ๊ทธ๋ฃน ํ•„ํ„ฐ ์„ค์ •
echo 12345 > /sys/kernel/debug/hwpoison/corrupt-filter-memcg

# ์˜ค๋ฅ˜ ํ•ด์ œ (PFN 0x12345์˜ ์˜ค๋ฅ˜ ํ•ด์ œ)
echo 0x12345 > /sys/kernel/debug/hwpoison/unpoison-pfn

# ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฅ˜ ์ด๋ ฅ ํ™•์ธ
dmesg | grep -i "memory failure"

# hwpoison ํŽ˜์ด์ง€ ์ˆ˜ ํ™•์ธ
cat /proc/meminfo | grep -i hwpoison

# ์‹ค์ œ ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ๋กœ๊ทธ ํ™•์ธ
dmesg | grep -i "mce\|machine check"

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

1. `hwpoison_filter_enable` (mm/hwpoison-inject.c:14)

static u32 hwpoison_filter_enable;
// ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ํ•„ํ„ฐ ํ™œ์„ฑํ™” ์ƒํƒœ
// 0: ํ•„ํ„ฐ ๋น„ํ™œ์„ฑํ™” (๋ชจ๋“  ํŽ˜์ด์ง€์— ์˜ค๋ฅ˜ ์ฃผ์ž…)
// 1: ํ•„ํ„ฐ ํ™œ์„ฑํ™” (์ง€์ •๋œ ์กฐ๊ฑด์˜ ํŽ˜์ด์ง€์—๋งŒ ์˜ค๋ฅ˜ ์ฃผ์ž…)

2. `hwpoison_filter_dev_major/minor` (mm/hwpoison-inject.c:15-16)

static u32 hwpoison_filter_dev_major = ~0U;
static u32 hwpoison_filter_dev_minor = ~0U;
// ๋””๋ฐ”์ด์Šค ๋ฒˆํ˜ธ ํ•„ํ„ฐ (๋ฉ”์ด์ €/๋งˆ์ด๋„ˆ ๋ฒˆํ˜ธ)
// ~0U: ํ•„ํ„ฐ ๋ฏธ์„ค์ • (๋ชจ๋“  ๋””๋ฐ”์ด์Šค ํ—ˆ์šฉ)

3. `hwpoison_filter_flags_mask/value` (mm/hwpoison-inject.c:17-18)

static u64 hwpoison_filter_flags_mask;
static u64 hwpoison_filter_flags_value;
// ํŽ˜์ด์ง€ ํ”Œ๋ž˜๊ทธ ํ•„ํ„ฐ
// mask: ๊ฒ€์‚ฌํ•  ํ”Œ๋ž˜๊ทธ ๋งˆ์Šคํฌ
// value: ์ผ์น˜ํ•ด์•ผ ํ•˜๋Š” ํ”Œ๋ž˜๊ทธ ๊ฐ’

4. `hwpoison_filter_memcg` (mm/hwpoison-inject.c:68)

static u64 hwpoison_filter_memcg;
// ๋ฉ”๋ชจ๋ฆฌ cgroup ํ•„ํ„ฐ
// 0: ํ•„ํ„ฐ ๋ฏธ์„ค์ • (๋ชจ๋“  cgroup ํ—ˆ์šฉ)
// non-zero: ์ง€์ •๋œ cgroup์˜ ํŽ˜์ด์ง€์—๋งŒ ์˜ค๋ฅ˜ ์ฃผ์ž…

5. `PG_hwpoison` (include/linux/page-flags.h:118)

PG_hwpoison,        /* ํ•˜๋“œ์›จ์–ด๋กœ ์†์ƒ๋œ ํŽ˜์ด์ง€. ์†๋Œ€์ง€ ๋ง ๊ฒƒ */
// ํŽ˜์ด์ง€ ํ”Œ๋ž˜๊ทธ ์ค‘ ํ•˜๋‚˜๋กœ, ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ํŽ˜์ด์ง€์— ์„ค์ •๋จ

6. `PG_has_hwpoisoned` (include/linux/page-flags.h:192)

PG_has_hwpoisoned = PG_active,
// ๋ณตํ•ฉ ํŽ˜์ด์ง€(THP ๋“ฑ) ๋‚ด์— hwpoison๋œ ์„œ๋ธŒํŽ˜์ด์ง€๊ฐ€ ํ•˜๋‚˜ ์ด์ƒ ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ„

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

1. `hwpoison_inject()` (mm/hwpoison-inject.c:102-142)

static int hwpoison_inject(void *data, u64 val)
{
unsigned long pfn = val;
struct page *p;
struct folio *folio;
int err;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;

if (!pfn_valid(pfn))
return -ENXIO;

p = pfn_to_page(pfn);
folio = page_folio(p);

if (!hwpoison_filter_enable)
goto inject;

shake_folio(folio);
/* ๋น„-LRU ํŽ˜์ด์ง€๋Š” free page๋ฅผ ์ œ์™ธํ•˜๊ณ  ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. */
if (!folio_test_lru(folio) && !folio_test_hugetlb(folio) &&
!is_free_buddy_page(p))
return 0;

/* ๋Œ€์ƒ ์†Œ์œ ์ž๋งŒ PG_hwpoison์ด ์žกํžˆ๋„๋ก ๋จผ์ € ๋А์Šจํ•œ ๊ฒ€์‚ฌ๋ฅผ ํ•œ๋‹ค. */
err = hwpoison_filter(&folio->page);
if (err)
return 0;

inject:
pr_info("Injecting memory failure at pfn %#lx\n", pfn);
err = memory_failure(pfn, MF_SW_SIMULATED);
return (err == -EOPNOTSUPP) ? 0 : err;
}
// debugfs๋ฅผ ํ†ตํ•ด ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ํ•จ์ˆ˜
// PFN: ์ฃผ์ž…ํ•  ํŽ˜์ด์ง€ ํ”„๋ ˆ์ž„ ๋ฒˆํ˜ธ
// MF_SW_SIMULATED: ์†Œํ”„ํŠธ์›จ์–ด ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ”Œ๋ž˜๊ทธ

2. `hwpoison_filter()` (mm/hwpoison-inject.c:83-98)

static int hwpoison_filter(struct page *p)
{
if (!hwpoison_filter_enable)
return 0;

if (hwpoison_filter_dev(p))
return -EINVAL;

if (hwpoison_filter_flags(p))
return -EINVAL;

if (hwpoison_filter_task(p))
return -EINVAL;

return 0;
}
// ํŽ˜์ด์ง€๊ฐ€ ์„ค์ •๋œ ํ•„ํ„ฐ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ๊ฒ€์‚ฌ
// 0: ํ•„ํ„ฐ ํ†ต๊ณผ (์˜ค๋ฅ˜ ์ฃผ์ž… ํ—ˆ์šฉ)
// -EINVAL: ํ•„ํ„ฐ ์‹คํŒจ (์˜ค๋ฅ˜ ์ฃผ์ž… ๊ฑฐ๋ถ€)

3. `memory_failure()` (mm/memory-failure.c:2388-2558)

try_memory_failure_hugetlb()๋Š” HugeTLB๋ฅผ ๋จผ์ € ๋ถ„๊ธฐํ•˜๊ณ , take_page_off_buddy()๋Š” free buddy page๋ฅผ ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜ ํŽ˜์ด์ง€๋Š” hwpoison_user_mappings()๋กœ ๋งคํ•‘์„ ์ •๋ฆฌํ•œ ๋’ค identify_page_state()๋กœ ์ตœ์ข… ํŒ์ •์„ ๋‚ด๋ฆฝ๋‹ˆ๋‹ค.

try_again:
res = try_memory_failure_hugetlb(pfn, flags, &hugetlb);
if (hugetlb)
goto unlock_mutex;

if (TestSetPageHWPoison(p)) {
res = -EHWPOISON;
if (flags & MF_ACTION_REQUIRED)
res = kill_accessing_process(current, pfn, flags);
if (flags & MF_COUNT_INCREASED)
put_page(p);
action_result(pfn, MF_MSG_ALREADY_POISONED, MF_FAILED);
goto unlock_mutex;
}

res = get_hwpoison_page(p, flags);
if (!res) {
if (is_free_buddy_page(p)) {
if (take_page_off_buddy(p)) {
page_ref_inc(p);
res = MF_RECOVERED;
} else {
if (retry) {
ClearPageHWPoison(p);
retry = false;
goto try_again;
}
res = MF_FAILED;
}
res = action_result(pfn, MF_MSG_BUDDY, res);
} else {
res = action_result(pfn, MF_MSG_KERNEL_HIGH_ORDER, MF_IGNORED);
}
goto unlock_mutex;
} else if (res < 0) {
res = action_result(pfn, MF_MSG_GET_HWPOISON, MF_IGNORED);
goto unlock_mutex;
}

folio = page_folio(p);

folio_lock(folio);
if (hwpoison_filter(p)) {
ClearPageHWPoison(p);
folio_unlock(folio);
folio_put(folio);
res = -EOPNOTSUPP;
goto unlock_mutex;
}
folio_unlock(folio);

if (folio_test_large(folio)) {
const int new_order = min_order_for_split(folio);
int err;

folio_set_has_hwpoisoned(folio);
err = try_to_split_thp_page(p, new_order, false);
if (err || new_order) {
folio = page_folio(p);
res = -EHWPOISON;
kill_procs_now(p, pfn, flags, folio);
put_page(p);
action_result(pfn, MF_MSG_UNSPLIT_THP, MF_FAILED);
goto unlock_mutex;
}
VM_BUG_ON_PAGE(!page_count(p), p);
folio = page_folio(p);
}

shake_folio(folio);

folio_lock(folio);

WARN_ON(folio_test_large(folio));

page_flags = folio->flags.f;

if (!folio_test_lru(folio) && !folio_test_writeback(folio))
goto identify_page_state;

folio_wait_writeback(folio);

if (!hwpoison_user_mappings(folio, p, pfn, flags)) {
res = action_result(pfn, MF_MSG_UNMAP_FAILED, MF_FAILED);
goto unlock_page;
}

if (folio_test_lru(folio) && !folio_test_swapcache(folio) &&
folio->mapping == NULL) {
res = action_result(pfn, MF_MSG_TRUNCATED_LRU, MF_IGNORED);
goto unlock_page;
}

identify_page_state:
res = identify_page_state(pfn, p, page_flags);
mutex_unlock(&mf_mutex);
return res;
unlock_page:
folio_unlock(folio);
unlock_mutex:
mutex_unlock(&mf_mutex);
return res;
}

4. `hwpoison_unpoison()` (mm/hwpoison-inject.c:144-150)

static int hwpoison_unpoison(void *data, u64 val)
{
if (!capable(CAP_SYS_ADMIN))
return -EPERM;

return unpoison_memory(val);
}
// hwpoison ์ƒํƒœ๋ฅผ ํ•ด์ œํ•˜๋Š” ํ•จ์ˆ˜
// val: ํ•ด์ œํ•  ํŽ˜์ด์ง€ ํ”„๋ ˆ์ž„ ๋ฒˆํ˜ธ

5. `pfn_inject_init()` (mm/hwpoison-inject.c:162-200)

static int __init pfn_inject_init(void)
{
hwpoison_dir = debugfs_create_dir("hwpoison", NULL);

/* ์•„๋ž˜ poison/unpoison ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํ•˜๋“œ์›จ์–ด ์ƒํƒœ๋ฅผ ์ง์ ‘ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค. */
/* ํ•˜๋“œ์›จ์–ด ์ง€์›์ด ์—†์–ด๋„ ์†Œํ”„ํŠธ์›จ์–ด ์ˆ˜์ค€ ํ…Œ์ŠคํŠธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. */
debugfs_create_file("corrupt-pfn", 0200, hwpoison_dir, NULL,
&hwpoison_fops);

debugfs_create_file("unpoison-pfn", 0200, hwpoison_dir, NULL,
&unpoison_fops);

debugfs_create_u32("corrupt-filter-enable", 0600, hwpoison_dir,
&hwpoison_filter_enable);

debugfs_create_u32("corrupt-filter-dev-major", 0600, hwpoison_dir,
&hwpoison_filter_dev_major);

debugfs_create_u32("corrupt-filter-dev-minor", 0600, hwpoison_dir,
&hwpoison_filter_dev_minor);

debugfs_create_u64("corrupt-filter-flags-mask", 0600, hwpoison_dir,
&hwpoison_filter_flags_mask);

debugfs_create_u64("corrupt-filter-flags-value", 0600, hwpoison_dir,
&hwpoison_filter_flags_value);

#ifdef CONFIG_MEMCG
debugfs_create_u64("corrupt-filter-memcg", 0600, hwpoison_dir,
&hwpoison_filter_memcg);
#endif

hwpoison_filter_register(hwpoison_filter);

return 0;
}
// ๋ชจ๋“ˆ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜ - debugfs ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ

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

1. hwpoison_inject() โ† debugfs ์“ฐ๊ธฐ ํŠธ๋ฆฌ๊ฑฐ
โ”œโ”€โ”€ capable(CAP_SYS_ADMIN) ํ™•์ธ
โ”œโ”€โ”€ pfn_valid(pfn) ํ™•์ธ
โ”œโ”€โ”€ pfn_to_page(pfn) โ†’ ํŽ˜์ด์ง€ ๋ณ€ํ™˜
โ”œโ”€โ”€ hwpoison_filter_enable ํ™•์ธ
โ”‚   โ”œโ”€โ”€ shake_folio(folio) โ†’ ํŽ˜์ด์ง€ ์บ์‹œ์—์„œ ์ œ๊ฑฐ
โ”‚   โ”œโ”€โ”€ folio_test_lru()/folio_test_hugetlb()/is_free_buddy_page() ๊ฒ€์‚ฌ
โ”‚   โ””โ”€โ”€ hwpoison_filter() โ†’ ํ•„ํ„ฐ ์กฐ๊ฑด ๊ฒ€์‚ฌ
โ””โ”€โ”€ memory_failure(pfn, MF_SW_SIMULATED) โ†’ ์‹ค์ œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

2. memory_failure() โ† ์‹ค์ œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ
โ”œโ”€โ”€ mutex_lock(&mf_mutex) โ†’ ์ „์—ญ ๋ฎคํ…์Šค ํš๋“
โ”œโ”€โ”€ pfn_to_online_page(pfn) โ†’ ์˜จ๋ผ์ธ ํŽ˜์ด์ง€ ํ™•์ธ
โ”œโ”€โ”€ try_memory_failure_hugetlb() โ†’ HugeTLB ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ
โ”œโ”€โ”€ TestSetPageHWPoison(p) โ†’ hwpoison ํ”Œ๋ž˜๊ทธ ์„ค์ •
โ”œโ”€โ”€ get_hwpoison_page() โ†’ ํŽ˜์ด์ง€ ์ฐธ์กฐ ์นด์šดํŠธ ์ฆ๊ฐ€
โ”œโ”€โ”€ hwpoison_filter(p) โ†’ ํ•„ํ„ฐ ์žฌ๊ฒ€์‚ฌ
โ”œโ”€โ”€ folio_test_large(folio) โ†’ THP ๋ถ„ํ•  ์ฒ˜๋ฆฌ
โ”œโ”€โ”€ shake_folio(folio) โ†’ ํŽ˜์ด์ง€ ์บ์‹œ์—์„œ ์ œ๊ฑฐ
โ”œโ”€โ”€ hwpoison_user_mappings() โ†’ ์‚ฌ์šฉ์ž ๋งคํ•‘ ํ•ด์ œ
โ””โ”€โ”€ action_result() โ†’ ๊ฒฐ๊ณผ ๊ธฐ๋ก

3. hwpoison_filter() โ† ํ•„ํ„ฐ ์ฒดํฌ
โ”œโ”€โ”€ hwpoison_filter_dev(p) โ†’ ๋””๋ฐ”์ด์Šค ๋ฒˆํ˜ธ ๊ฒ€์‚ฌ
โ”œโ”€โ”€ hwpoison_filter_flags(p) โ†’ ํŽ˜์ด์ง€ ํ”Œ๋ž˜๊ทธ ๊ฒ€์‚ฌ
โ””โ”€โ”€ hwpoison_filter_task(p) โ†’ ๋ฉ”๋ชจ๋ฆฌ cgroup ๊ฒ€์‚ฌ
HWPoison ํ˜ธ์ถœ ํ๋ฆ„

memory_failure()๋Š” ํ˜„์žฌ ํŽ˜์ด์ง€ ํ”Œ๋ž˜๊ทธ๋ฅผ ๋จผ์ € ํ™•์ธํ•˜๊ณ , ๋ถ„๋ฅ˜๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์œผ๋ฉด ์ €์žฅํ•ด ๋‘” page_flags ์Šค๋ƒ…์ƒท์œผ๋กœ ๋‹ค์‹œ ํŒ์ •ํ•ฉ๋‹ˆ๋‹ค.


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

1. hwpoison ์ฃผ์ž… ๊ฒฝ๋กœ ๋น„๊ต

์กฐ๊ฑดhwpoison_injectmemory_failure๋น„๊ณ 
ํŠธ๋ฆฌ๊ฑฐdebugfs ์“ฐ๊ธฐํ•˜๋“œ์›จ์–ด MCE์†Œํ”„ํŠธ์›จ์–ด vs ํ•˜๋“œ์›จ์–ด
๊ถŒํ•œCAP_SYS_ADMIN์ปค๋„ ๋‚ด๋ถ€์‚ฌ์šฉ์ž ๊ณต๊ฐ„ vs ์ปค๋„ ๊ณต๊ฐ„
๋Œ€์ƒ์ž„์˜ PFN์˜ค๋ฅ˜ ๊ฐ์ง€๋œ ํŽ˜์ด์ง€์„ ํƒ์  vs ์ž๋™
ํ”Œ๋ž˜๊ทธMF_SW_SIMULATEDMF_ACTION_REQUIRED ๋“ฑ์‹œ๋ฎฌ๋ ˆ์ด์…˜ vs ์‹ค์ œ

2. ํ•„ํ„ฐ ๋™์ž‘ ๋น„๊ต

ํ•„ํ„ฐ ํƒ€์ž…์„ค์ • ํŒŒ์ผ๋™์ž‘๋น„๊ณ 
๋””๋ฐ”์ด์Šคcorrupt-filter-dev-major/minorํŠน์ • ๋””๋ฐ”์ด์Šค์˜ ํŽ˜์ด์ง€๋งŒ ์˜ค๋ฅ˜ ์ฃผ์ž…ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ด€๋ จ
ํ”Œ๋ž˜๊ทธcorrupt-filter-flags-mask/valueํŠน์ • ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ฐ€์ง„ ํŽ˜์ด์ง€๋งŒ ์˜ค๋ฅ˜ ์ฃผ์ž…ํŽ˜์ด์ง€ ์ƒํƒœ ๊ธฐ๋ฐ˜
๋ฉ”๋ชจ๋ฆฌ cgroupcorrupt-filter-memcgํŠน์ • cgroup์˜ ํŽ˜์ด์ง€๋งŒ ์˜ค๋ฅ˜ ์ฃผ์ž…ํ”„๋กœ์„ธ์Šค ๊ฒฉ๋ฆฌ
์ „์ฒดcorrupt-filter-enableํ•„ํ„ฐ ์ „์ฒด ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™”์Šค์œ„์น˜ ์—ญํ• 

3. ํŽ˜์ด์ง€ ์ƒํƒœ๋ณ„ ์ฒ˜๋ฆฌ

ํŽ˜์ด์ง€ ์ƒํƒœ์ฒ˜๋ฆฌ ๋ฐฉ์‹ํ•จ์ˆ˜๋น„๊ณ 
LRU ํŽ˜์ด์ง€hwpoison ์ฒ˜๋ฆฌhwpoison_user_mappings()์ผ๋ฐ˜ ๋ฉ”๋ชจ๋ฆฌ ํŽ˜์ด์ง€
HugeTLB ํŽ˜์ด์ง€ํŠน์ˆ˜ ์ฒ˜๋ฆฌtry_memory_failure_hugetlb()Huge Page ์ง€์›
๋น„-LRU ๊ณ ์ฐจ ํŽ˜์ด์ง€์˜ค๋ฅ˜ ๋ฌด์‹œaction_result(MF_MSG_KERNEL_HIGH_ORDER, MF_IGNORED)์ปค๋„์ด ์ง์ ‘ ์“ฐ๋Š” ํŽ˜์ด์ง€
free ํŽ˜์ด์ง€buddy์—์„œ ์ œ๊ฑฐtake_page_off_buddy()๋นˆ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ

๊ด€๋ จ ๋ฌธ์„œ

  • 27-debug.html โ€” ๋””๋ฒ„๊ทธ ๋„๊ตฌ (KASAN, KFENCE, Kmemleak)
  • 08-oom.html โ€” OOM Killer
  • 05-page_reclaim.html โ€” ํŽ˜์ด์ง€ ํšŒ์ˆ˜
  • 22-memory_hotplug.html โ€” ๋ฉ”๋ชจ๋ฆฌ ํ•ซํ”Œ๋Ÿฌ๊ทธ

  • ์ฐธ๊ณ  ์‚ฌํ•ญ

    1. hwpoison ์ฃผ์ž… ์‹œ๋‚˜๋ฆฌ์˜ค

    # ์‹œ๋‚˜๋ฆฌ์˜ค 1: ํŠน์ • ํŽ˜์ด์ง€์— ์˜ค๋ฅ˜ ์ฃผ์ž…
    echo 0x100000 > /sys/kernel/debug/hwpoison/corrupt-pfn
    
    # ์‹œ๋‚˜๋ฆฌ์˜ค 2: ๋””๋ฐ”์ด์Šค ํ•„ํ„ฐ์™€ ํ•จ๊ป˜ ์˜ค๋ฅ˜ ์ฃผ์ž…
    echo 1 > /sys/kernel/debug/hwpoison/corrupt-filter-enable
    echo 8 > /sys/kernel/debug/hwpoison/corrupt-filter-dev-major
    echo 0x100000 > /sys/kernel/debug/hwpoison/corrupt-pfn
    
    # ์‹œ๋‚˜๋ฆฌ์˜ค 3: ๋ฉ”๋ชจ๋ฆฌ cgroup ํ•„ํ„ฐ์™€ ํ•จ๊ป˜ ์˜ค๋ฅ˜ ์ฃผ์ž…
    echo 1 > /sys/kernel/debug/hwpoison/corrupt-filter-enable
    echo 12345 > /sys/kernel/debug/hwpoison/corrupt-filter-memcg
    echo 0x100000 > /sys/kernel/debug/hwpoison/corrupt-pfn

    2. hwpoison ๋””๋ฒ„๊น… ํŒ

    # hwpoison ๊ด€๋ จ ๋กœ๊ทธ ์ƒ์„ธ ํ™•์ธ
    echo 8 > /proc/sys/kernel/printk
    dmesg -w | grep -i "memory failure\|hwpoison\|mce"
    
    # ํŽ˜์ด์ง€ ํ”Œ๋ž˜๊ทธ ํ™•์ธ (hwpoison ์ƒํƒœ ํ™•์ธ)
    cat /proc/kpageflags | grep -i hwpoison
    
    # ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฅ˜ ์ด๋ ฅ ํ™•์ธ
    cat /sys/devices/system/memory/soft_offline_page
    
    # hwpoison ํŽ˜์ด์ง€ ์ˆ˜ ํ™•์ธ
    cat /proc/vmstat | grep -i hwpoison

    3. hwpoison๊ณผ ๊ด€๋ จ๋œ ์ปค๋„ ์ปจํ”ผ๊ทธ ์˜ต์…˜

    # CONFIG_MEMORY_FAILURE: ํ•˜๋“œ์›จ์–ด ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ํ™œ์„ฑํ™”
    # CONFIG_HWPOISON_INJECT: hwpoison ์ฃผ์ž… ๋ชจ๋“ˆ ํ™œ์„ฑํ™”
    # CONFIG_MCE: Machine Check Exception ์ง€์›
    # CONFIG_X86_MCE: x86 MCE ์ง€์›