內存管理之memblock管理之移除塊


此函數是整個memblock中分配和釋放內存的核心函數,主要是對region操作。詳細實現如下:

static int __init_memblock memblock_remove_range(struct memblock_type *type,
 phys_addr_t base, phys_addr_t size)
{
int start_rgn, end_rgn;
int i, ret;

//先確定移除的邏輯塊所在的region,這步就是隔離isolate操作。
ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn);
if (ret)
return ret;

//把整個region從指定類型中移除。
for (i = end_rgn - 1; i >= start_rgn; i--)
memblock_remove_region(type, i);
return 0;
}


/**
 * memblock_isolate_range - isolate given range into disjoint memblocks

把給出的范圍內的邏輯塊從以所在的塊中脫離出來,這樣會增加一個新的region。

 * @type: memblock type to isolate range for
 * @base: base of range to isolate
* @size: size of range to isolate
 * @start_rgn: out parameter for the start of isolated region
 * @end_rgn: out parameter for the end of isolated region
 *
 * Walk @type and ensure that regions don't cross the boundaries defined by
 * [@base,@base+@size).  Crossing regions are split at the boundaries,
 * which may create at most two more regions.  The index of the first
 * region inside the range is returned in [email protected]_rgn and end in [email protected]_rgn.
 *
 * RETURNS:
 * 0 on success, -errno on failure.
 */

				    region[min, max]

pre -->  memory:  min<--------------|----------------|-------------------->max

示例:            0x1000----------0x5000-----------0x8000---------------0xc0000

base:0x5000, size:0x3000,

 

			region1[min, 0x5000]        region2[0x8000, max] 

now -->  memory: min<----------->        hole     <------------------->max

		0x1000--------0x5000             0x8000-------------0xc0000

 

 

static int memblock_isolate_range(struct memblock_type *type,
phys_addr_t base, phys_addr_t size,
int *start_rgn, int *end_rgn)

{
phys_addr_t end = base + memblock_cap_size(base, &size);
int idx;
struct memblock_region *rgn;

*start_rgn = *end_rgn = 0;

if (!size)
return 0;

/* we'll create at most two more regions 太多region,目前最大支持128個*/
while (type->cnt + 2 > type->max)
if (memblock_double_array(type, base, size) < 0)
return -ENOMEM;
//依次對每個region確定大小和覆蓋范圍。

	for_each_memblock_type(type, rgn) {
phys_addr_t rbase = rgn->base;
phys_addr_t rend = rbase + rgn->size;

if (rbase >= end)
break;
if (rend <= base)
continue;

if (rbase < base) {
/*
* @rgn intersects from below.  Split and continue
* to process the next region - the new top half.
*/
rgn->base = base;
rgn->size -= base - rbase;
type->total_size -= base - rbase;
插入新的region

			memblock_insert_region(type, idx, rbase, base - rbase,
      memblock_get_region_node(rgn),
      rgn->flags);
} else if (rend > end) {
/*
* @rgn intersects from above.  Split and redo the
* current region - the new bottom half.
*/
rgn->base = end;
rgn->size -= end - rbase;
type->total_size -= end - rbase;

另外一種插入方式

			memblock_insert_region(type, idx--, rbase, end - rbase,
      memblock_get_region_node(rgn),
      rgn->flags);
} else {
/* @rgn is fully contained, record it */
if (!*end_rgn)
*start_rgn = idx;
*end_rgn = idx + 1;
}
}

return 0;
}


static void memblock_remove_region(struct memblock_type *type, unsigned long r)
{
type->total_size -= type->regions[r].size;
更新大小

	memmove(&type->regions[r], &type->regions[r + 1],
(type->cnt - (r + 1)) * sizeof(type->regions[r]));
type->cnt--;

更新總的region大小

/* Special case for empty arrays */
if (type->cnt == 0) {
WARN_ON(type->total_size != 0);
type->cnt = 1;
type->regions[0].base = 0;
type->regions[0].size = 0;
type->regions[0].flags = 0;
memblock_set_region_node(&type->regions[0], MAX_NUMNODES);
}
}

0 個評論

要回覆文章請先登錄註冊