Linux内核API page_zone

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平台上三个区的划分如表所示。

Linux内核API page_zone

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,会出现如图所示的结果。

Linux内核API page_zone

结果分析:

page_zone( )需要有一个page指针作为参数,这里通过alloc_pages( )函数分配一个page,然后将它传递给page_zone( )函数获得一个zone类型指针,这样便得到了由alloc_pages( )所分配的页所在的区描述符。怎样判断它是在ZONE_DMA、ZONE_NORMAL或是ZONE_HIGHMEM中的呢,测试中输出区描述的名称为“DMA32”,可知由alloc_pages( )所分配的页在ZONE_DMA区。

测试程序中调用了alloc_pages( )函数来分配物理页,参考极客笔记网关于该函数的分析。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程