Directorio de artículos
1. Análisis de prototipo de la función memblock_add_range
En la memblock_add
función , llamar a la memblock_add_range
función inserta un bloque de memoria;
memblock_add_range
El prototipo de la función es el siguiente:
int __init_memblock memblock_add_range(struct memblock_type *type,
phys_addr_t base, phys_addr_t size,
int nid, unsigned long flags)
struct memblock_type *type
La representación del parámetro apunta al tipo de bloque de memoria que se agregará a la nueva región;
phys_addr_t base
El parámetro indica la dirección inicial ;
phys_addr_t size
El parámetro indica el tamaño ;
int nid
El parámetro representa el nid de la nueva área , apuntando a la estructura NUMA;
unsigned long flags
El parámetro indica el bit indicador del bloque de memoria recién agregado;
2. Análisis del código fuente de la función memblock_add_range
Comparación de bloques de memoria: En esta función se llama al siguiente código, su función es recorrer todos los "bloques de memoria", y cada vez que se recorre se compara el "nuevo bloque de memoria" con "este bloque de memoria" ;
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;
/*
* @rgn overlaps. If it separates the lower part of new
* area, insert that portion.
*/
if (rbase > base) {
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
WARN_ON(nid != memblock_get_region_node(rgn));
#endif
WARN_ON(flags != rgn->flags);
nr_new++;
if (insert)
memblock_insert_region(type, idx++, base,
rbase - base, nid,
flags);
}
/* area below @rend is dealt with, forget about it */
base = min(rend, end);
}
Ruta del código fuente: linux-4.12\mm\memblock.c #543
Insertar memoria: si la dirección de inicio es menor que la dirección final, debe insertar memoria, llamar a la memblock_insert_region
función y completar la operación de inserción de memoria;
/* insert the remaining portion */
if (base < end) {
nr_new++;
if (insert)
memblock_insert_region(type, idx, base, end - base,
nid, flags);
}
Ruta del código fuente: linux-4.12\mm\memblock.c #571/font>
Indicador de lista de bloques de memoria: nr_new
el parámetro indica si hay un nuevo "bloque de memoria" para agregar a la "lista de bloques de memoria" ;
if (!nr_new)
return 0;
Tres, análisis de prototipo de función memblock_insert_region
memblock_insert_region
El prototipo de la función es el siguiente:
struct memblock_type *type
El puntero del parámetro apunta al área de memoria.
int idx
El parámetro indica el índice de la lista enlazada del área de memoria
phys_addr_t base
El parámetro indica la dirección base del área de memoria.
phys_addr_t size
El parámetro indica el tamaño del área de memoria
int nid
El parámetro indica la identificación del nodo de memoria.
unsigned long flags
El parámetro indica el bit de bandera del bloque de memoria.
/**
* memblock_insert_region - insert new memblock region
* @type: memblock type to insert into
* @idx: index for the insertion point
* @base: base address of the new region
* @size: size of the new region
* @nid: node id of the new region
* @flags: flags of the new region
*
* Insert new memblock region [@base,@base+@size) into @type at @idx.
* @type must already have extra room to accommodate the new region.
*/
static void __init_memblock memblock_insert_region(struct memblock_type *type,
int idx, phys_addr_t base,
phys_addr_t size,
int nid, unsigned long flags)
Ruta del código fuente: linux-4.12\mm\memblock.c #478
Cuatro, código fuente de la función memblock_add_range
memblock_add_range
La función se define en la ubicación linux-4.12\mm\memblock.c #511 del código fuente del kernel de Linux ;
/**
* memblock_add_range - add new memblock region
* @type: memblock type to add new region into
* @base: base address of the new region
* @size: size of the new region
* @nid: nid of the new region
* @flags: flags of the new region
*
* Add new memblock region [@base,@base+@size) into @type. The new region
* is allowed to overlap with existing ones - overlaps don't affect already
* existing regions. @type is guaranteed to be minimal (all neighbouring
* compatible regions are merged) after the addition.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
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 idx, nr_new;
struct memblock_region *rgn;
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 accommodate the new area. The second actually inserts them.
*/
base = obase;
nr_new = 0;
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;
/*
* @rgn overlaps. If it separates the lower part of new
* area, insert that portion.
*/
if (rbase > base) {
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
WARN_ON(nid != memblock_get_region_node(rgn));
#endif
WARN_ON(flags != rgn->flags);
nr_new++;
if (insert)
memblock_insert_region(type, idx++, base,
rbase - base, nid,
flags);
}
/* area below @rend is dealt with, forget about it */
base = min(rend, end);
}
/* insert the remaining portion */
if (base < end) {
nr_new++;
if (insert)
memblock_insert_region(type, idx, base, end - base,
nid, flags);
}
if (!nr_new)
return 0;
/*
* 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);
return 0;
}
}
Ruta del código fuente: linux-4.12\mm\memblock.c #511