网站公告列表

  没有公告

加入收藏
设为首页
联系本站
您现在的位置: AnalogCN安诺电子 >> 文章 >> 技术交流 >> 文章正文
  uclinux-2008r1(bf561)内核中的zonelist初始化           ★★★ 【字体:
uclinux-2008r1(bf561)内核中的zonelist初始化
作者:快乐虾    文章来源:http://blog.csdn.net/lights_joy    点击数:    更新时间:2008-6-9    
在pglist_data这个结构体中,有一个成员:
     struct zonelist node_zonelists[MAX_NR_ZONES];
下面就来看看它的初始化过程。
1.1.1.1             build_all_zonelists
在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的调用什么事也不做。
1.1.1.2             __build_all_zonelists
此函数实现为:
/* 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!
 
1.1.1.3             build_zonelists
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]。
 
1.1.1.4             build_zonelist_cache
这个函数仅在__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;
}
很简单,没什么可说的。
 
1.1.1.5             nr_free_pagecache_pages
这个函数的实现为:
/*
 * 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。
文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章:
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    前置放大器在移动医疗服务系
    便携式多通道大容量生理信号
    防腐监测仪的设计与应用
    基于AD1674的酶标仪的设计
    基于C/S模式的JRTPLIB库的测
    ffmpeg与jrtplib相结合应用
    blackfin模拟摄像头驱动中的
    可编程逻辑在数字信号处理系
    发现VDSP4.5一个BUG:单步调
    VDSP5.0双核工程下sml3中的变
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    版权所有:AnalogCN安诺电子 湘ICP备06016315号