task_struct中的mm_struct

  //关于进程的地址空间,指向进程的地址空间。(链表和红黑树)
  struct mm_struct *mm, *active_mm;

mm_struct 内存描述符结构体

一个进程的虚拟地址空间主要由两个数据结构来描述。 一个是最高层次的mm_struct, 一个是较高层次的 vm_area_struct。

mm_struct 结构描述了一个进程的整个虚拟地址空间。 vm_area_truct描述了虚拟地址空间的一个区间(简称虚拟区)。

每个进程只有一个mm_struct结构,在每个进程的task_struct结构中,有一个指向该进程的结构。可以说,mm_struct结构是对整个用户空间的描述。

struct mm_struct {
    struct {
        struct vm_area_struct *mmap;        //  指向线性区对象的链表头
        struct rb_root mm_rb;                     //  指向线性区对象的红黑树
        u64 vmacache_seqnum;                 //   vmacache

//  用于在进程地址空间中搜索有效的进程地址空间的函数
#ifdef 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;    /* base of mmap area */

// 标识在mmap区域间隔的大小
        unsigned long mmap_legacy_base;    /* base of mmap area in bottom-up allocations */

// 进程虚拟空间的大小
        unsigned long task_size;    /* size of task vm space */
// 最高的虚拟地址结束地址
        unsigned long highest_vm_end;    /* highest vma end address */

// 指向页表的目录
        pgd_t * pgd;

// 共享进程的个数
        atomic_t mm_users;

// 内存描述符的主使用计数器,采用引用计数原理,但为0表示无用户再次使用
        atomic_t mm_count;

// 是否固定
        atomic_t has_pinned;

// 写保护,在使用COW时使用
        seqcount_t write_protect_seq;

// 线性区的个数
        int map_count;            /* number of VMAs */

// 保护进程页表和引用计数的锁
        spinlock_t page_table_lock; /* Protects page tables and some
                         * counters
                         */
        struct rw_semaphore mmap_lock;

// 
        struct list_head mmlist; /* List of maybe swapped mm's.    These
                      * are globally strung together off
                      * init_mm.mmlist, and are protected
                      * by mmlist_lock
                      */

// 进程拥有的最大页表数目
        unsigned long hiwater_rss; /* High-watermark of RSS usage */
// 进程线性区的最大页表数目
        unsigned long hiwater_vm;  /* High-water virtual memory usage */

// 已经映射的页数量
        unsigned long total_vm;       /* Total pages mapped */
// 被锁住的页数量
        unsigned long locked_vm;   /* Pages that have PG_mlocked set */
// 
        atomic64_t    pinned_vm;   /* Refcount permanently increased */
        unsigned long data_vm;       /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
        unsigned long exec_vm;       /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
// 用户堆栈的页数
        unsigned long stack_vm;       /* VM_STACK */
        unsigned long def_flags;

        spinlock_t arg_lock; /* protect the below fields */

//   代码段的起始地址 结束地址  数据段的起始地址 结束地址
        unsigned long start_code, end_code, start_data, end_data;
//  堆的起始地址和结束地址 栈的起始地址
        unsigned long start_brk, brk, start_stack;
//  命令行参数的起始地址 结束地址  环境变量的起始地址 结束地址
        unsigned long arg_start, arg_end, env_start, env_end;

        unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */

        /*
         * Special counters, in some configurations protected by the
         * page_table_lock, in other configurations by being atomic.
         */
        struct mm_rss_stat rss_stat;

        struct linux_binfmt *binfmt;

        /* Architecture-specific MM context */
        mm_context_t context;

        unsigned long flags; /* Must use atomic bitops to access */

        struct core_state *core_state; /* coredumping support */

#ifdef CONFIG_AIO
        spinlock_t            ioctx_lock;
        struct kioctx_table __rcu    *ioctx_table;
#endif
#ifdef CONFIG_MEMCG

        struct task_struct __rcu *owner;
#endif

// 命名空间
        struct user_namespace *user_ns;

        /* store ref to file /proc/<pid>/exe symlink points to */
        struct file __rcu *exe_file;

        struct uprobes_state uprobes_state;
        struct work_struct async_put_work;

    } __randomize_layout;

    unsigned long cpu_bitmap[];
};

mm_struct 结构

vm_area_struct

struct vm_area_struct {

// 起始地址
    unsigned long vm_start;        /* Our start address within vm_mm. */
// 结束地址在vm_mm之后的第一个字节
    unsigned long vm_end;        /* The first byte after our end address
                       within vm_mm. */

// 每个进程的vm区域的链表
    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.
     */
// VMA 左侧最大的可用内存间隙,在此VMA和vma->vm_prev之间或者VMA rbtree中一个VMA与vm_prev之间。 这有助于get_unmapped_area函数找到适合大小的空闲区域
    unsigned long rb_subtree_gap;

// 该VMA隶属的地址空间
    struct mm_struct *vm_mm;    /* The address space we belong to. */

// 此VMA的访问权限 
    pgprot_t vm_page_prot;
    unsigned long vm_flags;        /* Flags, see mm.h. */

// 对于具有地址空间和后备存储的区域,连接到address_space->i_mmap间隔树,或者链接到address_space->i_mmap_nonliner列表中的vma
    struct {
        struct rb_node rb;
        unsigned long rb_subtree_last;
    } 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_lock &
                      * page_table_lock */
    struct anon_vma *anon_vma;    /* Serialized by page_table_lock */

// 用于处理此结构体的函数指针
    const struct vm_operations_struct *vm_ops;

// 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) */

#ifdef CONFIG_SWAP
    atomic_long_t swap_readahead_info;
#endif
#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;
} __randomize_layout;

进程建立vm_area_struct结构后,只是说明进程可以访问这个虚存空间,但有可能还没有分配相应的物理页面并建立好页面映射。在这种情况 下,若是进程执行中有指令需要访问该虚存空间中的内存,便会产生一次缺页异常。这时候,就需要通过vm_area_struct结构里面的 vm_ops->nopage所指向的函数来将产生缺页异常的地址对应的文件数据读取出来。

文档更新时间: 2021-03-15 10:46   作者:周国强