Ryotta's Linux 7.0 MM

메모리 관리 서브시스템 완전 분석

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 변경점