[PATCH 1/4] powerpc: implement vmemmap_list_free()

Nathan Fontenot nfont at linux.vnet.ibm.com
Fri Jul 25 01:11:43 EST 2014


On 06/11/2014 03:23 AM, Li Zhong wrote:
> This patch implements vmemmap_list_free() for vmemmap_free().
> 
> The freed entries will be removed from vmemmap_list, and form a freed list,
> with next as the header. The next position in the last allocated page is kept
> at the list tail.
> 
> When allocation, if there are freed entries left, get it from the freed list;
> if no freed entries left, get it like before from the last allocated pages.
> 
> With this change, realmode_pfn_to_page() also needs to be changed to walk
> all the entries in the vmemmap_list, as the virt_addr of the entries might not
> be stored in order anymore.
> 
> It helps to reuse the memory when continuous doing memory hot-plug/remove
> operations, but didn't reclaim the pages already allocated, so the memory usage
> will only increase, but won't exceed the value for the largest memory
> configuration.
> 
> Signed-off-by: Li Zhong <zhong at linux.vnet.ibm.com>
> Cc: Nathan Fontenot <nfont at linux.vnet.ibm.com>

Acked-by: Nathan Fontenot <nfont at linux.vnet.ibm.com>

> ---
>  arch/powerpc/mm/init_64.c |   62 +++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 52 insertions(+), 10 deletions(-)
> 
> diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
> index e3734ed..fa5d28b 100644
> --- a/arch/powerpc/mm/init_64.c
> +++ b/arch/powerpc/mm/init_64.c
> @@ -226,14 +226,24 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
>  #endif /* CONFIG_PPC_BOOK3E */
>  
>  struct vmemmap_backing *vmemmap_list;
> +static struct vmemmap_backing *next;
> +static int num_left;
> +static int num_freed;
>  
>  static __meminit struct vmemmap_backing * vmemmap_list_alloc(int node)
>  {
> -	static struct vmemmap_backing *next;
> -	static int num_left;
> +	struct vmemmap_backing *vmem_back;
> +	/* get from freed entries first */
> +	if (num_freed) {
> +		num_freed--;
> +		vmem_back = next;
> +		next = next->list;
> +
> +		return vmem_back;
> +	}
>  
>  	/* allocate a page when required and hand out chunks */
> -	if (!next || !num_left) {
> +	if (!num_left) {
>  		next = vmemmap_alloc_block(PAGE_SIZE, node);
>  		if (unlikely(!next)) {
>  			WARN_ON(1);
> @@ -266,6 +276,38 @@ static __meminit void vmemmap_list_populate(unsigned long phys,
>  	vmemmap_list = vmem_back;
>  }
>  
> +static unsigned long vmemmap_list_free(unsigned long start)
> +{
> +	struct vmemmap_backing *vmem_back, *vmem_back_prev;
> +
> +	vmem_back_prev = vmem_back = vmemmap_list;
> +
> +	/* look for it with prev pointer recorded */
> +	for (; vmem_back; vmem_back = vmem_back->list) {
> +		if (vmem_back->virt_addr == start)
> +			break;
> +		vmem_back_prev = vmem_back;
> +	}
> +
> +	if (unlikely(!vmem_back)) {
> +		WARN_ON(1);
> +		return 0;
> +	}
> +
> +	/* remove it from vmemmap_list */
> +	if (vmem_back == vmemmap_list) /* remove head */
> +		vmemmap_list = vmem_back->list;
> +	else
> +		vmem_back_prev->list = vmem_back->list;
> +
> +	/* next point to this freed entry */
> +	vmem_back->list = next;
> +	next = vmem_back;
> +	num_freed++;
> +
> +	return vmem_back->phys;
> +}
> +
>  int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
>  {
>  	unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
> @@ -331,16 +373,16 @@ struct page *realmode_pfn_to_page(unsigned long pfn)
>  		if (pg_va < vmem_back->virt_addr)
>  			continue;
>  
> -		/* Check that page struct is not split between real pages */
> -		if ((pg_va + sizeof(struct page)) >
> -				(vmem_back->virt_addr + page_size))
> -			return NULL;
> -
> -		page = (struct page *) (vmem_back->phys + pg_va -
> +		/* After vmemmap_list entry free is possible, need check all */
> +		if ((pg_va + sizeof(struct page)) <=
> +				(vmem_back->virt_addr + page_size)) {
> +			page = (struct page *) (vmem_back->phys + pg_va -
>  				vmem_back->virt_addr);
> -		return page;
> +			return page;
> +		}
>  	}
>  
> +	/* Probably that page struct is split between real pages */
>  	return NULL;
>  }
>  EXPORT_SYMBOL_GPL(realmode_pfn_to_page);
> 



More information about the Linuxppc-dev mailing list