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 ํ๋จ์ ๋ฐ๊ณ ๊ทธ ๋ค ์ผ๋ฐ ์จ๋ผ์ธ ๊ฒฝ๋ก๋ก ์ด์ด์ง๋๋ค.
์์ค ํ์ผ ๊ฒฝ๋ก
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;
}
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-mem | virtio-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_size | sb_size >= memory_block_size ๋๋ force_bbm |
| ์ธ๋ฐ๋ | ๋์ (๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ๋ด ๋ถ๋ถ ํ ๋น) | ๋ฎ์ (๋ธ๋ก ์ ์ฒด) |
| ์ํ ์ถ์ | mb_states + sb_states ๋นํธ๋งต | bb_states ๋ฐ์ดํธ ๋ฐฐ์ด |
| ์คํ๋ผ์ธ | ์๋ธ๋ธ๋ก๋ณ fake-offline | ์น์ ๋จ์ fake-offline |
| ๋ฉ๋ชจ๋ฆฌ ์ ๊ฑฐ | ์๋ธ๋ธ๋ก ์ ๋ถ ์ธํ๋ฌ๊ทธ ํ ๋ธ๋ก ์ ๊ฑฐ | ๋น ๋ธ๋ก ์ ์ฒด ์คํ๋ผ์ธ ํ ์ ๊ฑฐ |
| ๋ฉ๋ชจ๋ฆฌ ๊ทธ๋ฃน | ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ๋จ์ | ๋น ๋ธ๋ก ๋จ์ |
feature ํ๋๊ทธ ๋น๊ต
| ํ๋๊ทธ | ๊ฐ | ์ค๋ช |
|---|---|---|
| VIRTIO_MEM_F_ACPI_PXM | 0 | node_id๊ฐ ACPI PXM์ผ๋ก ์ ํจ |
| VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE | 1 | ์ธํ๋ฌ๊ทธ๋ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ๋ถ๊ฐ |
| VIRTIO_MEM_F_PERSISTENT_SUSPEND | 2 | ์์คํํธ+.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/iomem | grep -Ei 'virtio | System 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;
}