1. 程式人生 > >struct vm_area_struct結構體學習

struct vm_area_struct結構體學習

Linux通過型別為vm_area_struct的結構體物件實現線性區,該結構定義了記憶體VMM記憶體區域。 每個VM區域/任務中有一個。 VM區域是程序虛擬記憶體空間的任何部分,它具有頁面錯誤處理程式的特殊規則(即共享庫,可執行區域等)。

vm_area_struct具體內容如下所示:

struct vm_area_struct {
	/* The first cache line has the info for VMA tree walking. 
	第一個快取行具有VMA樹移動的資訊*/

	unsigned long vm_start;		/* Our start address within vm_mm. */
	unsigned long vm_end;		/* The first byte after our end address within vm_mm. */

	/* linked list of VM areas per task, sorted by address
	每個任務的VM區域的連結列表,按地址排序*/
	struct vm_area_struct *vm_next, *vm_prev;

	struct rb_node vm_rb;

	/*
	 此VMA左側最大的可用記憶體間隙(以位元組為單位)。 
	 在此VMA和vma-> vm_prev之間,
	 或者在VMA rbtree中我們下面的一個VMA與其->vm_prev之間。 
	 這有助於get_unmapped_area找到合適大小的空閒區域。
	 */
	unsigned long rb_subtree_gap;

	/* Second cache line starts here. 
	第二個快取行從這裡開始*/

	struct mm_struct *vm_mm;	/* 我們所屬的address space*/
	pgprot_t vm_page_prot;		/* 此VMA的訪問許可權 */
	unsigned long vm_flags;		/* Flags, see mm.h. */

	/*
	 對於具有地址空間(address apace)和後備儲存(backing store)的區域,
	 連結到address_space->i_mmap間隔樹,或者連結到address_space-> i_mmap_nonlinear列表中的vma。
	 */
	union {
		struct {
			struct rb_node rb;
			unsigned long rb_subtree_last;
		} linear;
		struct list_head nonlinear;
	} shared;

	/*
	 在其中一個檔案頁面的COW之後,檔案的MAP_PRIVATE vma可以在i_mmap樹和anon_vma列表中。
	 MAP_SHARED vma只能位於i_mmap樹中。 
	 匿名MAP_PRIVATE,堆疊或brk vma(帶有NULL檔案)只能位於anon_vma列表中。
	 */
	struct list_head anon_vma_chain; /* Serialized by mmap_sem & * page_table_lock
										由mmap_sem和* page_table_lock序列化*/
	struct anon_vma *anon_vma;	/* Serialized by page_table_lock 由page_table_lock序列化*/

	/* 用於處理此結構體的函式指標 */
	const struct vm_operations_struct *vm_ops;

	/* 後備儲存(backing store)的資訊: */
	unsigned long vm_pgoff;		/* 以PAGE_SIZE為單位的偏移量(在vm_file中),*不是* PAGE_CACHE_SIZE*/
	struct file * vm_file;		/* 我們對映到檔案(可以為NULL)*/
	void * vm_private_data;		/* 是vm_pte(共享記憶體) */

#ifndef CONFIG_MMU
	struct vm_region *vm_region;	/* NOMMU對映區域 */
#endif
#ifdef CONFIG_NUMA
	struct mempolicy *vm_policy;	/* 針對VMA的NUMA政策 */
#endif
};

我們可以把vm_area_struct稱為線性區描述符,它標識了一個線性地址區間。

程序所擁有的線性區從來不重疊,並且核心盡力把新分配的線性區與緊鄰的現有線性區進行合併。如果兩個相鄰區的訪問許可權相匹配,就能把他們合併在一起。

程序所有的線性區是通過一個簡單的連結串列連結在一起的,出現在連結串列中的線性區是按記憶體地址的升序排列的。每兩個線性區可以由未用的記憶體地址區隔開。核心通過程序的記憶體描述符的mmap欄位來查詢線性區,其中mmap欄位指向連結串列中的第一個線性區描述符。同時記憶體描述符的map_count欄位存放程序所擁有的線性區數目。