page_zone函数功能描述:page_zone( )函数用来获取给定页框所在的区描述符。该区可为ZONE_DMA、ZONE_NORMAL或者ZONE_HIGHMEM。
page_zone文件包含
#include<linux/mm.h>
page_zone函数定义
在内核源码中的位置:linux-3.19.3/include/linux/mm.h
函数定义格式:
static inline struct zone *page_zone(const struct page *page)
page_zone输入参数说明
- 参数page是一个指针,它是对linux内存管理中页的描述,关于结构体page的定义参考alloc_pages( )函数的分析。
page_zone返回参数说明
- 该函数返回给定页框所在的区描述符,该描述符是结构体类型struct zone,它跟踪页框使用、空闲区域和锁等信息,在文件linux-3.19.3/include/linux/mmzone.h中定义。
Linux虚拟内存管理中有两个概念UMA(Uniform Memory Access), NUMA(Non Uniform Memory Access),它们是与体系结构相关的。UMA是指一致性内存访问,常用于单CPU体系结构,NUMA指非一致性内存访问,用于多CPU的机器。UMA模式下,CPU访问系统内存中任何位置的代价都是一样的,而NUMA模式下,不同内存相对于不同的CPU所处的位置不一样,CPU对它们的访问开销也因此不一样,系统为每个CPU划分了本地内存,不同CPU之间通过总线连接起来,这样CPU访问本地内存的代价比访问远端内存的代价要小。
为了支持非一致性内存访问(NUMA), Linux将内存划分成不同的节点(Node),划分给每个CPU的本地内存被称作一个节点。一致性内存访问(UMA)中也有节点,只不过系统中只有一个节点。多个节点是通过数据结构pglist_data链接起来的,该结构体在文件include/linux/mmzone.h中定义。每个节点一般被分为三个区,分别是ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM,关于区描述符参见本节上文对结构体zone的说明。在x86平台上三个区的划分如表所示。
ZONE_NORMAL区包含了大量的页(4096个),几乎所有的用户进程请求的空间都是分配在这个区的,不过ZONE_DMA也会被使用。ZONE_HIGHMEM中的页是内核不能直接访问的页,该部分的页并不能永久地映射到内核地址空间。
page_zone实例解析
编写测试文件:page_zone.c
头文件及全局变量声明如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
MODULE_LICENSE("GPL");
static int __init page_zone_init(void);
static void __exit page_zone_exit(void);
struct page * page = NULL;
模块初始化函数:
int __init page_zone_init(void)
{
page = alloc_pages(GFP_KERNEL,0); //分配一个物理页
if(! page)
{
printk("alloc_pages failed! \n");
return -ENOMEM;
}
else
{
printk("alloc_pages Successfully! \n");
struct zone * zone = NULL;
zone = page_zone( page ); //获取物理页page所属的区描述符
if(! zone)
{
printk("page_zone wrong! \n");
}
else
{
printk("the zone name is %s\n", zone->name);
}
}
return 0;
}
模块退出函数:
void __exit page_zone_exit(void)
{
if(page)
__free_pages(page,0); //释放所分配的物理页
printk("exit! \n");
}
模块初始化及退出函数调用:
module_init(page_zone_init);
module_exit(page_zone_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod page_zone.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
结果分析:
page_zone( )需要有一个page指针作为参数,这里通过alloc_pages( )函数分配一个page,然后将它传递给page_zone( )函数获得一个zone类型指针,这样便得到了由alloc_pages( )所分配的页所在的区描述符。怎样判断它是在ZONE_DMA、ZONE_NORMAL或是ZONE_HIGHMEM中的呢,测试中输出区描述的名称为“DMA32”,可知由alloc_pages( )所分配的页在ZONE_DMA区。
测试程序中调用了alloc_pages( )函数来分配物理页,参考极客笔记网关于该函数的分析。