Try   HackMD

Chapter 9: Virtual Memory 閱讀筆記

本文旨在記錄 Computer Systems: A Programmer's Perspective (CS:APP) 一書第七章閱讀心得,該書是 CMU 的計算機系統概論的教材 (難度相當於台灣的大學高年級),該書的簡體中文翻譯名稱為《深入理解計算機系統》。

CS:APP 亦是 Linux Kernel Internals 2024 Spring 課程指定教材,並一同收錄於
Linux Kernel Internals 2024 Spring Collections

9.7 Case Study: The Intel Core i7/Linux Memory Syste

9.7.2 Linux Virtual Memory System

下圖為 Linux 行程當中記憶體配置的示意圖:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

另一張圖將 MMU 各個部分和 Linux 核心程式碼連結:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

我們可以在 include/linux/mm_types.h 找到相對應的結構 vm_area_struct

/*
 * This struct describes a virtual memory area. There is one of these
 * per VM-area/task. A VM area is any part of the process virtual memory
 * space that has a special rule for the page-fault handlers (ie a shared
 * library, the executable area etc).
 */
struct vm_area_struct {
	/* The first cache line has the info for VMA tree walking. */

	union {
		struct {
			/* VMA covers [vm_start; vm_end) addresses within mm */
			unsigned long vm_start;
			unsigned long vm_end;
		};
#ifdef CONFIG_PER_VMA_LOCK
		struct rcu_head vm_rcu;	/* Used for deferred freeing. */
#endif
	};

	struct mm_struct *vm_mm;	/* The address space we belong to. */
	pgprot_t vm_page_prot;          /* Access permissions of this VMA. */

	/*
	 * Flags, see mm.h.
	 * To modify use vm_flags_{init|reset|set|clear|mod} functions.
	 */
	union {
		const vm_flags_t vm_flags;
		vm_flags_t __private __vm_flags;
	};
    // ....skip
}

注意到 mm_struct 並不直接帶有 vm_area_struct,而是後者透過 vm_area_struct->vm_mm 儲存。

若深入追究,我們可以在 copy_process() 下看到一系列初始化 VMA 的操作,如 copy_mm(),而其下之 copy_mm() 有以下操作

static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
{
    // ... skip
	if (clone_flags & CLONE_VM) {
		mmget(oldmm);
		mm = oldmm;
	} else {
		mm = dup_mm(tsk, current->mm);
		if (!mm)
			return -ENOMEM;
	}
    // ... skip
}

dup_mm() 其內的 dup_mmap() 就能看到如上圖其指定所屬 mm_struct 和一般鏈結多個 vma 的操作:

#ifdef CONFIG_MMU
static __latent_entropy int dup_mmap(struct mm_struct *mm,
					struct mm_struct *oldmm)
{
    struct vm_area_struct *mpnt, *tmp;
    ... 
    for_each_vma(vmi, mpnt) {
        ... 
        tmp->vm_mm = mm;
        ... 
        if (file) {
            ... 
            /* insert tmp into the share list, just after mpnt */
            vma_interval_tree_insert_after(tmp, mpnt, &mapping->i_mmap);
            ... 
        }
        ... 
    }
    ...
}