percpu: replace pcpu_realloc() with pcpu_mem_alloc() and pcpu_mem_free()
Impact: code reorganization for later changes With static map handling moved to pcpu_split_block(), pcpu_realloc() only clutters the code and it's also unsuitable for scheduled locking changes. Implement and use pcpu_mem_alloc/free() instead. Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
87
mm/percpu.c
87
mm/percpu.c
@@ -164,39 +164,41 @@ static bool pcpu_chunk_page_occupied(struct pcpu_chunk *chunk,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pcpu_realloc - versatile realloc
|
* pcpu_mem_alloc - allocate memory
|
||||||
* @p: the current pointer (can be NULL for new allocations)
|
* @size: bytes to allocate
|
||||||
* @size: the current size in bytes (can be 0 for new allocations)
|
|
||||||
* @new_size: the wanted new size in bytes (can be 0 for free)
|
|
||||||
*
|
*
|
||||||
* More robust realloc which can be used to allocate, resize or free a
|
* Allocate @size bytes. If @size is smaller than PAGE_SIZE,
|
||||||
* memory area of arbitrary size. If the needed size goes over
|
* kzalloc() is used; otherwise, vmalloc() is used. The returned
|
||||||
* PAGE_SIZE, kernel VM is used.
|
* memory is always zeroed.
|
||||||
*
|
*
|
||||||
* RETURNS:
|
* RETURNS:
|
||||||
* The new pointer on success, NULL on failure.
|
* Pointer to the allocated area on success, NULL on failure.
|
||||||
*/
|
*/
|
||||||
static void *pcpu_realloc(void *p, size_t size, size_t new_size)
|
static void *pcpu_mem_alloc(size_t size)
|
||||||
{
|
{
|
||||||
void *new;
|
|
||||||
|
|
||||||
if (new_size <= PAGE_SIZE)
|
|
||||||
new = kmalloc(new_size, GFP_KERNEL);
|
|
||||||
else
|
|
||||||
new = vmalloc(new_size);
|
|
||||||
if (new_size && !new)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memcpy(new, p, min(size, new_size));
|
|
||||||
if (new_size > size)
|
|
||||||
memset(new + size, 0, new_size - size);
|
|
||||||
|
|
||||||
if (size <= PAGE_SIZE)
|
if (size <= PAGE_SIZE)
|
||||||
kfree(p);
|
return kzalloc(size, GFP_KERNEL);
|
||||||
else
|
else {
|
||||||
vfree(p);
|
void *ptr = vmalloc(size);
|
||||||
|
if (ptr)
|
||||||
|
memset(ptr, 0, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new;
|
/**
|
||||||
|
* pcpu_mem_free - free memory
|
||||||
|
* @ptr: memory to free
|
||||||
|
* @size: size of the area
|
||||||
|
*
|
||||||
|
* Free @ptr. @ptr should have been allocated using pcpu_mem_alloc().
|
||||||
|
*/
|
||||||
|
static void pcpu_mem_free(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
if (size <= PAGE_SIZE)
|
||||||
|
kfree(ptr);
|
||||||
|
else
|
||||||
|
vfree(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -331,29 +333,27 @@ static int pcpu_split_block(struct pcpu_chunk *chunk, int i, int head, int tail)
|
|||||||
if (chunk->map_alloc < target) {
|
if (chunk->map_alloc < target) {
|
||||||
int new_alloc;
|
int new_alloc;
|
||||||
int *new;
|
int *new;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
new_alloc = PCPU_DFL_MAP_ALLOC;
|
new_alloc = PCPU_DFL_MAP_ALLOC;
|
||||||
while (new_alloc < target)
|
while (new_alloc < target)
|
||||||
new_alloc *= 2;
|
new_alloc *= 2;
|
||||||
|
|
||||||
if (chunk->map_alloc < PCPU_DFL_MAP_ALLOC) {
|
new = pcpu_mem_alloc(new_alloc * sizeof(new[0]));
|
||||||
/*
|
|
||||||
* map_alloc smaller than the default size
|
|
||||||
* indicates that the chunk is one of the
|
|
||||||
* first chunks and still using static map.
|
|
||||||
* Allocate a dynamic one and copy.
|
|
||||||
*/
|
|
||||||
new = pcpu_realloc(NULL, 0, new_alloc * sizeof(new[0]));
|
|
||||||
if (new)
|
|
||||||
memcpy(new, chunk->map,
|
|
||||||
chunk->map_alloc * sizeof(new[0]));
|
|
||||||
} else
|
|
||||||
new = pcpu_realloc(chunk->map,
|
|
||||||
chunk->map_alloc * sizeof(new[0]),
|
|
||||||
new_alloc * sizeof(new[0]));
|
|
||||||
if (!new)
|
if (!new)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
size = chunk->map_alloc * sizeof(chunk->map[0]);
|
||||||
|
memcpy(new, chunk->map, size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* map_alloc < PCPU_DFL_MAP_ALLOC indicates that the
|
||||||
|
* chunk is one of the first chunks and still using
|
||||||
|
* static map.
|
||||||
|
*/
|
||||||
|
if (chunk->map_alloc >= PCPU_DFL_MAP_ALLOC)
|
||||||
|
pcpu_mem_free(chunk->map, size);
|
||||||
|
|
||||||
chunk->map_alloc = new_alloc;
|
chunk->map_alloc = new_alloc;
|
||||||
chunk->map = new;
|
chunk->map = new;
|
||||||
}
|
}
|
||||||
@@ -696,7 +696,7 @@ static void free_pcpu_chunk(struct pcpu_chunk *chunk)
|
|||||||
return;
|
return;
|
||||||
if (chunk->vm)
|
if (chunk->vm)
|
||||||
free_vm_area(chunk->vm);
|
free_vm_area(chunk->vm);
|
||||||
pcpu_realloc(chunk->map, chunk->map_alloc * sizeof(chunk->map[0]), 0);
|
pcpu_mem_free(chunk->map, chunk->map_alloc * sizeof(chunk->map[0]));
|
||||||
kfree(chunk);
|
kfree(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,8 +708,7 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void)
|
|||||||
if (!chunk)
|
if (!chunk)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
chunk->map = pcpu_realloc(NULL, 0,
|
chunk->map = pcpu_mem_alloc(PCPU_DFL_MAP_ALLOC * sizeof(chunk->map[0]));
|
||||||
PCPU_DFL_MAP_ALLOC * sizeof(chunk->map[0]));
|
|
||||||
chunk->map_alloc = PCPU_DFL_MAP_ALLOC;
|
chunk->map_alloc = PCPU_DFL_MAP_ALLOC;
|
||||||
chunk->map[chunk->map_used++] = pcpu_unit_size;
|
chunk->map[chunk->map_used++] = pcpu_unit_size;
|
||||||
chunk->page = chunk->page_ar;
|
chunk->page = chunk->page_ar;
|
||||||
|
Reference in New Issue
Block a user