virtio-mem ๊ฐ€์ƒํ™”

๊ด€๋ จ ์†Œ์Šค: drivers/virtio/virtio_mem.c, include/uapi/linux/virtio_mem.h, mm/memory_hotplug.c

๊ฐœ์š” (Overview)

virtio-mem์€ ๊ฐ€์ƒ๋จธ์‹ (VM)์—์„œ ํ˜ธ์ŠคํŠธ(ํ•˜์ดํผ๋ฐ”์ด์ €)์— ์˜ํ•ด ๋™์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š” Virtio ๋“œ๋ผ์ด๋ฒ„์ž…๋‹ˆ๋‹ค. ๊ธฐ์กด virtio-balloon์ด "ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋นŒ๋ ค์ฃผ๋Š”" ๋ฐฉ์‹์ธ ๋ฐ˜๋ฉด, virtio-mem์€ ๋ฌผ๋ฆฌ์  DIMM์„ ๋™์ ์œผ๋กœ ํฌ๊ธฐ ์กฐ์ ˆํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์น˜ ๋ฐ์Šคํฌํ†ฑ ์ปดํ“จํ„ฐ์˜ RAM ์Šฌ๋กฏ์— DIMM์„ ๋ผ์› ๋‹ค ๋บ๋‹ค ํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ, ์ด๊ฒƒ์ด ์†Œํ”„ํŠธ์›จ์–ด์ ์œผ๋กœ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.

๊ฒŒ์ŠคํŠธ OS๋Š” virtio-mem ๋“œ๋ผ์ด๋ฒ„๋ฅผ ํ†ตํ•ด ํ•˜์ดํผ๋ฐ”์ด์ €์—๊ฒŒ "์ด ํฌ๊ธฐ๋งŒํผ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋”ํ•ด์ค˜" ๋˜๋Š” "์ด ํฌ๊ธฐ๋งŒํผ ์ค„์—ฌ์ค˜"๋ผ๊ณ  ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ดํผ๋ฐ”์ด์ €๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์‹ค์ œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ฑฐ๋‚˜ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค. ๋“œ๋ผ์ด๋ฒ„๋Š” add_memory_driver_managed()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปค๋„์˜ ๋ฉ”๋ชจ๋ฆฌ ํ•ซํ”Œ๋Ÿฌ๊ทธ ์ธํ”„๋ผ์™€ ์—ฐ๋™ํ•˜๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ๋‹จ์œ„๋กœ ์˜จ๋ผ์ธ/์˜คํ”„๋ผ์ธ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

virtio-mem์€ ๋‘ ๊ฐ€์ง€ ๋™์ž‘ ๋ชจ๋“œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค: SBM(Sub Block Mode)์€ ํ•˜๋‚˜์˜ Linux ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์„ ๋” ์ž‘์€ ์„œ๋ธŒ๋ธ”๋ก์œผ๋กœ ๋‚˜๋ˆ„์–ด ์„ธ๋ฐ€ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ณ , BBM(Big Block Mode)์€ ํฐ ๋ธ”๋ก ๋‹จ์œ„๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“œ๋Š” ์žฅ์น˜ ๋ธ”๋ก ํฌ๊ธฐ์™€ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ํฌ๊ธฐ์— ๋”ฐ๋ผ ์ž๋™ ์„ ํƒ๋ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ ์˜ฌ๋ผ์˜ค๋Š” ํŽ˜์ด์ง€๋Š” memory_hotplug.c์˜ ์˜จ๋ผ์ธ ์ฝœ๋ฐฑ ๊ฒฝ๋กœ๋ฅผ ๊ฑฐ์น˜๋ฏ€๋กœ, virtio-mem ์˜์—ญ์ด๋ฉด ๋จผ์ € ์ „์šฉ fake-offline ํŒ๋‹จ์„ ๋ฐ›๊ณ  ๊ทธ ๋’ค ์ผ๋ฐ˜ ์˜จ๋ผ์ธ ๊ฒฝ๋กœ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

virtio-mem ์ž๋ฃŒ๊ตฌ์กฐ ๊ด€๊ณ„๋„
virtio-mem ํ˜ธ์ถœ ํ๋ฆ„๋„

์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ

drivers/virtio/virtio_mem.c            โ† virtio-mem ๋“œ๋ผ์ด๋ฒ„ ๊ตฌํ˜„ (3156์ค„)
include/uapi/linux/virtio_mem.h       โ† virtio ํ”„๋กœํ† ์ฝœ ์ •์˜
mm/memory_hotplug.c                    โ† add_memory_driver_managed(), remove_memory()

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

# virtio-mem ๋ชจ๋“ˆ ์ƒํƒœ ํ™•์ธ
lsmod | grep virtio_mem

# virtio ๋””๋ฐ”์ด์Šค ๋ชฉ๋ก์—์„œ mem ๋””๋ฐ”์ด์Šค ํ™•์ธ
lspci | grep -i virtio

# ๋ฉ”๋ชจ๋ฆฌ ํ•ซํ”Œ๋Ÿฌ๊ทธ ์ƒํƒœ
cat /sys/devices/system/memory/block_size_bytes

# ํ˜„์žฌ ์˜จ๋ผ์ธ๋œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ์ˆ˜
ls /sys/devices/system/memory/ | grep memory | wc -l

# /proc/iomem์—์„œ virtio_mem ๋ฆฌ์†Œ์Šค ํ™•์ธ
grep -i virtio_mem /proc/iomem

# ๊ฒŒ์ŠคํŠธ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ์ƒํƒœ ํ™•์ธ
for f in /sys/devices/system/memory/memory*/state; do echo "$f: $(cat $f)"; done

# dmesg์—์„œ virtio-mem ๊ด€๋ จ ๋กœ๊ทธ
dmesg | grep -i "virtio.*mem"

# ๋ฉ”๋ชจ๋ฆฌ ๊ทธ๋ฃน (memory group) ํ™•์ธ
cat /sys/kernel/debug/memory_groups 2>/dev/null || echo "CONFIG_DEBUG_MEMORY_GROUPS ๋ฏธํ™œ์„ฑํ™”"

# ์˜คํ”„๋ผ์ธ๋œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ์ˆ˜ ํ™•์ธ
cat /sys/devices/system/memory/removable

# ZONE_MOVABLE ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ ํ™•์ธ
grep -i movable /proc/zoneinfo | head -5

# ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ํฌ๊ธฐ
cat /sys/devices/system/memory/block_size_bytes

# ์ž๋™ ์˜จ๋ผ์ธ ๋ธ”๋ก ์ •์ฑ…
cat /sys/devices/system/memory/auto_online_blocks 2>/dev/null

# memory_hotplug ๋ชจ๋“ˆ ํŒŒ๋ผ๋ฏธํ„ฐ
cat /sys/module/memory_hotplug/parameters/online_policy 2>/dev/null
cat /sys/module/memory_hotplug/parameters/memmap_on_memory 2>/dev/null

# ๋ฉ”๋ชจ๋ฆฌ ์••๋ ฅ๊ณผ ํšŒ์ˆ˜ ์ƒํƒœ
cat /proc/pressure/memory
cat /proc/buddyinfo
cat /proc/vmstat | grep -E 'allocstall|pgscan|pgsteal|pgfault|pgmajfault'

# ๋ฌผ๋ฆฌ ์ฃผ์†Œ ๋ฐฐ์น˜์™€ NUMA ๋ฐฐ์น˜
cat /proc/iomem | grep -Ei 'virtio|System RAM'
lsmem 2>/dev/null
numactl -H 2>/dev/null

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

struct virtio_mem

drivers/virtio/virtio_mem.c:102 โ€” virtio-mem ๋“œ๋ผ์ด๋ฒ„์˜ ๋ฉ”์ธ ๊ตฌ์กฐ์ฒด

struct virtio_mem {
struct virtio_device *vdev;       // Virtio ๋””๋ฐ”์ด์Šค ํฌ์ธํ„ฐ

bool unplug_all_required;         // ์‹œ์ž‘ ์‹œ ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์–ธํ”Œ๋Ÿฌ๊ทธ ํ•„์š” ์—ฌ๋ถ€
struct work_struct wq;            // plug/unplug ์š”์ฒญ ์ฒ˜๋ฆฌ ์›Œํฌํ
atomic_t wq_active;               // ์›Œํฌํ ํ™œ์„ฑ ์ƒํƒœ

struct virtqueue *vq;             // ๊ฒŒ์ŠคํŠธโ†’ํ˜ธ์ŠคํŠธ virtqueue
wait_queue_head_t host_resp;      // ํ˜ธ์ŠคํŠธ ์‘๋‹ต ๋Œ€๊ธฐ ํ

uint64_t plugged_size;            // ํ˜„์žฌ ํ”Œ๋Ÿฌ๊ทธ๋œ ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ
uint64_t requested_size;          // ํ˜ธ์ŠคํŠธ๊ฐ€ ์š”์ฒญํ•œ ๋ชฉํ‘œ ํฌ๊ธฐ

uint64_t device_block_size;       // ์žฅ์น˜ ๋ธ”๋ก ํฌ๊ธฐ (ํ˜ธ์ŠคํŠธ์™€์˜ ํ†ต์‹  ๋‹จ์œ„)
int nid;                          // NUMA ๋…ธ๋“œ ID
uint64_t addr;                    // ๋ฌผ๋ฆฌ ์‹œ์ž‘ ์ฃผ์†Œ
uint64_t region_size;             // ์ตœ๋Œ€ ๋ฆฌ์ „ ํฌ๊ธฐ
uint64_t usable_region_size;      // ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์ „ ํฌ๊ธฐ

struct resource *parent_resource; // ๋ถ€๋ชจ ๋ฆฌ์†Œ์Šค (๋“œ๋ผ์ด๋ฒ„ ๊ด€๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ)
int mgid;                         // ๋ฉ”๋ชจ๋ฆฌ ๊ทธ๋ฃน ID

atomic64_t offline_size;          // ์˜คํ”„๋ผ์ธ๋œ ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ
uint64_t offline_threshold;       // ์˜คํ”„๋ผ์ธ ์ž„๊ณ„๊ฐ’ (๊ธฐ๋ณธ 1GB)

bool in_sbm;                      // SBM ๋ชจ๋“œ ์—ฌ๋ถ€ (false๋ฉด BBM)

union {
struct { /* SBM ์ „์šฉ ํ•„๋“œ */ } sbm;
struct { /* BBM ์ „์šฉ ํ•„๋“œ */ } bbm;
};

struct mutex hotplug_mutex;       // ํ•ซํ”Œ๋Ÿฌ๊ทธ ๋™๊ธฐํ™” ๋ฎคํ…์Šค
struct hrtimer retry_timer;       // ์žฌ์‹œ๋„ ํƒ€์ด๋จธ (50์ดˆ~300์ดˆ)
struct notifier_block memory_notifier;  // ๋ฉ”๋ชจ๋ฆฌ ์˜จ๋ผ์ธ/์˜คํ”„๋ผ์ธ ์•Œ๋ฆผ
struct notifier_block pm_notifier;      // ์ „์› ๊ด€๋ฆฌ ์•Œ๋ฆผ
};
  • offline_threshold: ์˜คํ”„๋ผ์ธ๋œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ด ์ž„๊ณ„๊ฐ’์„ ์ดˆ๊ณผํ•˜๋ฉด ๋” ์ด์ƒ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. OOM์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์žฅ์น˜์ž…๋‹ˆ๋‹ค.
  • in_sbm: sb_size < memory_block_size_bytes()์ด๊ณ  force_bbm์ด false์ด๋ฉด SBM ๋ชจ๋“œ๊ฐ€ ์„ ํƒ๋ฉ๋‹ˆ๋‹ค.
  • enum virtio_mem_sbm_mb_state

    drivers/virtio/virtio_mem.c:67 โ€” SBM์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์˜ ์ƒํƒœ

    enum virtio_mem_sbm_mb_state {
    VIRTIO_MEM_SBM_MB_UNUSED = 0,           // ๋ฏธ์‚ฌ์šฉ, ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    VIRTIO_MEM_SBM_MB_PLUGGED,              // ํ”Œ๋Ÿฌ๊ทธ๋จ, Linux์— ๋ฏธ์ถ”๊ฐ€
    VIRTIO_MEM_SBM_MB_OFFLINE,              // ์™„์ „ ํ”Œ๋Ÿฌ๊ทธ, Linux ์ถ”๊ฐ€, ์˜คํ”„๋ผ์ธ
    VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL,      // ๋ถ€๋ถ„ ํ”Œ๋Ÿฌ๊ทธ, Linux ์ถ”๊ฐ€, ์˜คํ”„๋ผ์ธ
    VIRTIO_MEM_SBM_MB_KERNEL,               // ์™„์ „ ํ”Œ๋Ÿฌ๊ทธ, ์ปค๋„ ์กด ์˜จ๋ผ์ธ
    VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL,       // ๋ถ€๋ถ„ ํ”Œ๋Ÿฌ๊ทธ, ์ปค๋„ ์กด ์˜จ๋ผ์ธ
    VIRTIO_MEM_SBM_MB_MOVABLE,              // ์™„์ „ ํ”Œ๋Ÿฌ๊ทธ, ZONE_MOVABLE ์˜จ๋ผ์ธ
    VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL,      // ๋ถ€๋ถ„ ํ”Œ๋Ÿฌ๊ทธ, ZONE_MOVABLE ์˜จ๋ผ์ธ
    VIRTIO_MEM_SBM_MB_COUNT
    };
  • ์ƒํƒœ ๊ฐ„ ์ „์ด๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜จ๋ผ์ธ/์˜คํ”„๋ผ์ธ, ์„œ๋ธŒ๋ธ”๋ก ํ”Œ๋Ÿฌ๊ทธ/์–ธํ”Œ๋Ÿฌ๊ทธ์— ์˜ํ•ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • _PARTIAL ์ƒํƒœ๋Š” ์ผ๋ถ€ ์„œ๋ธŒ๋ธ”๋ก๋งŒ ํ”Œ๋Ÿฌ๊ทธ๋œ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • enum virtio_mem_bbm_bb_state

    drivers/virtio/virtio_mem.c:90 โ€” BBM์—์„œ ๋น…๋ธ”๋ก์˜ ์ƒํƒœ

    enum virtio_mem_bbm_bb_state {
    VIRTIO_MEM_BBM_BB_UNUSED = 0,       // ๋ฏธ์‚ฌ์šฉ
    VIRTIO_MEM_BBM_BB_PLUGGED,          // ํ”Œ๋Ÿฌ๊ทธ๋จ, Linux์— ๋ฏธ์ถ”๊ฐ€
    VIRTIO_MEM_BBM_BB_ADDED,            // ํ”Œ๋Ÿฌ๊ทธ๋จ, Linux์— ์ถ”๊ฐ€๋จ
    VIRTIO_MEM_BBM_BB_FAKE_OFFLINE,     // ๋ชจ๋“  ์˜จ๋ผ์ธ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ fake-offline
    VIRTIO_MEM_BBM_BB_COUNT
    };

    struct virtio_mem_config

    include/uapi/linux/virtio_mem.h:191 โ€” ํ˜ธ์ŠคํŠธ์™€ ๊ณต์œ ํ•˜๋Š” ์„ค์ • ๊ตฌ์กฐ์ฒด

    struct virtio_mem_config {
    __le64 block_size;            // ๋ธ”๋ก ํฌ๊ธฐ (๋ณ€๊ฒฝ ๋ถˆ๊ฐ€)
    __le16 node_id;               // ACPI PXM ๋…ธ๋“œ ID
    __le64 addr;                  // ์‹œ์ž‘ ์ฃผ์†Œ (๋ณ€๊ฒฝ ๋ถˆ๊ฐ€)
    __le64 region_size;           // ์ตœ๋Œ€ ๋ฆฌ์ „ ํฌ๊ธฐ (๋ณ€๊ฒฝ ๋ถˆ๊ฐ€)
    __le64 usable_region_size;    // ํ˜„์žฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ํฌ๊ธฐ (๋™์  ํ™•์žฅ/์ถ•์†Œ)
    __le64 plugged_size;          // ํ˜„์žฌ ํ”Œ๋Ÿฌ๊ทธ๋œ ํฌ๊ธฐ
    __le64 requested_size;        // ์š”์ฒญ๋œ ๋ชฉํ‘œ ํฌ๊ธฐ
    };
  • usable_region_size: region_size๊นŒ์ง€ ๋™์ ์œผ๋กœ ์ปค์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, UNPLUG_ALL ์š”์ฒญ ์‹œ ์ถ•์†Œ๋ฉ๋‹ˆ๋‹ค.
  • struct virtio_mem_req / virtio_mem_resp

    include/uapi/linux/virtio_mem.h:126,180 โ€” ๊ฒŒ์ŠคํŠธ-ํ˜ธ์ŠคํŠธ ํ†ต์‹  ๋ฉ”์‹œ์ง€

    struct virtio_mem_req_plug {
    	__virtio64 addr;
    	__virtio16 nb_blocks;
    	__virtio16 padding[3];
    };
    
    struct virtio_mem_req_unplug {
    	__virtio64 addr;
    	__virtio16 nb_blocks;
    	__virtio16 padding[3];
    };
    
    struct virtio_mem_req_state {
    	__virtio64 addr;
    	__virtio16 nb_blocks;
    	__virtio16 padding[3];
    };
    
    struct virtio_mem_req {
    	__virtio16 type;
    	__virtio16 padding[3];
    
    	union {
    		struct virtio_mem_req_plug plug;
    		struct virtio_mem_req_unplug unplug;
    		struct virtio_mem_req_state state;
    	} u;
    };
    
    struct virtio_mem_resp_state {
    	__virtio16 state;
    };
    
    struct virtio_mem_resp {
    	__virtio16 type;
    	__virtio16 padding[3];
    
    	union {
    		struct virtio_mem_resp_state state;
    	} u;
    };
  • VIRTIO_MEM_RESP_NACK: ํ”Œ๋Ÿฌ๊ทธ ์š”์ฒญ์ด ๊ฑฐ๋ถ€๋จ (์š”์ฒญ ํฌ๊ธฐ ์ดˆ๊ณผ ๋“ฑ)
  • VIRTIO_MEM_RESP_BUSY: ์žฅ์น˜๊ฐ€ ์ง€๊ธˆ ์ฒ˜๋ฆฌ ๋ถˆ๊ฐ€ (์žฌ์‹œ๋„ ํ•„์š”)

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

    virtio_mem_probe()

    drivers/virtio/virtio_mem.c:2935 โ€” ๋“œ๋ผ์ด๋ฒ„ ํ”„๋กœ๋ธŒ ํ•จ์ˆ˜

    static int virtio_mem_probe(struct virtio_device *vdev)
    {
    	struct virtio_mem *vm;
    	int rc;
    
    	BUILD_BUG_ON(sizeof(struct virtio_mem_req) != 24);
    	BUILD_BUG_ON(sizeof(struct virtio_mem_resp) != 10);
    
    	vdev->priv = vm = kzalloc_obj(*vm);
    	if (!vm)
    		return -ENOMEM;
    
    	init_waitqueue_head(&vm->host_resp);
    	vm->vdev = vdev;
    	INIT_WORK(&vm->wq, virtio_mem_run_wq);
    	mutex_init(&vm->hotplug_mutex);
    	INIT_LIST_HEAD(&vm->next);
    	spin_lock_init(&vm->removal_lock);
    	hrtimer_setup(&vm->retry_timer, virtio_mem_timer_expired, CLOCK_MONOTONIC,
    		      HRTIMER_MODE_REL);
    	vm->retry_timer_ms = VIRTIO_MEM_RETRY_TIMER_MIN_MS;
    	vm->in_kdump = is_kdump_kernel();
    
    	/* virtqueue ๋“ฑ๋ก */
    	rc = virtio_mem_init_vq(vm);
    	if (rc)
    		goto out_free_vm;
    
    	/* ๋””๋ฐ”์ด์Šค ์„ค์ •์„ ์ฝ๊ณ  ์ดˆ๊ธฐํ™” */
    	rc = virtio_mem_init(vm);
    	if (rc)
    		goto out_del_vq;
    
    	/* kdump๊ฐ€ ์•„๋‹ˆ๋ฉด config update๋ฅผ ๊ฑธ์–ด requested_size๋ฅผ ์ฒ˜๋ฆฌ */
    	if (!vm->in_kdump) {
    		atomic_set(&vm->config_changed, 1);
    		queue_work(system_freezable_wq, &vm->wq);
    	}
    
    	return 0;
    out_del_vq:
    	vdev->config->del_vqs(vdev);
    out_free_vm:
    	kfree(vm);
    	vdev->priv = NULL;
    
    	return rc;
    }
  • kdump ์ปค๋„์—์„œ๋Š” virtio_mem_init_kdump()์ด /proc/vmcore ์ฒ˜๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•˜๊ณ , ์‹ค์ œ (un)plug๋Š” ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • virtio_mem_run_wq()

    drivers/virtio/virtio_mem.c:2415 โ€” ์›Œํฌํ ๋ฉ”์ธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜

    static void virtio_mem_run_wq(struct work_struct *work)
    {
    	struct virtio_mem *vm = container_of(work, struct virtio_mem, wq);
    	uint64_t diff;
    	int rc;
    
    	if (unlikely(vm->in_kdump)) {
    		dev_warn_once(&vm->vdev->dev,
    			     "unexpected workqueue run in kdump kernel\n");
    		return;
    	}
    
    	hrtimer_cancel(&vm->retry_timer);
    
    	if (vm->broken)
    		return;
    
    	atomic_set(&vm->wq_active, 1);
    retry:
    	rc = 0;
    
    	/* ๋‚จ์•„ ์žˆ๋Š” ์ƒํƒœ๊ฐ€ ์žˆ์œผ๋ฉด ๋จผ์ € ์ •๋ฆฌํ•œ๋‹ค. */
    	if (unlikely(vm->unplug_all_required))
    		rc = virtio_mem_send_unplug_all_request(vm);
    
    	if (atomic_read(&vm->config_changed)) {
    		atomic_set(&vm->config_changed, 0);
    		virtio_mem_refresh_config(vm);
    	}
    
    	/* ์ด์ „ ์‹คํ–‰์—์„œ ๋‚จ์€ ๋ธ”๋ก์„ ์ •๋ฆฌํ•œ๋‹ค. */
    	if (!rc)
    		rc = virtio_mem_cleanup_pending_mb(vm);
    
    	if (!rc && vm->requested_size != vm->plugged_size) {
    		if (vm->requested_size > vm->plugged_size) {
    			diff = vm->requested_size - vm->plugged_size;
    			rc = virtio_mem_plug_request(vm, diff);
    		} else {
    			diff = vm->plugged_size - vm->requested_size;
    			rc = virtio_mem_unplug_request(vm, diff);
    		}
    	}
    
    	/* ์ด๋ฏธ ์™„์ „ํžˆ unplug๋œ Linux ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก์€ ๊ณ„์† ์ œ๊ฑฐ๋ฅผ ์‹œ๋„ํ•œ๋‹ค. */
    	if (!rc && vm->in_sbm && vm->sbm.have_unplugged_mb)
    		rc = -EBUSY;
    
    	switch (rc) {
    	case 0:
    		vm->retry_timer_ms = VIRTIO_MEM_RETRY_TIMER_MIN_MS;
    		break;
    	case -ENOSPC:
    		/* ์ฃผ์†Œ ์ •๋ ฌ์ด๋‚˜ ๋ฌผ๋ฆฌ ํ•œ๊ณ„ ๋•Œ๋ฌธ์— ๋” ์ด์ƒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๋‹ค. */
    		break;
    	case -ETXTBSY:
    		/* ํ•˜์ดํผ๋ฐ”์ด์ €๊ฐ€ ์ž ์‹œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค. */
    	case -EBUSY:
    		/* unplug์— ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ง€๊ธˆ์€ ๋น„์šธ ์ˆ˜ ์—†๋‹ค. */
    	case -ENOMEM:
    		/* ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ถ€์กฑํ•˜๋‹ˆ ๋‚˜์ค‘์— ๋‹ค์‹œ ์‹œ๋„ํ•œ๋‹ค. */
    		hrtimer_start(&vm->retry_timer, ms_to_ktime(vm->retry_timer_ms),
    			      HRTIMER_MODE_REL);
    		break;
    	case -EAGAIN:
    		/* ์„ค์ •์ด ๋ฐ”๋€Œ์—ˆ์œผ๋‹ˆ ์ฆ‰์‹œ ๋‹ค์‹œ ์‹œ๋„ํ•œ๋‹ค. */
    		goto retry;
    	default:
    		/* ์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜๋Š” ์žฅ์น˜๋ฅผ broken์œผ๋กœ ํ‘œ์‹œํ•œ๋‹ค. */
    		dev_err(&vm->vdev->dev,
    			"unknown error, marking device broken: %d\n", rc);
    		vm->broken = true;
    	}
    
    	atomic_set(&vm->wq_active, 0);
    }

    virtio_mem_plug_request() / virtio_mem_unplug_request()

    drivers/virtio/virtio_mem.c:1922,2306 โ€” SBM/BBM๋ณ„ ํ”Œ๋Ÿฌ๊ทธ/์–ธํ”Œ๋Ÿฌ๊ทธ ์š”์ฒญ ๋ถ„๊ธฐ

    static int virtio_mem_plug_request(struct virtio_mem *vm, uint64_t diff)
    {
    if (vm->in_sbm)
    return virtio_mem_sbm_plug_request(vm, diff);  // ์„œ๋ธŒ๋ธ”๋ก ๋‹จ์œ„
    return virtio_mem_bbm_plug_request(vm, diff);       // ๋น…๋ธ”๋ก ๋‹จ์œ„
    }

    SBM ์–ธํ”Œ๋Ÿฌ๊ทธ ์šฐ์„ ์ˆœ์œ„:

    1. OFFLINE_PARTIAL โ†’ 2. OFFLINE โ†’ 3. MOVABLE_PARTIAL โ†’ 4. KERNEL_PARTIAL โ†’ 5. MOVABLE โ†’ 6. KERNEL

    BBM ์–ธํ”Œ๋Ÿฌ๊ทธ ์šฐ์„ ์ˆœ์œ„:

    1. ์™„์ „ ์˜คํ”„๋ผ์ธ ๋ธ”๋ก โ†’ 2. ZONE_MOVABLE ๋ธ”๋ก โ†’ 3. ๋‚˜๋จธ์ง€

    ๋ฉ”๋ชจ๋ฆฌ ํ•ซํ”Œ๋Ÿฌ๊ทธ ์—ฐ๊ฒฐ

    virtio_mem_init_hotplug()๋Š” mhp_get_pluggable_range(true)๋กœ ์‹ค์ œ๋กœ ์ฃผ์†Œ๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„๋ฅผ ๋จผ์ € ์ž๋ฅด๊ณ , sb_size / bb_size๋ฅผ ๊ณ„์‚ฐํ•œ ๋’ค register_memory_notifier(), register_pm_notifier(), register_virtio_mem_device()๋ฅผ ์ฐจ๋ก€๋กœ ๋ถ™์ž…๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„๊ฐ€ ๋๋‚˜๋ฉด memory_hotplug.c์˜ ์˜จ๋ผ์ธ ์ฝœ๋ฐฑ ๊ฒฝ๋กœ๊ฐ€ virtio_mem_online_page_cb()๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋˜๊ณ , virtio-mem ๋ฒ”์œ„๋Š” virtio_mem_online_page()์—์„œ fake-offline ์—ฌ๋ถ€๋ฅผ ๋‹ค์‹œ ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค.

    virtio_mem_online_page_cb()

    drivers/virtio/virtio_mem.c:1358 โ€” ๋ฉ”๋ชจ๋ฆฌ ์˜จ๋ผ์ธ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ

    static void virtio_mem_online_page_cb(struct page *page, unsigned int order)
    {
    	const unsigned long addr = page_to_phys(page);
    	struct virtio_mem *vm;
    
    	rcu_read_lock();
    	list_for_each_entry_rcu(vm, &virtio_mem_devices, next) {
    		/* onlining ๋˜๋Š” ํŽ˜์ด์ง€๋Š” memory block ๊ฒฝ๊ณ„๋ฅผ ๋„˜์ง€ ์•Š๋Š”๋‹ค. */
    		if (!virtio_mem_contains_range(vm, addr, PFN_PHYS(1 << order)))
    			continue;
    
    		/* virtio_mem_set_fake_offline()๋Š” sleepํ•  ์ˆ˜ ์žˆ๋‹ค. */
    		rcu_read_unlock();
    
    		virtio_mem_online_page(vm, page, order);
    		return;
    	}
    	rcu_read_unlock();
    
    	/* virtio-mem ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ฉด ์ผ๋ฐ˜ ์˜จ๋ผ์ธ ๊ฒฝ๋กœ๋กœ ๋„˜๊ธด๋‹ค. */
    	generic_online_page(page, order);
    }

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

    virtio_mem_init_hotplug()๋Š” mhp_get_pluggable_range(true)๋กœ ์‹ค์ œ๋กœ ์ฃผ์†Œ๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„๋ฅผ ๋จผ์ € ์ž๋ฅด๊ณ , register_memory_notifier()์™€ register_virtio_mem_device()๋ฅผ ์—ฐ๊ฒฐํ•œ ๋’ค set_online_page_callback()๊ฐ€ ์žก์€ virtio_mem_online_page_cb()๊ฐ€ ํŽ˜์ด์ง€ ์˜จ๋ผ์ธ ๊ฒฝ๋กœ๋ฅผ ๊ฐ€๋กœ์ฑ„๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ƒˆ ํŽ˜์ด์ง€๋Š” ๋จผ์ € virtio-mem ๋ฒ”์œ„์ธ์ง€ ํ™•์ธ๋˜๊ณ , ๋ฒ”์œ„ ์•ˆ์ด๋ฉด virtio_mem_online_page()๋ฅผ ๊ฑฐ์ณ fake-offline ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๋ฉฐ, ๋ฒ”์œ„ ๋ฐ–์ด๋ฉด generic_online_page()๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค.

    ํ”Œ๋Ÿฌ๊ทธ ํ๋ฆ„ (๋ฉ”๋ชจ๋ฆฌ ์ถ”๊ฐ€)

    ํ˜ธ์ŠคํŠธ: requested_size ๋ณ€๊ฒฝ
    โ†’ virtio_mem_config_changed()
    โ†’ workqueue ์‹œ์ž‘
    โ†’ virtio_mem_run_wq()
    โ†’ virtio_mem_refresh_config()  // usable_region_size, requested_size ๊ฐฑ์‹ 
    โ†’ virtio_mem_plug_request()
    [SBM] โ†’ virtio_mem_sbm_plug_request()
    โ†’ virtio_mem_sbm_plug_any_sb()    // ๊ธฐ์กด ๋ธ”๋ก์— ์„œ๋ธŒ๋ธ”๋ก ์ถ”๊ฐ€
    โ†’ virtio_mem_sbm_plug_and_add_mb() // ์ƒˆ ๋ธ”๋ก ์ƒ์„ฑ ๋ฐ ์ถ”๊ฐ€
    โ†’ virtio_mem_sbm_plug_sb() โ†’ virtio_mem_send_plug_request() โ†’ virtqueue
    โ†’ virtio_mem_sbm_add_mb() โ†’ add_memory_driver_managed()
    [BBM] โ†’ virtio_mem_bbm_plug_request()
    โ†’ virtio_mem_bbm_plug_and_add_bb()
    โ†’ virtio_mem_bbm_plug_bb() โ†’ virtqueue
    โ†’ virtio_mem_bbm_add_bb() โ†’ add_memory_driver_managed()

    ์–ธํ”Œ๋Ÿฌ๊ทธ ํ๋ฆ„ (๋ฉ”๋ชจ๋ฆฌ ์ œ๊ฑฐ)

    ํ˜ธ์ŠคํŠธ: requested_size ๋ณ€๊ฒฝ
    โ†’ virtio_mem_run_wq()
    โ†’ virtio_mem_unplug_request()
    [SBM] โ†’ virtio_mem_sbm_unplug_request()
    โ†’ virtio_mem_sbm_unplug_any_sb()
    โ†’ virtio_mem_sbm_unplug_any_sb_online()  // ์˜จ๋ผ์ธ ๋ธ”๋ก
    โ†’ virtio_mem_fake_offline()  // alloc_contig_range()๋กœ ํ• ๋‹น ํ•ด์ œ
    โ†’ virtio_mem_sbm_unplug_sb() โ†’ virtqueue
    โ†’ virtio_mem_sbm_unplug_any_sb_offline() // ์˜คํ”„๋ผ์ธ ๋ธ”๋ก
    โ†’ virtio_mem_sbm_unplug_mb() โ†’ virtqueue
    โ†’ virtio_mem_sbm_remove_mb() โ†’ remove_memory()
    [BBM] โ†’ virtio_mem_bbm_unplug_request()
    โ†’ virtio_mem_bbm_offline_remove_and_unplug_bb()
    โ†’ virtio_mem_fake_offline() (์ „์ฒด BB ๋Œ€์ƒ)
    โ†’ virtio_mem_bbm_offline_and_remove_bb() โ†’ offline_and_remove_memory()
    โ†’ virtio_mem_bbm_unplug_bb() โ†’ virtqueue

    ์˜จ๋ผ์ธ ์ฝœ๋ฐฑ ํ๋ฆ„

    ๋ฉ”๋ชจ๋ฆฌ ์˜จ๋ผ์ธ (sysfs ๋˜๋Š” ์ž๋™)
    โ†’ virtio_mem_online_page_cb()
    โ†’ virtio_mem_online_page()
    [SBM] โ†’ ์„œ๋ธŒ๋ธ”๋ก ํ”Œ๋Ÿฌ๊ทธ ์ƒํƒœ ํ™•์ธ
    โ†’ plugged โ†’ generic_online_page()
    โ†’ unplugged โ†’ virtio_mem_set_fake_offline()
    [BBM] โ†’ BB ์ƒํƒœ ํ™•์ธ
    โ†’ FAKE_OFFLINE์ด๋ฉด โ†’ virtio_mem_set_fake_offline()
    โ†’ ์•„๋‹ˆ๋ฉด โ†’ generic_online_page()

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

    virtio-mem vs virtio-balloon ๋น„๊ต

    ํ•ญ๋ชฉvirtio-memvirtio-balloon
    ๋™์ž‘ ์›๋ฆฌDIMM ๋™์  ํฌ๊ธฐ ์กฐ์ ˆ (ํ•ซํ”Œ๋Ÿฌ๊ทธ)ํŽ˜์ด์ง€ ํ• ๋‹น/ํ•ด์ œ (inflation)
    granularity๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก/์„œ๋ธŒ๋ธ”๋ก4KB ํŽ˜์ด์ง€
    ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์ปค๋„ ํ•ซํ”Œ๋Ÿฌ๊ทธ ์ธํ”„๋ผ ์‚ฌ์šฉballoon_dev_info ๋ชฉ๋ก ๊ด€๋ฆฌ
    NUMA ์ธ์‹NUMA ๋…ธ๋“œ๋ณ„ ์žฅ์น˜ ํ• ๋‹นNUMA ์ธ์‹ ์ œํ•œ์ 
    ์˜คํ”„๋ผ์ธfake-offline โ†’ ์ œ๊ฑฐํŽ˜์ด์ง€๋ฅผ ํ˜ธ์ŠคํŠธ์— ๋ฐ˜ํ™˜
    ์˜๊ตฌ ๋ฉ”๋ชจ๋ฆฌ๋ถˆ๊ฐ€ (์–ธํ”Œ๋Ÿฌ๊ทธ ์‹œ ์ œ๊ฑฐ)๋ถˆ๊ฐ€
    kdump ์ง€์›vmcore ์ฒ˜๋ฆฌ ์ง€์›๊ธฐ๋ณธ ์ง€์›
    Free Page Reporting๋ถˆ๊ฐ€ (๋ณ„๋„ ๋ฉ”์ปค๋‹ˆ์ฆ˜)virtio-balloon VQ๋กœ ์ง€์›
    ๋ณต์žก๋„๋†’์Œ (SBM/BBM, ์ƒํƒœ ๋จธ์‹ )์ƒ๋Œ€์ ์œผ๋กœ ๋‚ฎ์Œ

    SBM vs BBM ๋น„๊ต

    ํ•ญ๋ชฉSBM (Sub Block Mode)BBM (Big Block Mode)
    granularity์„œ๋ธŒ๋ธ”๋ก (pageblock ํฌ๊ธฐ)๋น…๋ธ”๋ก (>= ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก)
    ์„ ํƒ ์กฐ๊ฑดsb_size < memory_block_sizesb_size >= memory_block_size ๋˜๋Š” force_bbm
    ์„ธ๋ฐ€๋„๋†’์Œ (๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ๋‚ด ๋ถ€๋ถ„ ํ• ๋‹น)๋‚ฎ์Œ (๋ธ”๋ก ์ „์ฒด)
    ์ƒํƒœ ์ถ”์ mb_states + sb_states ๋น„ํŠธ๋งตbb_states ๋ฐ”์ดํŠธ ๋ฐฐ์—ด
    ์˜คํ”„๋ผ์ธ์„œ๋ธŒ๋ธ”๋ก๋ณ„ fake-offline์„น์…˜ ๋‹จ์œ„ fake-offline
    ๋ฉ”๋ชจ๋ฆฌ ์ œ๊ฑฐ์„œ๋ธŒ๋ธ”๋ก ์ „๋ถ€ ์–ธํ”Œ๋Ÿฌ๊ทธ ํ›„ ๋ธ”๋ก ์ œ๊ฑฐ๋น…๋ธ”๋ก ์ „์ฒด ์˜คํ”„๋ผ์ธ ํ›„ ์ œ๊ฑฐ
    ๋ฉ”๋ชจ๋ฆฌ ๊ทธ๋ฃน๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ๋‹จ์œ„๋น…๋ธ”๋ก ๋‹จ์œ„

    feature ํ”Œ๋ž˜๊ทธ ๋น„๊ต

    ํ”Œ๋ž˜๊ทธ๊ฐ’์„ค๋ช…
    VIRTIO_MEM_F_ACPI_PXM0node_id๊ฐ€ ACPI PXM์œผ๋กœ ์œ ํšจ
    VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE1์–ธํ”Œ๋Ÿฌ๊ทธ๋œ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ๋ถˆ๊ฐ€
    VIRTIO_MEM_F_PERSISTENT_SUSPEND2์„œ์ŠคํŽœํŠธ+.Resume ์‹œ ํ”Œ๋Ÿฌ๊ทธ ์œ ์ง€

    ๋ฉ”๋ชจ๋ฆฌ ํ•ซํ”Œ๋Ÿฌ๊ทธ ๊ด€์ฐฐ ํฌ์ธํŠธ

    ํ•ญ๋ชฉvirtio-mem์—์„œ ๋ณด๋Š” ๊ฐ’ํ™•์ธ ๋ช…๋ น
    ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก ํฌ๊ธฐ์˜จ๋ผ์ธ/์˜คํ”„๋ผ์ธ์˜ ๊ธฐ์ค€ ๋‹จ์œ„`cat /sys/devices/system/memory/block_size_bytes`
    ์ž๋™ ์˜จ๋ผ์ธ์ƒˆ ๋ธ”๋ก์ด ์ž๋™์œผ๋กœ ์˜จ๋ผ์ธ๋˜๋Š”์ง€`cat /sys/devices/system/memory/auto_online_blocks 2>/dev/null`
    ์˜จ๋ผ์ธ ์ •์ฑ…`contig-zones` / `auto-movable``cat /sys/module/memory_hotplug/parameters/online_policy 2>/dev/null`
    memmap ๋ฐฐ์น˜`struct page`๋ฅผ ๋ฉ”๋ชจ๋ฆฌ ์œ„์— ๋‘˜์ง€ ์—ฌ๋ถ€`cat /sys/module/memory_hotplug/parameters/memmap_on_memory 2>/dev/null`
    ํ”Œ๋Ÿฌ๊ทธ ๊ฐ€๋Šฅ ๋ฒ”์œ„์žฅ์น˜๊ฐ€ ์‹ค์ œ๋กœ ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ฌผ๋ฆฌ ๋ฒ”์œ„`cat /proc/iomemgrep -Ei 'virtioSystem RAM'`

    ์˜คํ”„๋ผ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

    fake-offline ๋ฉ”์ปค๋‹ˆ์ฆ˜

    virtio-mem์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‹ค์ œ๋กœ ์ œ๊ฑฐํ•˜๊ธฐ ์ „์— "fake-offline" ๊ณผ์ •์„ ๊ฑฐ์นฉ๋‹ˆ๋‹ค:

    1. virtio_mem_fake_offline(): alloc_contig_range()๋กœ ๋ฌผ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ์—ฐ์† ํ• ๋‹น

    2. virtio_mem_set_fake_offline(): ํŽ˜์ด์ง€์— PG_offline ํ”Œ๋ž˜๊ทธ ์„ค์ •

    3. adjust_managed_page_count(): ๊ด€๋ฆฌ ํŽ˜์ด์ง€ ์ˆ˜ ๊ฐ์†Œ

    4. virtqueue๋กœ ์–ธํ”Œ๋Ÿฌ๊ทธ ์š”์ฒญ ์ „์†ก

    5. ์‘๋‹ต ACK ์‹œ virtio_mem_fake_online()๋กœ ํŽ˜์ด์ง€ ๋ณต์› ๋˜๋Š” ์™„์ „ ์ œ๊ฑฐ

    ์˜คํ”„๋ผ์ธ ์ž„๊ณ„๊ฐ’

    // drivers/virtio/virtio_mem.c:154
    #define VIRTIO_MEM_DEFAULT_OFFLINE_THRESHOLD (1024 * 1024 * 1024)  // 1GB
    
    // ์˜คํ”„๋ผ์ธ๋œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ž„๊ณ„๊ฐ’์„ ์ดˆ๊ณผํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์ถ”๊ฐ€ ์ค‘๋‹จ
    static bool virtio_mem_could_add_memory(struct virtio_mem *vm, uint64_t size)
    {
    return atomic64_read(&vm->offline_size) + size <= vm->offline_threshold;
    }

    ๊ด€๋ จ ๋ฌธ์„œ

  • 22-memory_hotplug.html โ€” ๋ฉ”๋ชจ๋ฆฌ ํ•ซํ”Œ๋Ÿฌ๊ทธ ์ธํ”„๋ผ
  • 45-balloon.html โ€” virtio-balloon ๋“œ๋ผ์ด๋ฒ„
  • 46-page_reporting.html โ€” Free Page Reporting
  • 13-numa.html โ€” NUMA ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ
  • 52-linux_6x_to_7x.html โ€” Linux 6.x โ†’ 7.0 ๋ณ€๊ฒฝ์ 