內存管理之9:磁盤頁面的抽象

date: 2014-10-01 19:09linux

在講《x86頁式內存管理》中提到過「頁面交換」。一個系統的物理內存老是有限的,可是運行在其上的進程卻不敢不顧的一味「索取」,爲了解決這種困境,在計算機的發展史上很早就有將內存中的內容與一個專用的磁盤空間交換的技術,即把內存中暫時不用的內容存到磁盤上,爲其餘急用的內容騰出內存空間,到須要時再將磁盤上的內容讀到內存中。數組

在繼續以前,要明確幾個概念。首先「虛存頁面」指虛擬地址空間中一個固定大小,邊界與頁面大小(4KB)對齊的區間及內容。「虛存頁面」最終要落實(映射)到某種物理存儲介質上,這就是「物理頁面」。根據介質的不一樣,「物理頁面」分爲「內存頁面」(在內存中)和「磁盤頁面」(在磁盤上)。當咱們談及(物理)內存頁面的分配和釋放時,指的僅是物理介質;而在談及頁面的換入換出時,指的是頁面中的內容。app

咱們在討論(物理)內存頁面時提到page結構就是內存頁面的戶口,系統在初始化階段,內核根據檢測到的內存的大小,爲每個頁幀創建page結構,造成一個page結構的數組,並用全局變量mem_map指向這個數組,mem_map就像是物理內存的戶口簿,有了這個戶口簿系統就能夠跟蹤到每個頁幀。spa

那麼「磁盤頁面」呢?「磁盤頁面」是如何管理的呢?code

1 交換設備的抽象swap_info_struct

首先,對「磁盤頁面」內核並無對應的結構體,由於磁盤頁面要依附在「交換設備」(一般是磁盤,也能夠是普通文件,設備即文件)上,從內核管理磁盤頁面角度來看,只需知道它在交換設備上的位置,以及該頁面的使用計數(表示該頁面是否被使用,以及有幾個用戶在共享該頁面)便可。一個交換設備上的磁盤頁面確定具備相同的屬性,這些屬性信息從交換設備上獲取便可。於是,內核對磁盤頁面的管理是按交換設備來進行的。交換設備對應的抽象爲swap_info_struct結構,而「磁盤頁面」的定義也是依附在swap_info_struct結構體中。blog

swap_info_struct結構定義以下:進程

<include/linux/swap.h>
    struct swap_info_struct {
    	unsigned int flags;
    	kdev_t swap_device;
    	spinlock_t sdev_lock;
    	struct dentry * swap_file;
    	struct vfsmount *swap_vfsmnt;
    	unsigned short * swap_map;
    	unsigned int lowest_bit;
    	unsigned int highest_bit;
    	unsigned int cluster_next;
    	unsigned int cluster_nr;
    	int prio;			/* swap priority */
    	int pages;
    	unsigned long max;
    	int next;			/* next entry on swap list */
    };
  • swap_file、swap_vfsmnt與文件系統相關。
  • swap_map指向一個unsigned short型的數組,數組中的每個元素表明一個磁盤頁面:元素對應的unsigned short值表明該磁盤頁面的引用計數;而下標則表示磁盤頁面在文件中或者磁盤上的位置。其中第一個元素即swap_map[0]所表明的那個磁盤頁面是不用作頁面交換的,它包含了該交換文件或設備自身的信息以及一個表明哪些頁面可供使用的位圖,這個頁面至關於該交換設備的「控制塊」。數組的大小由成員pages表示,它表示該頁面交換設備的大小。因爲交換設備上某些頁面是不用作交換的,而這些頁面大都集中在交換設備的開頭和結尾,因此lowest_bit和highest_bit分別表示交換設備上用戶交換的頁面的「起始」和「終止」。另外一成員max則表示該交換設備上最大的磁盤頁面號,也就是設備或文件的物理大小。

linux內核容許使用多個交換設備,因此在內核中還有一個swap_info_struct結構數組swap_info,其定義以下:內存

<include/linux/swap.h>
    #define MAX_SWAPFILES 8
    <mm/swapfile.c>
    struct swap_info_struct swap_info[MAX_SWAPFILES];

可見,最多可使用8個交換設備。注意這個全局數組swap_info,內核就是經過這個全局數組找到對應的交換設備的。it

2 磁盤頁面的「頁面表項」的抽象swp_entry_t

就像虛存頁面經過頁面表項pte_t與物理內存頁面創建映射關係同樣,磁盤頁面也有相似的「頁面表項」swp_entry_t。swp_entry_t的定義以下:內存管理

<include/linux/shmem_fs.h>
    
     /*
     * A swap entry has to fit into a "unsigned long", as
     * the entry is hidden in the "index" field of the
     * swapper address space.
     *
     * We have to move it here, since not every user of fs.h is including
     * mm.h, but m.h is including fs.h via sched .h :-/
     */
    typedef struct {
        unsigned long val;
    } swp_entry_t;

可見,swp_entry_t也爲32位的整數,與pte_t同樣,swp_entry_t也將32位分段使用,這裏分紅的3段,示意以下:

swp_entry_t

  • type段指示該頁面在哪一個交換設備(文件)中,是個序號,其實就是全局數組swap_info的下標。
  • offset段表示頁面在交換設備(文件)的位置,也是一個序號,其實就是swap_info_struct結構中數組swap_map的下標。
  • swp_entry_t的bit0必須爲0。其實swp_entry_t就是pte_t的「變身」。回憶前面pte_t的定義,當bit0爲1,表示頁面在內存中,而其他各bit表示該內存頁面的起始地址以及頁面屬性。而當頁面在磁盤上時,則相應的頁面表項pte_t再也不指向一個物理內存頁面,而是「變身」爲swp_entry_t,其bit0爲0,表示頁面不在內存中,因此MMU對其他各bit都忽略不顧,留待內核自由支配,內核也就順勢利用其他的bit指明瞭這個頁面的去向,何樂而不爲呢。

須要說明:當內存頁面交換到磁盤頁面上以後,對應的頁面表項pte_t就「變身」爲swp_entry_t,「變身」後仍駐留在以前的頁表中,此時虛存頁面被映射到一個磁盤頁面上了。當在用戶空間訪問虛存頁面時,根據CR3一步步找到這個頁面表項(swp_entry_t),MMU發現其bit0爲0,瞭解到該頁面不在內存中,因而觸發頁面異常。咱們在前面分析過頁面異常的處理程序do_page_fault,此種狀況又對應另外一種場景:出錯地址沒有落在空洞中,並且就落在某個虛存區間vma中,內核經過讀取對應的swp_entry_t能夠知道該虛存頁面的去向,而後將其換入到內存中。有興趣的同窗能夠自行一觀。

pte_t與swp_entry_t的關係是如此的密切,內核爲此定義了一組宏:

/* Encode and de-code a swap entry */
    #define SWP_TYPE(x)			(((x).val >> 1) & 0x3f)
    #define SWP_OFFSET(x)			((x).val >> 8)
    #define SWP_ENTRY(type, offset)	((swp_entry_t) { ((type) << 1) | ((offset) << 8) })
    #define pte_to_swp_entry(pte)		((swp_entry_t) { (pte).pte_low })
    #define swp_entry_to_pte(x)		((pte_t) { (x).val })
相關文章
相關標籤/搜索