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:
		
							parent
							
								
									6b19b0c240
								
							
						
					
					
						commit
						1880d93b80
					
				
							
								
								
									
										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 | ||||
|  * @p: the current pointer (can be NULL for new allocations) | ||||
|  * @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) | ||||
|  * pcpu_mem_alloc - allocate memory | ||||
|  * @size: bytes to allocate | ||||
|  * | ||||
|  * More robust realloc which can be used to allocate, resize or free a | ||||
|  * memory area of arbitrary size.  If the needed size goes over | ||||
|  * PAGE_SIZE, kernel VM is used. | ||||
|  * Allocate @size bytes.  If @size is smaller than PAGE_SIZE, | ||||
|  * kzalloc() is used; otherwise, vmalloc() is used.  The returned | ||||
|  * memory is always zeroed. | ||||
|  * | ||||
|  * 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) | ||||
| 		kfree(p); | ||||
| 	else | ||||
| 		vfree(p); | ||||
| 		return kzalloc(size, GFP_KERNEL); | ||||
| 	else { | ||||
| 		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) { | ||||
| 		int new_alloc; | ||||
| 		int *new; | ||||
| 		size_t size; | ||||
| 
 | ||||
| 		new_alloc = PCPU_DFL_MAP_ALLOC; | ||||
| 		while (new_alloc < target) | ||||
| 			new_alloc *= 2; | ||||
| 
 | ||||
| 		if (chunk->map_alloc < PCPU_DFL_MAP_ALLOC) { | ||||
| 			/*
 | ||||
| 			 * 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])); | ||||
| 		new = pcpu_mem_alloc(new_alloc * sizeof(new[0])); | ||||
| 		if (!new) | ||||
| 			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 = new; | ||||
| 	} | ||||
| @ -696,7 +696,7 @@ static void free_pcpu_chunk(struct pcpu_chunk *chunk) | ||||
| 		return; | ||||
| 	if (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); | ||||
| } | ||||
| 
 | ||||
| @ -708,8 +708,7 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void) | ||||
| 	if (!chunk) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	chunk->map = pcpu_realloc(NULL, 0, | ||||
| 				  PCPU_DFL_MAP_ALLOC * sizeof(chunk->map[0])); | ||||
| 	chunk->map = pcpu_mem_alloc(PCPU_DFL_MAP_ALLOC * sizeof(chunk->map[0])); | ||||
| 	chunk->map_alloc = PCPU_DFL_MAP_ALLOC; | ||||
| 	chunk->map[chunk->map_used++] = pcpu_unit_size; | ||||
| 	chunk->page = chunk->page_ar; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user