[Gestión de la memoria del kernel de Linux] interfaz de programación del asignador de memblock ② (análisis de la función memblock_add_range | análisis de la función memblock_insert_region)





1. Análisis de prototipo de la función memblock_add_range



En la memblock_addfunción , llamar a la memblock_add_rangefunción inserta un bloque de memoria;

memblock_add_rangeEl 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 *typeLa representación del parámetro apunta al tipo de bloque de memoria que se agregará a la nueva región;

phys_addr_t baseEl parámetro indica la dirección inicial ;

phys_addr_t sizeEl parámetro indica el tamaño ;

int nidEl parámetro representa el nid de la nueva área , apuntando a la estructura NUMA;

unsigned long flagsEl 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_regionfunció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_regionEl prototipo de la función es el siguiente:

struct memblock_type *typeEl puntero del parámetro apunta al área de memoria.

int idxEl parámetro indica el índice de la lista enlazada del área de memoria

phys_addr_t baseEl parámetro indica la dirección base del área de memoria.

phys_addr_t sizeEl parámetro indica el tamaño del área de memoria

int nidEl parámetro indica la identificación del nodo de memoria.

unsigned long flagsEl 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_rangeLa función se define en la ubicación linux-4.12\mm\memblock.c #511 del código fuente del kernel de Linux ;

inserte la descripción de la imagen aquí

/**
 * 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

Supongo que te gusta

Origin blog.csdn.net/han1202012/article/details/124292398
Recomendado
Clasificación