# Chapter 9: Virtual Memory 閱讀筆記 本文旨在記錄 *Computer Systems: A Programmer's Perspective* (CS:APP) 一書第七章閱讀心得,該書是 CMU 的計算機系統概論的教材 (難度相當於台灣的大學高年級),該書的簡體中文翻譯名稱為《深入理解計算機系統》。 CS:APP 亦是 [Linux Kernel Internals 2024 Spring](https://wiki.csie.ncku.edu.tw/linux/schedule) 課程指定教材,並一同收錄於 [Linux Kernel Internals 2024 Spring Collections](https://hackmd.io/@Kuanch/linux2024-collection)。 ## 9.7 Case Study: The Intel Core i7/Linux Memory Syste ### 9.7.2 Linux Virtual Memory System 下圖為 Linux 行程當中記憶體配置的示意圖: ![image](https://hackmd.io/_uploads/BJldUd9P0.png) 另一張圖將 MMU 各個部分和 Linux 核心程式碼連結: ![image](https://hackmd.io/_uploads/rkYiLdqwC.png) 我們可以在 `include/linux/mm_types.h` 找到相對應的結構 `vm_area_struct` ```c /* * 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()` 有以下操作 ```c 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 的操作: ```c #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); ... } ... } ... } ```