Linux内核如何区分匿名页映射?

page结构体关键成员

内核中使用page结构体来描述物理内存,每个物理页就对应一个page结构体来描述,所以page结构体占用的内存大小是与系统物理内存大小成正比的。物理内存越大,用于描述物理页的page结构体就越多,占用的内存也就越大,因此为了减少内存的占用,page结构体大量使用了union联合体结构。如下我们只列举了本文下面要讲述的一些page成员。

include/linux/mm_types.h:

struct page {
	unsigned long flags;		/* Atomic flags, some possibly
					 * updated asynchronously */
	union {
		struct address_space *mapping;	/* If low bit clear, points to
						 * inode address_space, or NULL.
						 * If page mapped as anonymous
						 * memory, low bit is set, and
						 * it points to anon_vma object:
						 * see PAGE_MAPPING_ANON below.
						 */
		void *s_mem;			/* slab first object */
		atomic_t compound_mapcount;	/* first tail page */
		/* page_deferred_list().next	 -- second tail page */
	};

...
      atomic_t _refcount;

...

	/*
	 * On machines where all RAM is mapped into kernel address space,
	 * we can simply calculate the virtual address. On machines with
	 * highmem some memory is mapped into kernel virtual memory
	 * dynamically, so we need a place to store that address.
	 * Note that this field could be 16 bits on x86 ... ;)
	 *
	 * Architectures with slow multiplication can define
	 * WANT_PAGE_VIRTUAL in asm/page.h
	 */
	void *virtual;			/* Kernel virtual address (NULL if
					   not kmapped, ie. highmem) */
...
}
/*
 * The struct page can be forced to be double word aligned so that atomic ops
 * on double words work. The SLUB allocator can make use of such a feature.
 */
#ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
	__aligned(2 * sizeof(unsigned long))
#endif
;
  • flags
    描述页的状态
  • _refcount
    描述页被引用计数
  • mapping
    这个结构体很关键,如果低位为0,它用于描述该页被映射的地址空间结构体,指向一个文件系统页缓存结构体struct address_space;如果低位为1,那么它指向一个匿名映射结构体struct anon_vma。
    因此这个mapping可能是一个(struct address_space *)类型的指针,也可能是一个(struct anon_vma *)类型的指针。
  • virtual
    注意这个virtual表示的是Kernel virtual address,内核虚拟地址而不是用户空间虚拟地址,表示物理页对应的内核虚拟地址,如果是高端内存,可能并没有kmap到内核虚拟地址,此时为NULL。
    一个物理页可能同时被映射到内核虚拟地址空间和用户虚拟地址空间,并不冲突,因为页表是通过虚拟地址转换为物理地址的,所以可能存在多对一的关系。

mapping怎么区分匿名页映射的

内核中的映射分为两种,一种为匿名映射,一种为文件映射,匿名映射对应的结构体为struct anon_vma ;文件映射会对应页缓存,结构体为struct address_space。由于地址对齐的关系,每个 struct address_spacestruct anon_vma 结构体都不会存放在奇数地址上,所以假如不做任何处理,mapping正常情况下的最低位肯定是0,那么由于page结构体在内存中会大量存在,为了充分利用每个bit的空间,这里使用了如下操作:

  • 保存struct anon_vma地址到mapping
page->mapping = (void *)&anon_vma + 1;
  • 从mapping获取struct anon_vma地址
struct anon_vma * anon_vma = (struct anon_vma *)(page->mapping - 1);

通过保存struct anon_vma结构体地址时加1操作,提取struct anon_vma结构体地址时减1操作,从而可以利用在mapping中的最低位来区分当前page是否为匿名映射:

#define PAGE_MAPPING_ANON   0x1

static __always_inline int PageMappingFlags(struct page *page)
{   
    return ((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) != 0;
}
    
static __always_inline int PageAnon(struct page *page)
{
    page = compound_head(page);
    return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0;
}

这里可以看到通过判断mapping成员的最低位来区分是否为匿名映射。


Linux 4.14 source code

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值