Linux虛存分析報告_第1頁
Linux虛存分析報告_第2頁
Linux虛存分析報告_第3頁
Linux虛存分析報告_第4頁
Linux虛存分析報告_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、1 / 29 文檔可自由編輯打印LinuxLinux 虛虛 存存 分分 析析 報報 告告方方 存存 好好第一章第一章 前前 言言2第二章第二章 LINUX 虛存管理概述虛存管理概述31、LINUX虛存管理的基本特點32、LINUX虛存管理的主要實現(xiàn)技術3第三章第三章 LINUX 虛存管理數(shù)據(jù)結構虛存管理數(shù)據(jù)結構51、32-BIT虛擬地址52、LINUX的多級頁表結構53、頁表項的格式64、動態(tài)地址映射75、用戶進程的虛擬內存結構86、我們的工作10第四章第四章 PROCESS 的虛存管理數(shù)據(jù)結構的建立、維護、拆除及相關系統(tǒng)調用流程的虛存管理數(shù)據(jù)結構的建立、維護、拆除及相關系統(tǒng)調用流程111、進

2、程的載入、創(chuàng)建及內存管理數(shù)據(jù)結構和鏈結關系的建立112、數(shù)據(jù)結構及鏈結關系的拆除(SYS_EXIT)133、缺頁中斷服務14第五章第五章 主要函數(shù)分析主要函數(shù)分析16MEMORY.C16MMAP.C22第六章第六章 后記后記292 / 29 文檔可自由編輯打印第一章第一章 前前 言言Linux 是一個功能強大的操作系統(tǒng),而內存管理則是操作系統(tǒng)的核心,它負責管理計算機系統(tǒng)的存儲器。作為操作系統(tǒng)的核心,必須能夠克服物理內存的局限,使用戶進程在透明方式下,擁有比實際物理內存大得多的內存。其策略之一就是使用虛擬內存。Linux成功地實現(xiàn)了以虛擬內存為核心的內存管理策略,強大得分頁機制,公平得交換方式,

3、各類有效得高速緩存,以及以頁保護為主得保護措施等。內存管理的目的是要盡可能地方便用戶。同時 Linux 系統(tǒng)通過對用戶進程虛存的有效管理,作到了虛存對一般用戶和 Linux程序員的透明。本文首先闡述了 Linux 虛存管理以基本特點和主要實現(xiàn)技術,并分析了 Linux 虛存管理的主要數(shù)據(jù)結構及其相關關系。圍繞它的建立、維護、使用和拆除,作了一個粗淺的剖析,因本人水平有限,有不當之處,請老師指正。同時應該指出的是本文所做的工作離不開同組的林濤、徐玫峰和范昭偉同學的幫助,謝謝他們。3 / 29 文檔可自由編輯打印第二章第二章 Linux 虛存管理概述虛存管理概述Linux 的內存管理采用頁式管理,

4、使用多級頁表,動態(tài)地址轉換機構與主存、輔存共同實現(xiàn)虛擬內存:每個用戶 Process 擁有 4GB 的虛擬地址空間,Process 在運行過程中可以動態(tài)浮動和擴展,為用戶提供了透明的、靈活有效的內存使用方式,下面簡述 Linux 虛存管理以基本特點和主要實現(xiàn)技術:1、 Linux 虛存管理的基本特點虛存管理的基本特點1.更大的地址空間。虛擬內存可以是系統(tǒng)實際擁有的物理內存的若干倍。因而它使得操作系統(tǒng)看起來擁有比實際大得多的內存。2.合理的物理內存分配。Linux 通過共享和交換策略,使各個運行的進程能公平地共享內存。3.保護。Linux 存儲管理子系統(tǒng)為每一內存頁設置了“上鎖位” ,在線性地址

5、及每級頁表頁項上設置了“讀/寫”位,這樣來確保某一個進程不受其他進程的干擾。即使某一個進程失敗了,也不會影響到其他進程和操作系統(tǒng)本身。4.共享虛擬內存Linux 實現(xiàn)的虛擬內存允許兩個進程之間互相共享內存,例如:共享的庫。在這種情形之下,庫代碼僅存在于一個進程,而不需要為每一個應用都復制一份。2、 Linux 虛存管理的主要實現(xiàn)技術虛存管理的主要實現(xiàn)技術1、 請求調頁(demanding paging)與內存擴展用戶 Process 創(chuàng)建時,并不是將它所需所有頁都分配給相應物理頁。開始時只裝入頁面中 Process 的第一個頁面,其他頁根據(jù) Process 運行過程的請求從外存調入所需頁面,當

6、Process 訪問一個頁表項 P 位為 0 的頁中地址時,表示此頁不在主存中,將產生缺頁中斷,系統(tǒng)調用 handle_mm_fault()處理訪問異常,為之分配相應物理頁后,它再調用 s()函數(shù),從外存中讀入該頁面。Linux 是一種請求式分頁存貯管理,這才使之可以運行大于主存空間的 Process。2、 頁換出策略4 / 29 文檔可自由編輯打印內存中頁面不足時,Linux 使用頁面 AGE 技術實現(xiàn)了頁淘汰策略的最近最少使用(LRU)算法:即每次換出時,總是選擇最老的頁換出,對易于從其他設備上獲取的非臟(not dirty)頁面。Linux 采用丟棄(discarding)技術,如果發(fā)生

7、過寫操作,則將該頁寫入系統(tǒng)的 S 中,這樣就可以加快換入的速度。3、 內存共享Linux 將內存劃分為 4K 大小的頁面,為內存共享提供了基礎:(1)不同進程間頁面共享時,可令共享該頁的 Process 的頁表項(pte)均指向該頁。(2)對 kernel 代碼和數(shù)據(jù)段的共享,通過 Process 創(chuàng)建時 fork() 函數(shù)將 kernel 代碼和數(shù)據(jù)段映射到用戶虛存的 3GB4GB 的空間中去,所以每個 Process 都可以通過一定方式共享kernel 的代碼和數(shù)據(jù)段。4、 內存保護采用了“Hole”技術、虛存段的保護、地址轉換機構、頁表存取控制位(R/W 位)等技術實現(xiàn)了內存保護?!癏o

8、le”技術 物理內存前 4K 是一空頁(empty_zero_page) ,用來捕獲 NULL 指針的異常訪問。在 Process 每個虛存段后,都有一個“4K”的“Hole” ,用來捕獲虛存段的越界訪問。虛存段保護方式 主存中虛存段的全部或部分可以設為保護方式,防止非法訪問。頁表項存取控制位(R/W 位) 頁表項以“R/W”位表示此頁的存取權限“1”為可讀寫, “0”為不可讀寫,可用來防止越權訪問。地址轉換機構 分頁存貯管理方法中,地址轉換機構進行的頁面映象實際上防止了各 Process 的主存塊間互不干擾,起到 Process 隔離的作用。5、 動態(tài)地址變換利用 i386 的地址變換機構

9、Linux 實現(xiàn)了動態(tài)地址變換,Process 執(zhí)行時訪問到某一虛擬地址時才確定其對應的物理地址。這種方式為 Process 存貯塊的動態(tài)和動態(tài)擴展提供了基礎。5 / 29 文檔可自由編輯打印第三章第三章 Linux 虛存管理數(shù)據(jù)結構虛存管理數(shù)據(jù)結構1、32-bit 虛擬地址虛擬地址在 Linux 中,4GB 的虛存需通過 32-bit 地址進行尋址。 (Linux 中虛擬地址與線形地址為同一概念)虛擬地址被分割成 3 個子位段,其中 2 個子位段包含 10 位, 1 個子位段包含 12 位,如圖 2.1 所示:123圖 1 32 位虛擬地址3 個子位段分別表示不同含義:子位段 1 指向被稱作

10、頁目錄(PGD)的一張表,子位段 2 指向被稱作頁表(PTE)的一張表,子位段 3 指向頁內地址。2、Linux 的多級頁表結構的多級頁表結構標準的 Linux 的虛存頁表為三級頁表,依次為頁目錄(Page Directory-PGD)、中間頁目錄(Page Middle Directory-PMD)、頁表(Page Table)PTE) 。如圖 2.2 所示。 PGD PMD PTE PAGE FRAME圖 2 Linux 的多級頁表結構在 i386 機器上 Linux 的頁表結構實際為兩級,PGD 和 PMD 頁表是合二為一的。所有有關 PMD 的操作實際上是對 PGD 的操作。所以原代碼

11、中形如*-pgd-*()和*-pmd-*()的函數(shù)實現(xiàn)的功能也是一樣的。6 / 29 文檔可自由編輯打印頁目錄(PGD) 是一個大小為 4K 的表,每一個 process 只有一個頁目錄,以 4 字節(jié)為一個表項,分成 1024 個表項(或稱入口點);該表項的值為所指頁表的始地址。32 位虛擬地址的第 1 個子位段共 10 位,其值的范圍從 0 到 1023,對應于頁目錄的一個入口點。頁目錄(PTE)的每一個入口點的值為此表項所指的一頁框(page frame) ,32 位虛擬地址的第 2 個子位段共 10 位,其值的范圍從 0 到 1023。頁框(page frame)并不是物理頁,它指是虛存

12、的一個地址空間。3、頁表項的格式、頁表項的格式Linux 中頁表每一個表項的格式,如圖所示: 31 12 11 7 6 5 4 3 2 1 0 Address Reserved DA U RP SW圖 3 頁表項格式其中,各位段的含義如下:P:存在位,表示該表項對地址的轉換是否有效。i386 處理器在 P=0 時不解釋表項中的任何位,此時這些位的含義完全由軟件自行解釋。P 位提供了至關重要的屬性,以支持分頁機制。如果 P=1,則表示虛擬地址所對應的頁框存在于物理內存中,訪問該虛擬地址的程序可以正常運行;P=0,則表示虛擬地址所對應的頁框不存在于物理內存中,訪問該虛擬地址的程序將會引發(fā)頁訪問異常

13、,產生缺頁中斷。使得 Operating System 可以把缺少的頁從磁盤上讀入內存,并將讀入頁存入到表項中,然后將該頁標志為存在,再使引起異常的程序繼續(xù)執(zhí)行。R/W :讀寫位,表示對該表項指向的頁可以進行讀、寫或執(zhí)行操作。R/W=1 則該頁可寫,可讀,且可執(zhí)行;R/W=0 則該頁可讀,可執(zhí)行,但不可寫。當處理器7 / 29 文檔可自由編輯打印處于特權級 02 時,R/W 位被忽略。如該表項位于頁目錄中,則作用于該表項映射的所有各頁。U/S:用戶/系統(tǒng)位。U/S=1 則該頁可在任何處理器特權級下訪問;U/S=0 則該頁只能在處理器特權級 02 下被訪問。如該表項位于頁目錄中,則作用于該表項映

14、射的所有各頁。D:已寫標志位。在對該表項映射的頁進行寫訪問之前,處理器對該位置 1。如該表項是頁目錄中表項,處理器不修改 D 位。Address:頁框物理地址的高 20 位。系統(tǒng)將物理內存分割成 4K 大小的內存頁框,Address 實際上代表了頁框的幀號。4、動態(tài)地址映射、動態(tài)地址映射Linus 虛存采用動態(tài)地址映射方式,即 Process 的地址空間和存儲空間的對應關系是在程序的執(zhí)行過程中實現(xiàn)的:Process 每用到一個地址時, 都需虛存的地址轉換機構把虛擬地址轉化為內存的實際地址。其地址映射如下圖所示:圖 4 32 位虛擬地址轉換圖動態(tài)地址映射使 Linux 可以實現(xiàn) Process

15、在主存中的動態(tài)重定位,虛存段的動態(tài)擴展和8 / 29 文檔可自由編輯打印移動;也為虛存的實現(xiàn)提供了基礎。5、用戶進程的虛擬內存結構、用戶進程的虛擬內存結構用戶進程的虛擬內存結構如圖所示:9 / 29 文檔可自由編輯打印mm_struct每一個進程的 task_struct 中都有一個結構 mm_struct,此結構包含了進程中與儲存管理相關的大部分信息,其申明如下:struct mm_struct int count;/ 使用該 mm 結構的個數(shù),如果是多處理機,則有可能 count 1pgd_t * pgd; /* 進程頁目錄的起始地址,如上圖所示 */unsigned long conte

16、xt;unsigned long start_code, end_code, start_data, end_data;/*start_code、end_code:進程代碼段的起始地址和結束地址。start_data、end_data:進程數(shù)據(jù)段的起始地址和結束地址。*/unsigned long start_brk, brk, start_stack, start_mmap;unsigned long arg_start, arg_end, env_start, env_end;/* arg_start、arg_end:調用參數(shù)區(qū)的起始地址和結束地址。env_start、env_end:進程

17、環(huán)境區(qū)的起始地址和結束地址。*/unsigned long rss, total_vm, locked_vm;/* rss:進程內容駐留在物理內存的頁面總數(shù)。*/unsigned long def_flags;struct vm_area_struct * mmap; /* 以雙向鏈表組成的 vma 模塊的首指針。 */struct vm_area_struct * mmap_avl; /* 以 avl 樹結構組成的虛擬空間的首指針。*/struct semaphore mmap_sem;用戶進程虛存管理的數(shù)據(jù)結構如圖 5 所示。用戶共有 4GB 的虛存空間,實際可申請的虛存空間為 03GB。

18、3GB4GB 的虛存空間在用戶進程創(chuàng)建時,已由函數(shù) fork()將 kernel的代碼段和數(shù)據(jù)段映射到 3GB4GB 的虛存空間。因而所有進程的 3GB4GB 的虛存空間的映象都是相同的,從而以這種方式使所有進程共享 kernel 的代碼段和數(shù)據(jù)段。VMA進程的虛擬空間通常由一個個 vma 塊組成,這些塊的結構如下所示:struct vm_area_struct struct mm_struct * vm_mm;/* VM area parameters */unsigned long vm_start; /該 vma 塊代表的使用虛擬空間的起始地址unsigned long vm_end;

19、/該 vma 塊代表的使用虛擬空間的結束地址pgprot_t vm_page_prot; /保護位 unsigned short vm_flags; /標志位/* AVL tree of VM areas per task, sorted by address */short vm_avl_height; /avl 樹高度struct vm_area_struct * vm_avl_left; /vma 塊的左子節(jié)點struct vm_area_struct * vm_avl_right; /vma 塊的右子節(jié)點/* linked list of VM areas per task, sort

20、ed by address */struct vm_area_struct * vm_next; /* 在按地址大小排列的單向鏈表上的下一個指針*/10 / 29 文檔可自由編輯打印/* for areas with inode, the circular list inode-i_mmap */* for shm areas, the circular list of attaches */* otherwise unused */struct vm_area_struct * vm_next_share;struct vm_area_struct * vm_prev_share;/* mo

21、re */struct vm_operations_struct * vm_ops;/對 VMA 塊進行操作的函數(shù)集unsigned long vm_offset;struct inode * vm_inode;/該 VMA 塊對應的文件unsigned long vm_pte;/* shared mem */;采用 avl 樹的優(yōu)點是可以快速找到相關地址所在的 vma 塊。同時,同一個任務的 vma塊還按前后順序排成一個線性鏈表。6、我們的工作、我們的工作針對上圖所示的用戶進程虛存管理的數(shù)據(jù)結構,圍繞它的建立、維護、使用和拆除,我們組作了相應的工作,主要包括以下幾點:1、進程的載入、創(chuàng)建及內

22、存管理數(shù)據(jù)結構和鏈結關系的建立 (sys_execve, sys_fork, sys_clone)2、頁表的建立與釋放 ( new_page_tables, free_page_tables, .)3、虛擬內存的申請與釋放(sys_mmap, sys_munmap)4、缺頁中斷處理(do_page_fault)5、虛擬塊 VMA 的管理(sys_remap, sys_mprotect)6、 數(shù)據(jù)結構及鏈結關系的拆除(sys_exit)其中,虛擬內存的申請與釋放由林濤和徐玫峰同學負責,虛擬塊 VMA 的管理由范昭偉同學負責,相關的工作體現(xiàn)在他們的分析報告中。11 / 29 文檔可自由編輯打印第四

23、章第四章 Process 的虛存管理數(shù)據(jù)結構的建立、維護、的虛存管理數(shù)據(jù)結構的建立、維護、拆除及相關系統(tǒng)調用流程拆除及相關系統(tǒng)調用流程1、進程的載入、創(chuàng)建及內存管理數(shù)據(jù)結構和鏈結關系的建立、進程的載入、創(chuàng)建及內存管理數(shù)據(jù)結構和鏈結關系的建立sys_execve 系統(tǒng)調用負責將可執(zhí)行文件映象載入到內存,與內存相關的操作主要是: 通過調用 exit_mmap 清除當前進程的所有的虛存塊,通過調用 clear_page_table 清除當前進程的頁表項,通過調用 flush_old_signals 清除當前進程的殘留信號,通過調用flush_old_files 清除當前進程的已打開文件,從而將當前進

24、程掏空,成為一個空殼。然后系統(tǒng)根據(jù) bprm 結構更新 current 進程的控制塊,并通過調用兩次 do_mmap 分別將執(zhí)行文件的代碼段和數(shù)據(jù)段映射到虛存。系統(tǒng)一般只將前兩頁載入物理內存中,同時分配一頁給堆棧,其它的均留在硬盤中通過虛擬內存映射機制映射為虛擬內存。當運行中發(fā)生缺頁中斷時,系統(tǒng)處理缺頁中斷,將缺頁調入物理內存中,如果發(fā)生物理內存不足的情況,則由kswapd()選擇合適的頁調入交換文件中或扔掉(如未發(fā)生寫操作) 。具體流程如下:asmlinkage int sys_execve(struct pt_regs regs)/為 do_execve()的調用準備參數(shù)do_execve

25、()初始化 bprm /* bprm 是 struct linux_binprm,進程控制塊中某些參數(shù)的暫存器*/search_binary_handler()/*尋找二進制文件的處理程序(handler),并用該 handler(一般是 load_aout_binary)程序處理該二進制文件*/load_aout_binary()do_load_aout_binary()/異常情況判斷,flush_old_exec(bprm)exec_mmap()/ if necessary, then copy_on_writeexit_mmap(current-mm)/清除當前進程的所有的虛存塊12 /

26、 29 文檔可自由編輯打印clear_page_table(current)/清除當前進程的頁表項flush_tlb_mm(current-mm); /?flush_thread(); /?flush_old_signals(current-sig);/清除當前進程的殘留信號flush_old_files(current-files);/清除當前進程的已打開文件/到此為止,當前進程已被掏空,成為一個空殼。根據(jù) bprm 結構更新 current 進程的控制塊do_mmap();/將執(zhí)行文件的代碼段映射到虛存do_mmap();/將執(zhí)行文件的數(shù)據(jù)段映射到虛存 / do_load_aout_bin

27、ary /end for load_aout_binary/ end for search_binary_handler/end for do_execve/end for sys_execve2、do_fork()當通過 sys_fork 和 sys_clone 系統(tǒng)調用來創(chuàng)建子進程時,系統(tǒng)將通過 do_fork 函數(shù)來完成大部分的創(chuàng)建任務,do_fork 函數(shù)首先申請一頁的核心空間給進程控制塊,再申請一頁的核心空間給系統(tǒng)堆棧,再通過 copy_mm 函數(shù)為子進程復制父進程的虛擬空間(如果是sys_clone 系統(tǒng)調用,則不用復制,子進程的 mm 指針指向父進程 mm_struct) ,具體

28、流程如下:asmlinkage int sys_fork(struct pt_regs regs)return do_fork(SIGCHLD, regs.esp, &regs);asmlinkage int sys_clone(struct pt_regs regs)unsigned long clone_flags;unsigned long newsp;clone_flags = regs.ebx;newsp = regs.ecx;if (!newsp)newsp = regs.esp;return do_fork(clone_flags, newsp, &regs);d

29、o_fork()申請一頁的核心空間給進程控制塊 (struct task_struct *p)申請一頁的核心空間給系統(tǒng)堆棧*P=*current;/復制父進程的進程控制塊作必要的修改13 / 29 文檔可自由編輯打印copy_mm()如果是 clone父子進程的 mm 指針指向同一個 mm_struct;mm_struct-count+;else /畫圖struct mm_struct *mm = 申請一頁核心空間;*mm = *current-mm; /復制父進程的相關信息new_page_tables(); /建立新的頁目錄表 pgd,且復制 init 進程的 768-1023 項dup_

30、mmap();/復制父進程的虛擬空間映射for 對于父進程中的每一個 VMA 塊復制該 VMA 塊,作相應修改并重新鏈起來;copy_page_range(mm, current-mm, 該 VMA 塊)其工作機制是循環(huán)調用 copy_pmd_range,將 vma 塊中的所有虛擬空間復制到對應的虛擬空間中。在做復制之前,必須確保新任務對應的被復制的虛擬空間中必須都為零。 /end for dup_mmap()/ end for copy_mm(). ./end for do_fork()2、數(shù)據(jù)結構及鏈結關系的拆除(、數(shù)據(jù)結構及鏈結關系的拆除(sys_exit)sys_exit()系統(tǒng)調用

31、sys_exit 來結束進程,調用 exit_mm()將所有虛擬內存都結束掉,最后中止進程。asmlinkage int sys_exit(int error_code) ()do_exit(). .kerneld_exit();_exit_mm(current);if ( !-current-mm-count ) /無其他進程共享該 mm_structexit_mmap(mm);14 / 29 文檔可自由編輯打印for 對于當前進程 current-mm 中的每一個 VMA 塊,調用 vm_ops-unmap 釋放該 VMA 塊對應的虛擬空間調用 zap_page_range 將指向釋放掉的

32、虛擬空間中的 pte 頁表項清零。調用 kfree 釋放該 VMA 塊結構占用的物理空間。free_page_tables(mm);/將 mm-pdg 中所有的 pte 頁表項清空,并將 mm-pdg 清空kfree(mm);current-mm = init.mm/end for _exit_mm(current);_exit_files(current);_exit_fs(current);_exit_sighand(current);/end for do_exit;3、缺頁中斷服務、缺頁中斷服務當程序在運行中,訪問到的無效的虛擬地址的時候,系統(tǒng)將激發(fā)出缺頁中斷。激發(fā)缺頁中斷的情況通常有

33、四種:1.COW 型中斷,當某個進程進行寫操作時,如果寫的頁是多進程在使用時,為了不影響其它進程的正常運行,通常需要將該頁復制一份,供執(zhí)行寫操作的進程單獨使用。2.被訪問的物理頁由于太長時間沒有訪問而被 kswapd 置換到 s 中。3.被訪問的物理頁由于是第一次訪問,所以還在磁盤上或由于訪問后被置換時因為沒有發(fā)生寫操作,而未寫到 s 中。4.當進程動態(tài)的訪問一片存儲區(qū)域時,如在程序中動態(tài)開辟的數(shù)組等,則該頁不在 s 中,也不在磁盤上。缺頁中斷服務入口程序是函數(shù) do_page_faultdo_page_fault 首先進行各種錯誤情況判斷,并作相應處理,然后根據(jù) error_code 來判斷

34、缺頁中斷類型:第一種情況采用 do_wp_page 函數(shù)來處理,第二、三、四種情況由do_no_page 函數(shù)來處理。下面將分別介紹這些函數(shù)的流程圖。void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,unsigned long address, int write_access)15 / 29 文檔可自由編輯打印為復制可寫頁申請一頁空間根據(jù) address 計算pgd ,pmd,pte退出使用該物理頁的進程1 ?將該物理頁置dirty釋放原先分配的復制頁將物理頁復制到復制頁上將復制頁鏈入虛存中將指向原先物

35、理頁的 pte 釋放掉退出異常11圖 7 do_wp_page 示意圖void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,unsigned long address, int write_access)根據(jù) address 計算三級頁表中 pgd/pmd/pte 的值,如無對應的項,分配空間將其填上if ( pte_present(entry) )該頁已在內存中,return;/可能是共享該頁的其他進程已將該頁讀入else if (!pte_none(entry)/情況 2pte 中該項非空,說明該頁被 k

36、swapd 置換到 s 中,調用 do_s 讀入該頁;else if ( !vma-vm_ops | !vma-vm_ops-nopage)/情況 4該頁對應的 VMA 塊沒有相應的 nopage 操作,說明該 VMA 塊對應的是數(shù)據(jù)段內容調用_get_free_page 操作為該頁分配內存,并將該頁賦值為 0,同時鏈入該進程的頁表中else/情況 3調用虛擬塊操作將磁盤中對應文件讀入 page 中,將 pte 表中對應的項指向該頁。將該頁 dirty 位置位,如果該頁有多進程使用,且非共享,置寫保護位。16 / 29 文檔可自由編輯打印第五章第五章 主要函數(shù)分析主要函數(shù)分析Memory.c在

37、該文件中,Linux 提供了對虛擬內存操作的若干函數(shù),其中包括對虛擬頁的復制、新建頁表、清除頁表、處理缺頁中斷等等。1static inline void copy_page(unsigned long from, unsigned long to)為了節(jié)約內存的使用,在系統(tǒng)中,各進程通常采用共享內存,即不同的進程可以共享同一段代碼段或數(shù)據(jù)段。當某一進程發(fā)生對共享的內存發(fā)生寫操作時,為了不影響其它進程的正常運行,系統(tǒng)將把該內存塊復制一份,供需要寫操作的進程使用,這就是所謂的copy-on-write 機制。copy_page 就是提供復制內存功能的函數(shù),它調用 C 語言中標準的內存操作函數(shù),將

38、首地址為 from 的一塊虛擬內存頁復制到首地址為 to 的空間中。2、void clear_page_tables(struct task_struct * tsk)clear_page_table 的功能是將傳入的結構 tsk 中的 pgd 頁表中的所有項都清零,同時將二級頁表所占的空間都釋放掉。傳入 clear_page_tables 的是當前進程的 tsk 結構,取得該進程的一級頁目錄指針 pgd 后,采用循環(huán)的方式,調用 free_one_pgd 清除 pgd 表。表共 1024項。在 free_one_pgd 中,實際執(zhí)行的功能只調用一次 free_one_pmd(在 80 x86

39、 中,由于硬件的限制,只有兩級地址映射,故將 pmd 與 pgd 合并在一起) 。在 free_one_pmd 中,函數(shù)調用 pte_free 將對應于 pmd 的二級頁表所占的物理空間釋放掉(進程代碼、數(shù)據(jù)所用的物理內存在 do_munmap 釋放掉了)并將 pmd 賦值為零。clear_page_table 在系統(tǒng)啟動一個可執(zhí)行文件的映象或載入一個動態(tài)鏈接庫時被調用。在 fs/exec.c 中的 do_load_elf_binary()或 do_load_aout_binary()調用 flash_old_exec,后者調用 exec_mmap,而 exec_mmap 調用 clear_p

40、age_table。其主要功能是當啟動一個新的應用程序的時候,將復制的 mm_struct 中的頁表清除干凈,并釋放掉原有的所有二級頁表空間。3、void oom(struct task_struct * task)返回出錯信息。4、void free_page_tables(struct mm_struct * mm) 17 / 29 文檔可自由編輯打印在 free_page_table 中,大部分的代碼與 clear_page_table 中的函數(shù)一致。所不同的是,該函數(shù)在最后調用了 pgd_free(page_dir),即不光釋放掉二級頁表所占的空間,同時還釋放一級頁目錄所占的空間。這是

41、因為 free_page_tables 被_exit_mm 調用,_exit_mm 又被do_exit (kernel/kernel.c)調用。當進程中止、系統(tǒng)退出或系統(tǒng)重起時都需要用do_exit(屬于進程管理)將所有的進程結束掉。在結束進程過程中 ,將調用free_page_table 將進程的空間全部釋放掉,當然包括釋放進程一級頁目錄所占的空間。5、int new_page_tables(struct task_struct * tsk)該函數(shù)的主要功能是建立新的頁目錄表,它的主要流程如如下:1.調用 pgd_alloc()為新的頁目錄表申請一片 4K 空間 。2.將初始化進程的內存結構

42、中從 768 項開始到 1023 項的內容復制給新的頁表(所有的進程都共用虛擬空間中 3G4G 的內存,即在核心態(tài)時可以訪問所有相同的存儲空間) 。3.調用宏 SET_PAGE_DIR(include/asm/pgtable.h)將進程控制塊 tsk-ts-CR3 的值改為新的頁目錄表的首地址,同時將 CPU 中的 CR3 寄存器的值改為新的頁目錄表的首地址,從而使新進程進入自己的運行空間。4.將 tsk-mm-pgd 改為新的頁目錄表的首地址。new_page_tables 被 copy_mm 調用,而 copy_mm 被 copy_mm_do_fork 調用,這兩個函數(shù)都在 kernel/

43、fork.c 中。同時,new_page_tables 也可以在 exec_mmap(fs/exec.c)中調用。即新的進程的產生可以通過兩種途徑,一種是 fork,在程序中動態(tài)地生成新的進程,這樣新進程的頁表原始信息利用 copy_mm 從其父進程中繼承而得,另一種是運行一個可執(zhí)行文件映象,通過文件系統(tǒng)中的 exec.c,將映象復制到 tsk 結構中。兩種方法都需要調用new_page_tables 為新進程分配頁目錄表。6、static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow)將原 pte 頁表項

44、復制到 new_pte 上,其流程如下:1.檢測 old_pte 是否在內存中,如不在物理內存中,調用 s 按 old_pte 在 s 中的入口地址,將 old_pte 復制到內存中,同時把 old_pte 的入口地址賦給 new_pte 并返回。反之轉向 3。2.獲取 old_pte 對應的物理地址的頁號。18 / 29 文檔可自由編輯打印3.根據(jù)頁號判斷 old_pte 是否為系統(tǒng)保留的,如果為系統(tǒng)保留的,這些頁為所有的進程在核心態(tài)下使用,用戶進程沒有寫的權利,則只需將 old_pte 指針直接轉賦給 new_pte 后返回。反之則該 pte 屬于普通內存的,則轉向 4。4.根據(jù)傳入的 C

45、-O-W 標志,為 old_pte 置寫保護標志,如果該頁是從 s 中得來的,將 old_pte 頁置上“dirty”標志。將 old_pte 賦值給 new_pte。5.將 mem_map 結構中關于物理內存使用進程的個數(shù)的數(shù)值 count 加 1。7、static inline int copy_pte_range(pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long address, unsigned long size, int cow)通過循環(huán)調用 copy_one_pte 將從源 src_pmd 中以地址 address 開始的長度為 size

46、 的空間復制給 dst_pmd 中。如 dst_pmd 中還未分配地址為 address 的頁表項,則先給三級頁表pte 表分配 4K 空間。 (每調用一次 copy_one_pte 復制 4K 空間。在一次 copy_pte_range 中最多可復制 4M 空間) 。8、static inline int copy_pmd_range(pgd_t *dst_pgd, pgd_t *src_pgd, unsigned long address, unsigned long size, int cow)通過循環(huán)調用 copy_pte_range 將從源 src_pgd 中以地址 address

47、開始的長度為 size 的空間復制給 dst_pgd 中。如 dst_pgd 中還未分配地址為 address 的頁表項,則在一級(同時也是二級)頁表中給對應的 pmd 分配目錄項。9、int copy_page_range(struct mm_struct *dst, struct mm_struct *src,struct vm_area_struct *vma)該函數(shù)的主要功能是將某個任務或進程的 vma 塊復制給另一個任務或進程。其工作機制是循環(huán)調用 copy_pmd_range,將 vma 塊中的所有虛擬空間復制到對應的虛擬空間中。在做復制之前,必須確保新任務對應的被復制的虛擬空間中

48、必須都為零。copy_page_range按 dup_mmap()-copy_mm()-do_fork()的順序被調用(以上三個函數(shù)均在 kernel/fork.c 中) 。當進程被創(chuàng)建的時候,需要從父進程處復制所有的虛擬空間,copy_page_range 完成的就是這個任務。copy_page_range 的函數(shù)調用關系見圖 8。19 / 29 文檔可自由編輯打印copy_page_rangecopy_pmd_rangecopy_pte_rangecopy_one_ptedup_mmapcopy_mmdo_forkkernel/fork.c圖 8 copy_page_range 示意圖9、

49、static inline void free_pte(pte_t page)虛存頁 page 如在內存中,且不為系統(tǒng)的保留內存,調用 free_page 將其釋放掉(如在系統(tǒng)保留區(qū)中,則為全系統(tǒng)共享,故不能刪除) 。如 page 在 s 中,調用 s()將其釋放。10、static inline void forget_pte(pte_t page)如 page 不為空,調用 free_pte 將其釋放。11、static inline void zap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)zap

50、為 zero all pages 的縮寫。該函數(shù)的作用是將在 pmd 中從虛擬地址 address 開始,長度為 size 的內存塊通過循環(huán)調用 pte_clear 將其頁表項清零,調用 free_pte 將所含空間中的物理內存或交換空間中的虛存頁釋放掉。在釋放之前,必須檢查從 address 開始長度為size 的內存塊有無越過 PMD_SIZE.(溢出則可使指針逃出 01023 的區(qū)間)。12、static inline void zap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)函數(shù)結構與 zap_p

51、te_range 類似,通過調用 zap_pte_range 完成對所有落在 address 到address+size 區(qū)間中的所有 pte 的清零工作。zap_pmd_range 至多清除 4M 空間的物理內存。13、int zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)20 / 29 文檔可自由編輯打印函數(shù)結構與前兩個函數(shù)類似。將任務從 address 開始到 address+size 長度內的所有對應的 pmd 都清零。zap_page_range 的調用關系與被調用的關系如

52、圖 9 可知。zap_page_range的主要功能是在進行內存收縮、釋放內存、退出虛存映射或移動頁表的過程中,將不在使用的物理內存從進程的三級頁表中清除。 (在討論 clear_page_tables 時,就提到過當進程退出時,釋放頁表之前,先保證將頁表對應項清零,保證在處于退出狀態(tài)時,進程不占用03G 的空間。 )zap_page_rangevm_truncatedo_munmapexit_mmapmove_page_tableszap_pmd_rangezap_pte_rangefree_page圖 9 zap_page_range 調用關系示意圖14、static inline voi

53、d zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pte_t zero_pte)15、static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size, pte_t zero_pte)16、int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)這三個函數(shù)與前面的三個函數(shù)從結構

54、上看很相似,他們的功能是將虛擬空間中從地址address 開始,長度為 size 的內存塊所對應的物理內存都釋放掉,同時將指向這些區(qū)域的pte 都指向系統(tǒng)中專門開出的長度為 4K,全為 0 的物理頁。zeromap_page_range 在 kernel代碼中沒有被引用,這個函數(shù)是舊版本的 Linux 遺留下來的,在新版本中已經被zap_page_range 所替代。17、static inline void remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,unsigned long offset,

55、pgprot_t prot)18、static inline int remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,unsigned long offset, pgprot_t prot)19、int remap_page_range(unsigned long from, unsigned long offset, unsigned long size, 21 / 29 文檔可自由編輯打印pgprot_t prot)這三個函數(shù)也同前面的函數(shù)一樣,層層調用,現(xiàn)僅介紹一下最后一個函數(shù)的作用。remap

56、_page_range 的功能是將原先被映射到虛擬內存地址 from 處的,大小為 size 的虛擬內存塊映射到以偏移量 offset 為起始地址的虛擬內存中,同時將原來的 pte、pmd 項都清零。該函數(shù)也是逐級調用,在 remap_pte_range 中,通過 set_pte 將的物理頁映射到新的虛擬內存頁表項 pte 上。remap_page_range 函數(shù)的功能與下文中的 remap.c 中介紹的功能相近,因此在 kernel 中也沒有用到。20、unsigned long put_dirty_page(struct task_struct * tsk, unsigned long

57、page,unsigned long address)將虛擬內存頁 page 鏈接到任務 tsk 中虛擬地址為 address 的虛擬內存中,其主要調用的流程如下:put_dirty_page-setup_arg_page-do_load_xxx_binary(xxx 為 aout 或 elf,這些函數(shù)都在 fsexec.c 中),它的功能是將在載入可執(zhí)行文件的時候,將其相關的堆棧信息、環(huán)境變量等復制到當前進程的空間上。21、void handle_mm_fault(struct vm_area_struct * vma, unsigned long address, int write_ac

58、cess)用于處理 ALPHA 機中的缺頁中斷22 / 29 文檔可自由編輯打印mmap.c在 mmap.c 中,主要提供了對進程內存管理進行支持的函數(shù),主要包括了do_mmap、do_munmap 等對進程的虛擬塊堆 avl 數(shù)進行管理的函數(shù)。圖 10 mmap.c 中函數(shù)調用圖有關有關 avl 樹的一些操作:樹的一些操作:1、static inline void avl_neighbours (struct vm_area_struct * node, struct vm_area_struct * tree, struct vm_area_struct * to_the_left, st

59、ruct vm_area_struct * to_the_right)尋找 avl 樹 tree 中的節(jié)點 node 的前序節(jié)點和后序節(jié)點,將結果放在指針 to_the_left 和to_the_right 中,即使得*to_the_left-next=node,node-next=*to_the_right。在實際搜索中,過程是找到 node 節(jié)點中的左節(jié)點的最右節(jié)點和右節(jié)點的最左節(jié)點,采用 avl 樹搜索可以提高效率。2、static inline void avl_rebalance (struct vm_area_struct * nodeplaces_ptr, int count)將

60、由于插入操作或刪除操作而造成不平衡的 avl 樹恢復成平衡狀態(tài)。nodeplaces_ptr 是指向的是需要調整的子樹的根節(jié)點,count 是該子樹的高度。3、 static inline void avl_insert (struct vm_area_struct * new_node, struct vm_area_struct * ptree)將新節(jié)點 new_node 插入 avl 樹 ptree 中,并將該樹重新生成平衡 avl 樹。在創(chuàng)建 avl 樹時,將 vma 模塊不斷的插入 avl 樹中,構建一個大的 avl 樹。當進程創(chuàng)建時,復制父進程后需要將以雙向鏈表拷貝過來的 vma 鏈生成 avl

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論