总结内存管理数据结构和API

内存管理数据结构的关系图

1 由mm数据结构和虚拟地址vaddr找到对应的VMA

find_vma()根据mm_struct和addr找到vma。

find_vma()首先在当前进程current->vmacache[]中查找addr对应的vma;如果未找到,则遍历mm->mm_rb红黑树,通过rb_node找到对应的vma,然后判断是否和addr吻合。

2  由page和VMA找到虚拟地址vaddr

vma_address()只针对匿名页面

inline unsigned long
vma_address(struct page *page, struct vm_area_struct *vma)
{
    unsigned long address = __vma_address(page, vma);

    /* page should be within @vma mapping range */
    VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma);

    return address;
}

static inline unsigned long
__vma_address(struct page *page, struct vm_area_struct *vma)
{
    pgoff_t pgoff = page_to_pgoff(page);
    //根据page->index计算当前vma的偏移地址。
    return vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
}

static inline pgoff_t page_to_pgoff(struct page *page)
{
    if (unlikely(PageHeadHuge(page)))
        return page->index << compound_order(page);
    else
        //page->index表示在一个vma中page的index。
        return page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
}

4k页面的话

#define PAGE_SHIFT    12   

#define PAGE_SIZE       (1UL << PAGE_SHIFT)

1UL << PAGE_SHIFT 即:0x0000 0001<<12  =  0x0000 1000 = 212 = 4K

page index

vma->vm_pgoff

viraddress = VMA->vm_start +(page->index - VMA->vm_pgoff)<< PAGE_SHIFT

3 由page找到所有映射的VMA

通过反向映射rmap系统rmap_walk()来实现,对于匿名页面来说是rmap_walk_anon()

static int rmap_walk_anon(struct page *page, struct rmap_walk_control *rwc)
{
    struct anon_vma *anon_vma;
    pgoff_t pgoff;
    struct anon_vma_chain *avc;
    int ret = SWAP_AGAIN;

    anon_vma = rmap_walk_anon_lock(page, rwc);//由page->mapping找到anon_vma数据结构。
    if (!anon_vma)
        return ret;

    pgoff = page_to_pgoff(page);
    anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) {-----遍历anon_vma->rb_root红黑树,取出avc数据结构。
        struct vm_area_struct *vma = avc->vma;//每个avc数据结构指向每个映射的vma
        unsigned long address = vma_address(page, vma);

        if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
            continue;

        ret = rwc->rmap_one(page, vma, address, rwc->arg);
        if (ret != SWAP_AGAIN)
            break;
        if (rwc->done && rwc->done(page))
            break;
    }
    anon_vma_unlock_read(anon_vma);
    return ret;
}

4 page和pfn之间的互换

page_to_pfn()和pfn_to_page()定义在linux/include/asm-generic/memory_mode.h中定义。

#define page_to_pfn __page_to_pfn
#define pfn_to_page __pfn_to_page

#define __pfn_to_page(pfn)    (mem_map + ((pfn) - ARCH_PFN_OFFSET))//pfn减去ARCH_PFN_OFFSET得到page相对于mem_map的偏移。
#define __page_to_pfn(page)    ((unsigned long)((page) - mem_map) + \
                 ARCH_PFN_OFFSET)//page到mem_map的偏移加上ARCH_PFN_OFFSET得到当前page对应的pfn号。

5 pfn和paddr之间的互换

物理地址paddr和pfn的互换通过位移PAGE_SHIFT可以简单的得到,pfn坐移PAGE_SHIFT就可以得到paddr物理地址,PAGE_SHIFT 就是12。

PHYS_OFFSET - the physical address of the start of memory. */

/*
 * Convert a physical address to a Page Frame Number and back
 */
#define    __phys_to_pfn(paddr)    ((unsigned long)((paddr) >> PAGE_SHIFT))
#define    __pfn_to_phys(pfn)    ((phys_addr_t)(pfn) << PAGE_SHIFT)

6 page和pte之间的互换

先由page到pfn,然后由pfn到pte,可以实现page到pte的转换。

1.page转化成pfn。

2.pfn怎么到pte?

#define pfn_pte(pfn,prot)    __pte(__pfn_to_phys(pfn) | pgprot_val(prot))


#define __page_to_pfn(page)    ((unsigned long)((page) - mem_map) + \
                 ARCH_PFN_OFFSET)

由pte到page,通过pte_pfn()找到对应的pfn号,再由pfn号找到对应的page。

1.pte页表项里面有字段保存的就是pfn页帧号。

2.pfn就可以转化成page。

#define pte_page(pte)        pfn_to_page(pte_pfn(pte))

#define pte_pfn(pte)        ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT)

参考文档:

Linux内存管理 (19)总结内存管理数据结构和API

struct page反向映射vma

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值