文章目录
- 一、vm_area_struct 结构体成员分析
-
- 1、vm_ops 成员
- 二、vm_operations_struct 结构体成员分析
-
- 1、open 函数指针
- 2、close 函数指针
- 3、mremap 函数指针
- 4、fault 函数指针
- 5、huge_fault 函数指针
- 6、map_pages 函数指针
- 7、page_mkwrite 函数指针
- 三、vm_area_struct 结构体完整源码
- 四、vm_operations_struct 结构体完整源码
在博客 【Linux 内核 内存管理】虚拟地址空间布局架构 ⑦ ( vm_area_struct 结构体成员分析 | vm_start | vm_end | vm_next | vm_prev |vm_rb) 中 , 分析了 vm_start
vm_end
vm_next
vm_prev
vm_rb
这
个结构体成员作用 ;
在博客 【Linux 内核 内存管理】内存映射相关数据结构 ② ( vm_area_struct 结构体成员分析 | vm_mm 成员 | vm_page_prot 成员 | vm_flags 成员 ) 中 , 分析了 vm_area_struct
结构体中的 vm_mm
vm_page_prot
vm_flags
成员作用 ;
在博客 【Linux 内核 内存管理】内存映射相关数据结构 ③ ( vm_area_struct 结构体成员分析 | shared 成员 | anon_vma_chain 成员 | anon_vma 成员 ) 中 , 分析了 vm_area_struct
结构体中的 shared
anon_vma_chain
anon_vma
成员作用 ;
一、vm_area_struct 结构体成员分析
1、vm_ops 成员
vm_ops
成员是 " 虚拟内存操作集合 " , 该 vm_operations_struct
结构体中封装了大量的虚拟内存操作 ;
/* Function pointers to deal with this struct. */
const struct vm_operations_struct *vm_ops;
二、vm_operations_struct 结构体成员分析
vm_operations_struct
结构体 定义在 Linux 内核源码的 linux-4.12includelinuxmm.h#361 位置 ;
/*
* These are the virtual MM functions - opening of an area, closing and
* unmapping it (needed to keep files on disk up-to-date etc), pointer
* to the functions called when a no-page or a wp-page exception occurs.
*/
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
int (*mremap)(struct vm_area_struct * area);
int (*fault)(struct vm_fault *vmf);
int (*huge_fault)(struct vm_fault *vmf, enum page_entry_size pe_size);
void (*map_pages)(struct vm_fault *vmf,
pgoff_t start_pgoff, pgoff_t end_pgoff);
下面对 vm_operations_struct
结构体成员进行分析 ;
1、open 函数指针
open
函数指针 , 指向的函数 , 在 创建 " 虚拟内存区域 " 时调用 ;
void (*open)(struct vm_area_struct * area);
2、close 函数指针
close
函数指针 , 指向的函数 , 在 删除 " 虚拟内存区域 " 时调用 ;
void (*close)(struct vm_area_struct * area);
3、mremap 函数指针
mremap
函数指针 , 指向的函数 , 在 使用系统调用 mremap
函数 移动 " 虚拟内存区域 " 时调用 ;
int (*mremap)(struct vm_area_struct * area);
4、fault 函数指针
在 【Linux 内核 内存管理】内存映射原理 ② ( 内存映射概念 | 文件映射 | 匿名映射 | 内存映射原理 | 分配虚拟内存页 | 产生缺页异常 | 分配物理内存页 | 共享内存 | 进程内存 ) 博客中 , 介绍了内存映射的原理 , 分配 " 虚拟内存区域 " 后 ,
第一次访问会产生 " 缺页异常 " ,
之后对于 " 文件映射 " , 如果没有映射 " 物理内存页 " , 就会回调 fault
函数 , 将 文件中的数据 读取到 " 物理内存页 " 中 ;
fault
函数指针 , 指向的函数 , 就是在 回调 fault
函数时 时调用 ;
int (*fault)(struct vm_fault *vmf);
5、huge_fault 函数指针
huge_fault
函数指针 , 与上面的 fault
函数指针类似 , 只是 huge_fault
函数指针针对的是 使用 " 透明巨型页 " 的文件映射 的情况 ;
int (*huge_fault)(struct vm_fault *vmf, enum page_entry_size pe_size);
6、map_pages 函数指针
在 【Linux 内核 内存管理】内存映射原理 ② ( 内存映射概念 | 文件映射 | 匿名映射 | 内存映射原理 | 分配虚拟内存页 | 产生缺页异常 | 分配物理内存页 | 共享内存 | 进程内存 ) 博客中 , 介绍了内存映射的原理 , 分配 " 虚拟内存区域 " 后 ,
第一次访问 " 文件映射 " 对应的 " 虚拟内存页 " 时 , 如果发现 文件 没有映射到该 " 虚拟内存页中 " , 会报 " 缺页异常 " ,
" 异常处理程序 " 会读取 正在访问的文件页 , 以及 预读取 后续的文件页 ,
调用 map_pages
函数指针指向的函数 , 为 文件页 分配 " 物理内存页 " ;
void (*map_pages)(struct vm_fault *vmf,
pgoff_t start_pgoff, pgoff_t end_pgoff);
7、page_mkwrite 函数指针
要 修改 " 私有文件映射 " 对应的 " 虚拟文件页 " 时 ,
如果是 第一次 写该 内存映射 时 , 会生成 " 页错误异常 " ,
" 异常处理程序 " 会执行 " 写复制 " 机制 ,
调用该 page_mkwrite
函数指针指向的函数 , 通知该 " 文件页 " 马上要变成可写状态 ,
此时 " 文件系统 " 会检查该 写操作 是否合法 , 是否允许修改该 文件页 , 是否需要等待以便进入合适的状态再进行写操作 ;
代码语言:javascript复制 /* notification that a previously read-only page is about to become
* writable, if an error is returned it will cause a SIGBUS */
int (*page_mkwrite)(struct vm_fault *vmf);
三、vm_area_struct 结构体完整源码
vm_area_struct
结构体完整源码 :
/*
* This struct defines a memory VMM memory area. There is one of these
* per VM-area/task. A VM area is any part of the process virtual memory
* space that has a special rule for the page-fault handlers (ie a shared
* library, the executable area etc).
*/
struct vm_area_struct {
/* The first cache line has the info for VMA tree walking. */
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 */
struct vm_area_struct *vm_next, *vm_prev;
struct rb_node vm_rb;
/*
* Largest free memory gap in bytes to the left of this VMA.
* Either between this VMA and vma->vm_prev, or between one of the
* VMAs below us in the VMA rbtree and its ->vm_prev. This helps
* get_unmapped_area find a free area of the right size.
*/
unsigned long rb_subtree_gap;
/* Second cache line starts here. */
struct mm_struct *vm_mm; /* The address space we belong to. */
pgprot_t vm_page_prot; /* Access permissions of this VMA. */
unsigned long vm_flags; /* Flags, see mm.h. */
/*
* For areas with an address space and backing store,
* linkage into the address_space->i_mmap interval tree.
*/
struct {
struct rb_node rb;
unsigned long rb_subtree_last;
} shared;
/*
* A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
* list, after a COW of one of the file pages. A MAP_SHARED vma
* can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
* or brk vma (with NULL file) can only be in an anon_vma list.
*/
struct list_head anon_vma_chain; /* Serialized by mmap_sem &
* page_table_lock */
struct anon_vma *anon_vma; /* Serialized by page_table_lock */
/* Function pointers to deal with this struct. */
const struct vm_operations_struct *vm_ops;
/* Information about our backing store: */
unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE
units */
struct file * vm_file; /* File we map to (can be NULL). */
void * vm_private_data; /* was vm_pte (shared mem) */
#ifndef CONFIG_MMU
struct vm_region *vm_region; /* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *vm_policy; /* NUMA policy for the VMA */
#endif
struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
};
四、vm_operations_struct 结构体完整源码
vm_operations_struct
结构体完整源码 :
/*
* These are the virtual MM functions - opening of an area, closing and
* unmapping it (needed to keep files on disk up-to-date etc), pointer
* to the functions called when a no-page or a wp-page exception occurs.
*/
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
int (*mremap)(struct vm_area_struct * area);
int (*fault)(struct vm_fault *vmf);
int (*huge_fault)(struct vm_fault *vmf, enum page_entry_size pe_size);
void (*map_pages)(struct vm_fault *vmf,
pgoff_t start_pgoff, pgoff_t end_pgoff);
/* notification that a previously read-only page is about to become
* writable, if an error is returned it will cause a SIGBUS */
int (*page_mkwrite)(struct vm_fault *vmf);
/* same as page_mkwrite when using VM_PFNMAP|VM_MIXEDMAP */
int (*pfn_mkwrite)(struct vm_fault *vmf);
/* called by access_process_vm when get_user_pages() fails, typically
* for use by special VMAs that can switch between memory and hardware
*/
int (*access)(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write);
/* Called by the /proc/PID/maps code to ask the vma whether it
* has a special name. Returning non-NULL will also cause this
* vma to be dumped unconditionally. */
const char *(*name)(struct vm_area_struct *vma);
#ifdef CONFIG_NUMA
/*
* set_policy() op must add a reference to any non-NULL @new mempolicy
* to hold the policy upon return. Caller should pass NULL @new to
* remove a policy and fall back to surrounding context--i.e. do not
* install a MPOL_DEFAULT policy, nor the task or system default
* mempolicy.
*/
int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
/*
* get_policy() op must add reference [mpol_get()] to any policy at
* (vma,addr) marked as MPOL_SHARED. The shared policy infrastructure
* in mm/mempolicy.c will do this automatically.
* get_policy() must NOT add a ref if the policy at (vma,addr) is not
* marked as MPOL_SHARED. vma policies are protected by the mmap_sem.
* If no [shared/vma] mempolicy exists at the addr, get_policy() op
* must return NULL--i.e., do not "fallback" to task or system default
* policy.
*/
struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
unsigned long addr);
#endif
/*
* Called by vm_normal_page() for special PTEs to find the
* page for @addr. This is useful if the default behavior
* (using pte_page()) would not find the correct page.
*/
struct page *(*find_special_page)(struct vm_area_struct *vma,
unsigned long addr);
};