8. vma操作概述

在32位系统中,每个用户进程可以拥有3GB大小的虚拟地址空间,通常要远大于物理内存,那么如何管理这些虚拟地址空间呢?用户进程通常会多次调用malloc()或使用mmap()接口映射文件到用户空间来进行读写等操作,这些操作都会要求在虚拟地址空间中分配内存块,这些内存块基本上都是离散的。malloc()是用户态常用的分配内存的接口API函数。mmap()是用户态常用的用于建立文件映射或匿名映射的函数。这些进程地址空间在内核中使用struct vm_area_struct数据结构来描述,简称VMA,也被称为进程地址空间或进程线性区。由于这些地址空间归属于各个用户进程,所以在用户进程的struct mm_struct数据结构中也有相应的成员,用于对这些VMA进行管理。

    VMA数据结构定义在mm_types.h(include/linux/mm_types.h)


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

    /*指定VMA在进程地址空间的起始地址*/
    unsigned long vm_start;     /* Our start address within vm_mm. */
    /*指定VMA在进程地址空间的结束地址*/
    unsigned long vm_end;       /* The first byte after our end address
                       within vm_mm. */

    /* linked list of VM areas per task, sorted by address */
    /*进程的vma都连接成一个链表*/
    struct vm_area_struct *vm_next, *vm_prev;

    /*vma作为一个节点加入红黑树中,每个进程的struct mm_struct数据结构中都有这样一棵红黑树mm->mm_rb*/
    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. */

    /*指向该vma所属的进程struct mm_struct数据结构*/
    struct mm_struct *vm_mm;    /* The address space we belong to. */

    /*vma的访问权限*/
    pgprot_t vm_page_prot;      /* Access permissions of this VMA. */

    /*描述该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.
     */
    /*anon_vam_chain和anon_vma:用于管理RMAP反向映射*/
    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. */
    /*指向许多方法的集合,这些方法用于在vma中执行各种操作,通常用于文件映射*/
    const struct vm_operations_struct *vm_ops;

    /* Information about our backing store: */
    /*指定文件映射的偏移量,这个变量的单位不是Byte,而是页面的大小(PAGE_SIZE)*/
    unsigned long vm_pgoff;     /* Offset (within vm_file) in PAGE_SIZE
                       units, *not* PAGE_CACHE_SIZE */
    
    /*指向file的实例,描述一个被映射的文件*/
    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 mm_struct数据结构是描述进程内存管理的核心数据结构,该数据结构也提供了管理VMA所需的信息,这些信息概况如下:

VMA按照起始地址以递增的方式插入mm_struct->mmap链表中。当进程拥有大量的VMA时,扫描链表和查找特定的VMA是非常低效的操作。

    例如在云计算的机器中,所有内核中通常要靠红黑树来协助,以便提高查找速度。

include/linux/mm_types.h

//每个VMA都要连接到mm_struct中的链表和红黑树中,以方便查找。

struct mm_struct {

    /*mmap形成一个单链表,进程中所有的vma都连接到这个链表中,链表头时mm_struct->mmap*/

    struct vm_area_struct *mmap;        /* list of VMAs */

    /*mm_rb是红黑树的根节点,每个进程有一棵VMA的红黑树*/

    struct rb_root mm_rb;

    u32 vmacache_seqnum;                   /* per-thread 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 */

    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;          /* How many users with user space? */

    atomic_t mm_count;          /* How many references to "struct mm_struct" (users count as 1) */

    atomic_long_t nr_ptes;          /* PTE page table pages */

    atomic_long_t nr_pmds;          /* PMD page table pages */

    int map_count;              /* number of VMAs */



    spinlock_t page_table_lock;     /* Protects page tables and some counters */

    struct rw_semaphore mmap_sem;



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

    unsigned long pinned_vm;    /* Refcount permanently increased */

    unsigned long shared_vm;    /* Shared pages (files) */

    unsigned long exec_vm;      /* VM_EXEC & ~VM_WRITE */

    unsigned long stack_vm;     /* VM_GROWSUP/DOWN */

    unsigned long def_flags;

    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;



    cpumask_var_t cpu_vm_mask_var;



    /* Architecture-specific MM context */

    mm_context_t context;



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



    struct core_state *core_state; /* coredumping support */

#ifdef CONFIG_AIO

    spinlock_t          ioctx_lock;

    struct kioctx_table __rcu   *ioctx_table;

#endif

#ifdef CONFIG_MEMCG

    /*

     * "owner" points to a task that is regarded as the canonical

     * user/owner of this mm. All of the following must be true in

     * order for it to be changed:

     *

     * current == mm->owner

     * current->mm != mm

     * new_owner->mm == mm

     * new_owner->alloc_lock is held

     */

    struct task_struct __rcu *owner;

#endif



    /* store ref to file /proc/<pid>/exe symlink points to */

    struct file *exe_file;

#ifdef CONFIG_MMU_NOTIFIER

    struct mmu_notifier_mm *mmu_notifier_mm;

#endif

#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS

    pgtable_t pmd_huge_pte; /* protected by page_table_lock */

#endif

#ifdef CONFIG_CPUMASK_OFFSTACK

    struct cpumask cpumask_allocation;

#endif

#ifdef CONFIG_NUMA_BALANCING

    /*

     * numa_next_scan is the next time that the PTEs will be marked

     * pte_numa. NUMA hinting faults will gather statistics and migrate

     * pages to new nodes if necessary.

     */

    unsigned long numa_next_scan;



    /* Restart point for scanning and setting pte_numa */

    unsigned long numa_scan_offset;



    /* numa_scan_seq prevents two threads setting pte_numa */

    int numa_scan_seq;

#endif

#if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION)

    /*

     * An operation with batched TLB flushing is going on. Anything that

     * can move process memory needs to flush the TLB when moving a

     * PROT_NONE or PROT_NUMA mapped page.

     */

    bool tlb_flush_pending;

#endif

    struct uprobes_state uprobes_state;

#ifdef CONFIG_X86_INTEL_MPX

    /* address of the bounds directory */

    void __user *bd_addr;

#endif

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byd yes

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值