處理非連續記憶體區訪問

2021-05-22 17:10:07 字數 1573 閱讀 3790

回憶一下「缺頁異常處理程式 」,當出現缺頁異常,並且是程序處於核心態,即do_page_fault()中的那個if (unlikely(address >= task_size))分支語句後,將通過vmalloc_fault(address)判斷該發生缺頁異常的位址address是否處於非連續記憶體區:(arch/i386/mm/fault.c)

static inline int vmalloc_fault(unsigned long address)

我們已經在「非連續記憶體區 」博文中看到,核心在更新非連續記憶體區對應的頁表項時是非常獺惰的。事實上,vmalloc()和vfree()函式只把自己限制在更新主核心頁表(即頁全域性目錄init_mm.pgd和它的子頁表)。

然而,一旦核心初始化階段結束,任何程序或核心執行緒便都不直接使用主核心頁表。 因此,我們來考慮核心態程序對非連續記憶體區的第一次訪問。當把線性位址轉換為實體地址時,cpu的記憶體管理單元肯定會遇到空的頁表項並產生乙個缺頁。

但是,缺頁異常處理程式認識這種特殊情況,因為異常發生在核心態且產生缺頁的線性位址大於task_size。因此,vmalloc_fault()檢查相應的主核心頁表項:

pgd_paddr = read_cr3();

#define read_cr3() ()

static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)

#define pte_offset_kernel(dir, address) /

((pte_t *) pmd_page_kernel(*(dir)) +  pte_index(address))

#define pte_index(address) /

(((address) >> page_shift) & (ptrs_per_pte - 1))

#define pmd_page_kernel(pmd) /

((unsigned long) __va(pmd_val(pmd) & page_mask))

#define pmd_val(x)    ((x).pmd)

把存放在cr3暫存器中的當前程序頁全域性目錄的實體地址賦給區域性變數pgd_paddr(核心不使用current->mm_pgd匯出當前程序的頁全域性目錄位址,因為這種缺頁可能在任何時刻都發生,甚至在程序切換期間發生。),把與pgd_paddr相應的線性位址賦給區域性變數pgd,並且把主核心頁全域性目錄的線性位址賦給pgd_k區域性變數。

如果產生缺頁的線性位址所對應的主核心頁全域性目錄項為空,即if(!pud_present(*pud_k)),則vmalloc_sync_one()返回null,vmalloc_fault()函式返回-1。否則,函式檢查與錯誤線性位址相對應的主核心頁上級目錄項和主核心頁中間目錄項。如果它們中有乙個為空,vmalloc_fault()就返回-1。

否則,就把主目錄項複製到程序頁中間目錄的相應項中(set_pmd(pmd, *pmd_k),如果pae被啟用,頁上級目錄項就不可能為空;如果沒有啟用pae,設五頁中間目錄項的同時也就隱含設里了頁上級目錄項。)。

隨後對頁表項重複上述整個操作(pte_k = pte_offset_kernel(pmd_k, address))。

非連續記憶體區

從前面的博文中我們已經知道,把一塊存放slab結構的記憶體區對映到一組連續的物理頁是最好的選擇,這樣會充分利用快取記憶體並獲得較低的平均訪問時間。不過,上面的方式主要是針對那些使用非常頻繁的核心資料結構 如task struct inode來設計的。如果對記憶體區的請求不是很頻繁,那麼,通過連續的線...

初始化非連續記憶體區

回到 mm init 函式,繼續走,下乙個函式 pgtable cache init 不知道咋的,是個空函式,也許是保留著以後開發吧。最後乙個函式是 vmalloc init 來自mm vmalloc.c 1088void init vmalloc init void 1089 1101 1102 ...

OS 非連續記憶體分配

利用調整程序占用的分割槽位置,來減少或避免分割槽碎片。2.分割槽對換 通過搶占並 處於等待狀態的程序分割槽,增大可用記憶體空間,將等待狀態的程序掛起。在連續記憶體分配的過程中,不可避免的要產生記憶體碎片,從而使得連續記憶體分配難以實現,並且記憶體利用效率較低。從而需要對記憶體碎片進行更好的利用 非連...