uclinux-2008r1(bf561)内核中的zonelist初始化

本文详细解析了Linux内核中内存管理模块的初始化流程,重点介绍了pglist_data结构体中的zonelists成员及其初始化过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
快乐虾
http://blog.youkuaiyun.com/lights_joy/
lights@hb165.com
  
 
本文适用于
ADI bf561 DSP
uclinux-2008r1-rc8 (移植到vdsp5)
Visual DSP++ 5.0
 
 
欢迎转载,但请保留作者信息
 
在pglist_data这个结构体中,有一个成员:
     struct zonelist node_zonelists[MAX_NR_ZONES];
下面就来看看它的初始化过程。
在start_kernel函数中调用了这个函数:
     build_all_zonelists();
它的实现在mm/page_alloc.c中:
void __meminit build_all_zonelists(void)
{
     if (system_state == SYSTEM_BOOTING) {
         __build_all_zonelists(NULL);
         cpuset_init_current_mems_allowed();
     } else {
//       /* we have to stop all cpus to guaranntee there is no user
//          of zonelist */
//       stop_machine_run(__build_all_zonelists, NULL, NR_CPUS);
//       /* cpuset refresh routine should be here */
         WARN();
     }
     vm_total_pages = nr_free_pagecache_pages();
     printk("Built %i zonelists. Total pages: %ld/n",
              num_online_nodes(), vm_total_pages);
}
对于这个函数,只会在start_kernel中调用一次,此时system_state == SYSTEM_BOOTING。当然,如果需要支持memory_hot_plug,还会有另外的调用,在此忽略它,因此实际只会执行if的第一个分支。
在这个函数中对cpuset_init_current_mems_allowed的调用什么事也不做。
此函数实现为:
/* return values int ....just for stop_machine_run() */
static int __meminit __build_all_zonelists(void *dummy)
{
     int nid;
 
     for_each_online_node(nid) {
         build_zonelists(NODE_DATA(nid));
         build_zonelist_cache(NODE_DATA(nid));
     }
     return 0;
}
在这个函数中for_each_online_node只会执行一次,因为在整个系统中,只有唯一一个pglist_data!
 
static void __meminit build_zonelists(pg_data_t *pgdat)
{
     int node, local_node;
     enum zone_type i,j;
 
     local_node = pgdat->node_id;
     for (i = 0; i < MAX_NR_ZONES; i++) {
         struct zonelist *zonelist;
 
         zonelist = pgdat->node_zonelists + i;
 
         j = build_zonelists_node(pgdat, zonelist, 0, i);
         /*
          * Now we build the zonelist so that it contains the zones
          * of all the other nodes.
          * We don't want to pressure a particular node, so when
          * building the zones for node N, we make sure that the
          * zones coming right after the local ones are those from
          * node N+1 (modulo N)
          */
         for (node = local_node + 1; node < MAX_NUMNODES; node++) {
              if (!node_online(node))
                   continue;
              j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
         }
         for (node = 0; node < local_node; node++) {
              if (!node_online(node))
                   continue;
              j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
         }
 
         zonelist->zones[j] = NULL;
     }
}
在这个函数中有
#define NODES_SHIFT     0
 
#define MAX_NUMNODES    (1 << NODES_SHIFT)
而localnode的值为0。因此这个函数实际上就相当于:
static void __meminit build_zonelists(pg_data_t *pgdat)
{
     int node, local_node;
     enum zone_type i,j;
 
     local_node = pgdat->node_id;
     for (i = 0; i < MAX_NR_ZONES; i++) {
         struct zonelist *zonelist;
         zonelist = pgdat->node_zonelists + i;
         j = build_zonelists_node(pgdat, zonelist, 0, i);
         zonelist->zones[j] = NULL;
     }
}
实际上,我们只要关心build_zonelists_node函数就行了。
/*
 * Builds allocation fallback zone lists.
 *
 * Add all populated zones of a node to the zonelist.
 */
static int __meminit build_zonelists_node(pg_data_t *pgdat,
              struct zonelist *zonelist, int nr_zones, enum zone_type zone_type)
{
     struct zone *zone;
 
     BUG_ON(zone_type >= MAX_NR_ZONES);
     zone_type++;
 
     do {
         zone_type--;
         zone = pgdat->node_zones + zone_type;
         if (populated_zone(zone)) { // 只要present_pages不为,则此条件为真
              zonelist->zones[nr_zones++] = zone;
              check_highest_zone(zone_type); // 空调用
         }
 
     } while (zone_type);
     return nr_zones;
}
在内核中有两个ZONE,ZONE_DMA和ZONE_NORMAL,但是ZONE_NORMAL的内存大小为0,其present_pages也为0,因此在初始化后,zonelist->zones数组实际只有一个元素,它指向ZONE_DMA,即contig_page_data->zone[0]。
 
这个函数仅在__build_all_zonelists中被调用一次:
/* non-NUMA variant of zonelist performance cache - just NULL zlcache_ptr */
static void __meminit build_zonelist_cache(pg_data_t *pgdat)
{
     int i;
 
     for (i = 0; i < MAX_NR_ZONES; i++)
         pgdat->node_zonelists[i].zlcache_ptr = NULL;
}
很简单,没什么可说的。
 
这个函数的实现为:
/*
 * Amount of free RAM allocatable within all zones
 */
unsigned int nr_free_pagecache_pages(void)
{
     return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER));
}
在这里gfp_zone(GFP_HIGHUSER)将返回GFP_HIGHUSER所在的内存区域,因为内核只使用ZONE_DMA,故这个调用返回0,即ZONE_DMA。
下面看看nr_free_zone_pages的实现:
static unsigned int nr_free_zone_pages(int offset)
{
     /* Just pick one node, since fallback list is circular */
     pg_data_t *pgdat = NODE_DATA(numa_node_id());
     unsigned int sum = 0;
 
     struct zonelist *zonelist = pgdat->node_zonelists + offset;
     struct zone **zonep = zonelist->zones;
     struct zone *zone;
 
     for (zone = *zonep++; zone; zone = *zonep++) {
         unsigned long size = zone->present_pages;
         unsigned long high = zone->pages_high;
         if (size > high)
              sum += size - high;
     }
 
     return sum;
}
传递进来的参数为0,而且我们知道zonelist->zones实际只有一个元素,且指向pgdat->node_zones[0],即ZONE_DMA的描述结构zone。因而这个函数的功能就简单了,就是返回ZONE_DMA的空闲页数。对于64M内存(限制为60M),其值将为0x3b6a。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值