memblock_add_range笔记

参考文章,https://blog.csdn.net/liuhangtiant/article/details/80561148 个人认为,有配图,更易于理解

一.当第二块内存的结束地址小于第一块内存的起始地址时:

1.1 ~ 1.5步骤分析 

int __init_memblock memblock_add_range(struct memblock_type *type,
				phys_addr_t base, phys_addr_t size,
				int nid, unsigned long flags)
{
	bool insert = false;
	phys_addr_t obase = base;
	phys_addr_t end = base + memblock_cap_size(base, &size);
	int i, nr_new;

	if (!size)
		return 0;

	/* special case for empty array */
	if (type->regions[0].size == 0) {
		WARN_ON(type->cnt != 1 || type->total_size);
		type->regions[0].base = base;
		type->regions[0].size = size;
		type->regions[0].flags = flags;
		memblock_set_region_node(&type->regions[0], nid);
		type->total_size = size;
		return 0;
	}
repeat:
	/*
	 * The following is executed twice.  Once with %false @insert and
	 * then with %true.  The first counts the number of regions needed
	 * to accomodate the new area.  The second actually inserts them.
	 */
	base = obase;
	nr_new = 0;

	for (i = 0; i < type->cnt; i++) {
		struct memblock_region *rgn = &type->regions[i];
		phys_addr_t rbase = rgn->base;
		phys_addr_t rend = rbase + rgn->size;

                                 // rbase为第一块内存的起始地址,end为第二块内存的结束地址
                                 // 1.如果第2块内存的结束地址小于第一块内存的起始地址,说明
                                 // 第二块内存低于第一块内存,此时应将第二块内存放在zone0处
                                 // 第一块内存放在zone1处,交换下位置
                                 // region必须从大到小排列。这里说的大小,是指region所代表的
                                 // 内存的起始/结束地址,也就是说,region0的结束地址,必须小
                                 // 于或等于region1的起始地址
		if (rbase >= end) // 1.1     
			break;        // 1.2 break退出循环
		if (rend <= base)
			continue;
		/*
		 * @rgn overlaps.  If it separates the lower part of new
		 * area, insert that portion.
		 */
		if (rbase > base) {
			nr_new++;
			if (insert)
				memblock_insert_region(type, i++, base,
						       rbase - base, nid,
						       flags);
		}
		/* area below @rend is dealt with, forget about it */
		base = min(rend, end);
	}    // end for

	/* insert the remaining portion */
	if (base < end) {                    // 1.3 成立    
		nr_new++;                        // nr_new ++
		if (insert)                      // insert = false 不成立
			memblock_insert_region(type, i, base, end - base,
					       nid, flags);
	}

	/*
	 * If this was the first round, resize array and repeat for actual
	 * insertions; otherwise, merge and return.
	 */
	if (!insert) {                    // 1.4  insert = false 
		while (type->cnt + nr_new > type->max)   //type->cnt = 1 nr_new = 1 type->max=128
			if (memblock_double_array(type, obase, size) < 0)
				return -ENOMEM;
		insert = true;               // 1.5 insert = true,返回到repeat处
		goto repeat;
	} else {
		memblock_merge_regions(type);
		return 0;
	}
}

 1.6~1.10步骤分析

int __init_memblock memblock_add_range(struct memblock_type *type,
				phys_addr_t base, phys_addr_t size,
				int nid, unsigned long flags)
{
	bool insert = false;
	phys_addr_t obase = base;
	phys_addr_t end = base + memblock_cap_size(base, &size);
	int i, nr_new;

	if (!size)
		return 0;

	/* special case for empty array */
	if (type->regions[0].size == 0) {
		WARN_ON(type->cnt != 1 || type->total_size);
		type->regions[0].base = base;
		type->regions[0].size = size;
		type->regions[0].flags = flags;
		memblock_set_region_node(&type->regions[0], nid);
		type->total_size = size;
		return 0;
	}
repeat:        // 1.6 goto 跳到这个地方
	/*
	 * The following is executed twice.  Once with %false @insert and
	 * then with %true.  The first counts the number of regions needed
	 * to accomodate the new area.  The second actually inserts them.
	 */
	base = obase;      // 第二块内存的起始地址
	nr_new = 0;        // nr_new 又重置为0

	for (i = 0; i < type->cnt; i++) {    // type->cnt = 1
		struct memblock_region *rgn = &type->regions[i];
		phys_addr_t rbase = rgn->base;
		phys_addr_t rend = rbase + rgn->size;

		if (rbase >= end)        // 1.7 第二块内存的结束地址小于第一块内存的起始地址,i=0
			break;
		if (rend <= base)
			continue;
		/*
		 * @rgn overlaps.  If it separates the lower part of new
		 * area, insert that portion.
		 */
		if (rbase > base) {
			nr_new++;
			if (insert)
				memblock_insert_region(type, i++, base,
						       rbase - base, nid,
						       flags);
		}
		/* area below @rend is dealt with, forget about it */
		base = min(rend, end);
	}    // end for

	/* insert the remaining portion */
	if (base < end) {        // 1.8 base < end成立
		nr_new++;            // nr_new++  nr_new = 1
		if (insert)          // insert = true
			memblock_insert_region(type, i, base, end - base, nid, flags);// 1.9插入内存块
                        // 将第二块内存放到regions[0]中,第一块内存放到regions[1]中,i=0
                        // 同时,type->cnt++,type->total_size += size; 
	}

	/*
	 * If this was the first round, resize array and repeat for actual
	 * insertions; otherwise, merge and return.
	 */
	if (!insert) {
		while (type->cnt + nr_new > type->max)
			if (memblock_double_array(type, obase, size) < 0)
				return -ENOMEM;
		insert = true;
		goto repeat;
	} else {
		memblock_merge_regions(type);    // 1.9 
		return 0;
	}
}
static void __init_memblock memblock_merge_regions(struct memblock_type *type)
{
	int i = 0;

	/* cnt never goes below 1 */
	while (i < type->cnt - 1) {        // 1.10  type->cnt = 2
		struct memblock_region *this = &type->regions[i];
		struct memblock_region *next = &type->regions[i + 1];

        /* 只有当第二个内存块(next region)的起始地址等于第一内存块(this region)的
         * 起始地址加上size时,并且 node,flags应该相等,才符号merge条件
         * 
         */
		if (this->base + this->size != next->base ||
		    memblock_get_region_node(this) !=
		    memblock_get_region_node(next) ||
		    this->flags != next->flags) {
			BUG_ON(this->base + this->size > next->base);
			i++;
			continue;
		}

		this->size += next->size;
		/* move forward from next + 1, index of which is i + 2 */
		memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next));
		type->cnt--;
	}
}

二.当第二个内存块的起始地址大于第一个内存块的结束地址时

 

int __init_memblock memblock_add_range(struct memblock_type *type,
				phys_addr_t base, phys_addr_t size,
				int nid, unsigned long flags)
{
	bool insert = false;
	phys_addr_t obase = base;
	phys_addr_t end = base + memblock_cap_size(base, &size);
	int i, nr_new;

	if (!size)
		return 0;

	/* special case for empty array */
	if (type->regions[0].size == 0) {
		WARN_ON(type->cnt != 1 || type->total_size);
		type->regions[0].base = base;
		type->regions[0].size = size;
		type->regions[0].flags = flags;
		memblock_set_region_node(&type->regions[0], nid);
		type->total_size = size;
		return 0;
	}
repeat:
	/*
	 * The following is executed twice.  Once with %false @insert and
	 * then with %true.  The first counts the number of regions needed
	 * to accomodate the new area.  The second actually inserts them.
	 */
	base = obase;
	nr_new = 0;

	for (i = 0; i < type->cnt; i++) {
		struct memblock_region *rgn = &type->regions[i];
		phys_addr_t rbase = rgn->base;
		phys_addr_t rend = rbase + rgn->size;

		if (rbase >= end)
			break;
                            // rend为第一块内存的结束地址,base为第二块内存的起始地址
		if (rend <= base)   // 2.1 当第二块内存的起始地址大于等于第一块内存的结束地址时
                            // 不处理,contine,即找出最后一个内存块,base >= rend
			continue;
		/*
		 * @rgn overlaps.  If it separates the lower part of new
		 * area, insert that portion.
		 */
		if (rbase > base) {
			nr_new++;
			if (insert)
				memblock_insert_region(type, i++, base,
						       rbase - base, nid,
						       flags);
		}
		/* area below @rend is dealt with, forget about it */
		base = min(rend, end);
	}    // end for

	/* insert the remaining portion */
	if (base < end) {    // 2.2 成立
		nr_new++;        // nr_new++ nr_new = 1
		if (insert)      // insert = false    // 2.4 insert = true
			memblock_insert_region(type, i, base, end - base,
					       nid, flags);    // 2.5,此时i = 1
	}

	/*
	 * If this was the first round, resize array and repeat for actual
	 * insertions; otherwise, merge and return.
	 */
	if (!insert) {
		while (type->cnt + nr_new > type->max)
			if (memblock_double_array(type, obase, size) < 0)
				return -ENOMEM;
		insert = true;    // 2.3 insert = true
		goto repeat;
	} else {
		memblock_merge_regions(type);
		return 0;
	}
}

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

科技之光666

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

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

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

打赏作者

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

抵扣说明:

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

余额充值