linux vma,内存管理 – Linux内核API find_vma
find_vma函數功能描述:find_vma( )函數根據一個屬于某個進程的虛擬地址,找到其所屬的進程虛擬區間,并返回相應的vma_area_struct結構體指針。
find_vma文件包含
#include
find_vma函數定義
在內核源碼中的位置:linux-3.19.3/mm/mmap.c
函數定義格式:
struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
find_vma輸入參數說明
mm:是進程整個用戶空間的抽象,也是總的控制結構,一個進程只有一個mm_struct結構,一個進程整個用戶空間通常有若干離散的虛擬區間,這些虛擬區間由vm_area_struct結構描述。
addr:是進程用戶空間中一虛擬地址,它屬于某一虛擬區間。
find_vma返回參數說明
struct vm_area_struct是對進程虛擬區間抽象的數據結構,find_vma( )函數返回一個該結構類型指針,該指針指向描述進程中虛擬地址addr所在虛擬區間的結構體。
其中,struct mm_struct和struct vm_area_struct在文件linux-3.19.3/include/linux/mm_types.h中定義,它們的具體結構如下,這里對部分字段的含義進行了說明:
struct mm_struct {
struct vm_area_struct * mmap; /* 指向線性區對象的鏈表頭 */
struct rb_root mm_rb;
u32 vmacache_seqnum; /*每一個線程的vmacache序列號*/
#if def CONFIG_MMU
/* 在進程地址空間忠搜索有效線性地址區間的方法 */
unsigned long (*get_unmapped_area) (struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags);
#endif
/* 標識第一個分配的匿名線性區或文件內存映射的線性地址 */
unsigned long mmap_base;
unsigned long mmap_legacy_base;
unsigned long task_size;
unsigned long highest_vm_end;
/* 內核從這個地址開始搜索進程地址空間中線性地址的空閑區間 */
pgd_t * pgd; /*指向頁全局目錄 */
atomic_t mm_users; /* 次使用計數器 */
atomic_t mm_count; /* 主使用計數器*/
atomic_long_t nr_ptes; /*頁表所在的頁*/
int map_count; /* 線性區vma的個數 */
spinlock_t page_table_lock; /* 線性區的自旋鎖和頁表的自旋鎖 */
struct rw_semaphore mmap_sem; /* 線性區的讀/寫信號量 */
struct list_head mmlist; /* 指向內存描述符鏈表中的相鄰元素*/
unsigned long hiwater_rss;
unsigned long hiwater_vm;
/**total_vm指進程地址空間的大小(頁數), locked_vm指“鎖住”而不能換出的頁的個數,
**shared_vm指共享文件內存映射中的頁數,exec_vm指可執行內存映射中的頁數*/
unsigned long total_vm, locked_vm, pinned_vm, shared_vm, exec_vm;
/*stack_vm指用戶堆棧中的頁數*/
unsigned long stack_vm, def_flags;
/*start_code指可執行的起始地址,end_code指可執行代碼的最后地址,start_data
**指已初始化數據的起始地址,end_data指已初始化數據的最后地址*/
unsigned long start_code, end_code, start_data, end_data;
/*start_ brk指堆的起始地址,brk指堆的當前最后地址,start_ stack指用戶態堆棧的起始地址*/
unsigned long start_brk, brk, start_stack;
/* arg_start指命令行參數起始地址,arg_end指命令行參數的最后地址,
**env_start指環境變量的起始地址,env_end指環境變量的最后地址*/
unsigned long arg_start, arg_end, env_start, env_end;
……
……
};
struct vm_area_struct {
unsigned long vm_start; /* 線性區的第一個線性地址 */
unsigned long vm_end; /* 線性區之后的第一個線性地址 */
struct vm_area_struct *vm_next, *vm_prev; /* 進程鏈表中的下一個線性區及上一個線性區*/
struct rb_node vm_rb; /* 用于紅黑樹的數據*/
unsigned long rb_subtree_gap;
struct mm_struct * vm_mm; /*指向線性區所在的內存描述符 */
pgprot_t vm_page_prot; /* 線性區中頁框的訪問許可權 */
unsigned long vm_flags; /* 線性區的標志*/
……
……
struct list_head anon_vma_node; /* 指向匿名線性區鏈表的指針 */
struct anon_vma * anon_vma; /* 指向anon_vma數據結構的指針 */
const struct vm_operations_struct * vm_ops; /* 指向線性區的方法 */
unsigned long vm_pgoff; /*在映射文件中的偏移量,對于匿名頁,它等于0或vm_start/PAGE_SIZE*/
struct file * vm_file; /* 指向映射文件的文件對象 */
void * vm_private_data; /* 指向內存區的私有數據 */
……
……
};
find_vma實例解析
編寫測試文件:find_vma.c
頭文件及全局變量聲明如下:
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
static int __init find_vma_init(void);
static void __exit find_vma_exit(void);
模塊初始化函數:
int __init find_vma_init(void)
{
struct mm_struct *mm ;
unsigned long addr ;
struct vm_area_struct * vma ;
mm = current->mm; //mm指向當前進程
addr = mm->mmap->vm_next->vm_start + 1;
printk("addr = 0x%lx\n", addr);
vma = find_vma(mm, addr);
if(vma ! = NULL )
{
/*輸出所查找的虛擬區間的起始地址*/
printk("vma->vm_start = 0x%lx\n", vma->vm_start);
/*輸出所查找虛擬區間的結束地址*/
printk("vma->vm_end = 0x%lx\n", vma->vm_end);
}
else
printk("UNLUCK! You have failed! \n");
return 0;
}
模塊退出函數:
void __exit find_vma_exit(void)
{
printk("exit! \n");
}
模塊初始化及退出函數調用:
module_init(find_vma_init);
module_exit(find_vma_exit);
實例運行結果及分析:
首先編譯模塊,執行命令insmod find_vma.ko插入模塊,然后執行命令dmesg -c,會出現如圖所示的結果。
結果分析:
““mm = current->mm; ”`獲取當前進程用戶空間。
令“ addr = mm->mmap->vm_next->vm_start + 1; ”此時addr即為用戶空間中的某一虛擬地址,這里為當前進程第二個虛擬區間的起始地址加1,由輸出結果可知addr = 0x7fb896ce6001。然后調用find_vma( )函數查詢addr所在的虛擬區間,將描述該虛擬區間的結構體指針賦值給vma,最后通過輸出vma的vm_start和vm_end值驗證了查找成功。
總結
以上是生活随笔為你收集整理的linux vma,内存管理 – Linux内核API find_vma的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: K3销售订单携带批号至销售出库单
- 下一篇: [译] RNN 循环神经网络系列 2:文