linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] powerpc: implement vmemmap_list_free()
@ 2014-06-11  8:23 Li Zhong
  2014-06-11  8:23 ` [PATCH 2/4] powerpc: implement vmemmap_remove_mapping() for BOOK3S Li Zhong
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Li Zhong @ 2014-06-11  8:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus, Li Zhong, Nathan Fontenot

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@linux.vnet.ibm.com>
Cc: Nathan Fontenot <nfont@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);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/4] powerpc: implement vmemmap_remove_mapping() for BOOK3S
  2014-06-11  8:23 [PATCH 1/4] powerpc: implement vmemmap_list_free() Li Zhong
@ 2014-06-11  8:23 ` Li Zhong
  2014-07-24 15:12   ` Nathan Fontenot
  2014-06-11  8:23 ` [PATCH 3/4] powerpc: implement vmemmap_free() Li Zhong
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Li Zhong @ 2014-06-11  8:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus, Li Zhong, Nathan Fontenot

This is to be called in vmemmap_free(), leave the implementation on BOOK3E 
empty as before.

Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
Cc: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
 arch/powerpc/mm/hash_utils_64.c |    2 +-
 arch/powerpc/mm/init_64.c       |   22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 88fdd9d..25d9d66 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -243,7 +243,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-static int htab_remove_mapping(unsigned long vstart, unsigned long vend,
+int htab_remove_mapping(unsigned long vstart, unsigned long vend,
 		      int psize, int ssize)
 {
 	unsigned long vaddr;
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index fa5d28b..69203c8 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -212,6 +212,13 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
 	for (i = 0; i < page_size; i += PAGE_SIZE)
 		BUG_ON(map_kernel_page(start + i, phys, flags));
 }
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+static void vmemmap_remove_mapping(unsigned long start,
+				   unsigned long page_size)
+{
+}
+#endif
 #else /* CONFIG_PPC_BOOK3E */
 static void __meminit vmemmap_create_mapping(unsigned long start,
 					     unsigned long page_size,
@@ -223,6 +230,21 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
 					mmu_kernel_ssize);
 	BUG_ON(mapped < 0);
 }
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+extern int htab_remove_mapping(unsigned long vstart, unsigned long vend,
+			int psize, int ssize);
+
+static void vmemmap_remove_mapping(unsigned long start,
+				   unsigned long page_size)
+{
+	int mapped = htab_remove_mapping(start, start + page_size,
+					 mmu_vmemmap_psize,
+					 mmu_kernel_ssize);
+	BUG_ON(mapped < 0);
+}
+#endif
+
 #endif /* CONFIG_PPC_BOOK3E */
 
 struct vmemmap_backing *vmemmap_list;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] powerpc: implement vmemmap_free()
  2014-06-11  8:23 [PATCH 1/4] powerpc: implement vmemmap_list_free() Li Zhong
  2014-06-11  8:23 ` [PATCH 2/4] powerpc: implement vmemmap_remove_mapping() for BOOK3S Li Zhong
@ 2014-06-11  8:23 ` Li Zhong
  2014-07-24 15:12   ` Nathan Fontenot
  2014-06-11  8:23 ` [PATCH 4/4] powerpc: start loop at section start of start in vmemmap_populated() Li Zhong
  2014-07-24 15:11 ` [PATCH 1/4] powerpc: implement vmemmap_list_free() Nathan Fontenot
  3 siblings, 1 reply; 8+ messages in thread
From: Li Zhong @ 2014-06-11  8:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus, Li Zhong, Nathan Fontenot

vmemmap_free() does the opposite of vmemap_populate().
This patch also puts vmemmap_free() and vmemmap_list_free() into
 CONFIG_MEMMORY_HOTPLUG.

Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
Cc: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
 arch/powerpc/mm/init_64.c |   85 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 64 insertions(+), 21 deletions(-)

diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 69203c8..4963790 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -298,6 +298,37 @@ static __meminit void vmemmap_list_populate(unsigned long phys,
 	vmemmap_list = vmem_back;
 }
 
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
+{
+	unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
+
+	/* Align to the page size of the linear mapping. */
+	start = _ALIGN_DOWN(start, page_size);
+
+	pr_debug("vmemmap_populate %lx..%lx, node %d\n", start, end, node);
+
+	for (; start < end; start += page_size) {
+		void *p;
+
+		if (vmemmap_populated(start, page_size))
+			continue;
+
+		p = vmemmap_alloc_block(page_size, node);
+		if (!p)
+			return -ENOMEM;
+
+		vmemmap_list_populate(__pa(p), start, node);
+
+		pr_debug("      * %016lx..%016lx allocated at %p\n",
+			 start, start + page_size, p);
+
+		vmemmap_create_mapping(start, page_size, __pa(p));
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
 static unsigned long vmemmap_list_free(unsigned long start)
 {
 	struct vmemmap_backing *vmem_back, *vmem_back_prev;
@@ -330,40 +361,52 @@ static unsigned long vmemmap_list_free(unsigned long start)
 	return vmem_back->phys;
 }
 
-int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
+void __ref vmemmap_free(unsigned long start, unsigned long end)
 {
 	unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
 
-	/* Align to the page size of the linear mapping. */
 	start = _ALIGN_DOWN(start, page_size);
 
-	pr_debug("vmemmap_populate %lx..%lx, node %d\n", start, end, node);
+	pr_debug("vmemmap_free %lx...%lx\n", start, end);
 
 	for (; start < end; start += page_size) {
-		void *p;
+		unsigned long addr;
 
+		/*
+		 * the section has already be marked as invalid, so
+		 * vmemmap_populated() true means some other sections still
+		 * in this page, so skip it.
+		 */
 		if (vmemmap_populated(start, page_size))
 			continue;
 
-		p = vmemmap_alloc_block(page_size, node);
-		if (!p)
-			return -ENOMEM;
-
-		vmemmap_list_populate(__pa(p), start, node);
-
-		pr_debug("      * %016lx..%016lx allocated at %p\n",
-			 start, start + page_size, p);
-
-		vmemmap_create_mapping(start, page_size, __pa(p));
+		addr = vmemmap_list_free(start);
+		if (addr) {
+			struct page *page = pfn_to_page(addr >> PAGE_SHIFT);
+
+			if (PageReserved(page)) {
+				/* allocated from bootmem */
+				if (page_size < PAGE_SIZE) {
+					/*
+					 * this shouldn't happen, but if it is
+					 * the case, leave the memory there
+					 */
+					WARN_ON_ONCE(1);
+				} else {
+					unsigned int nr_pages =
+						1 << get_order(page_size);
+					while (nr_pages--)
+						free_reserved_page(page++);
+				}
+			} else
+				free_pages((unsigned long)(__va(addr)),
+							get_order(page_size));
+
+			vmemmap_remove_mapping(start, page_size);
+		}
 	}
-
-	return 0;
-}
-
-void vmemmap_free(unsigned long start, unsigned long end)
-{
 }
-
+#endif
 void register_page_bootmem_memmap(unsigned long section_nr,
 				  struct page *start_page, unsigned long size)
 {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] powerpc: start loop at section start of start in vmemmap_populated()
  2014-06-11  8:23 [PATCH 1/4] powerpc: implement vmemmap_list_free() Li Zhong
  2014-06-11  8:23 ` [PATCH 2/4] powerpc: implement vmemmap_remove_mapping() for BOOK3S Li Zhong
  2014-06-11  8:23 ` [PATCH 3/4] powerpc: implement vmemmap_free() Li Zhong
@ 2014-06-11  8:23 ` Li Zhong
  2014-07-24 15:13   ` Nathan Fontenot
  2014-07-24 15:11 ` [PATCH 1/4] powerpc: implement vmemmap_list_free() Nathan Fontenot
  3 siblings, 1 reply; 8+ messages in thread
From: Li Zhong @ 2014-06-11  8:23 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: paulus, Li Zhong, Nathan Fontenot

vmemmap_populated() checks whether the [start, start + page_size) has valid
pfn numbers, to know whether a vmemmap mapping has been created that includes
this range.

Some range before end might not be checked by this loop:
  sec11start......start11..sec11end/sec12start..end....start12..sec12end
as the above, for start11(section 11), it checks [sec11start, sec11end), and
loop ends as the next start(start12) is bigger than end. However,
[sec11end/sec12start, end) is not checked here.

So before the loop, adjust the start to be the start of the section, so we don't miss ranges like the above.

After we adjust start to be the start of the section, it also means it's
aligned with vmemmap as of the sizeof struct page, so we could use
page_to_pfn directly in the loop.

Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
Cc: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
 arch/powerpc/mm/init_64.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 4963790..253b4b9 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -175,9 +175,10 @@ static unsigned long __meminit vmemmap_section_start(unsigned long page)
 static int __meminit vmemmap_populated(unsigned long start, int page_size)
 {
 	unsigned long end = start + page_size;
+	start = (unsigned long)(pfn_to_page(vmemmap_section_start(start)));
 
 	for (; start < end; start += (PAGES_PER_SECTION * sizeof(struct page)))
-		if (pfn_valid(vmemmap_section_start(start)))
+		if (pfn_valid(page_to_pfn((struct page *)start)))
 			return 1;
 
 	return 0;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/4] powerpc: implement vmemmap_list_free()
  2014-06-11  8:23 [PATCH 1/4] powerpc: implement vmemmap_list_free() Li Zhong
                   ` (2 preceding siblings ...)
  2014-06-11  8:23 ` [PATCH 4/4] powerpc: start loop at section start of start in vmemmap_populated() Li Zhong
@ 2014-07-24 15:11 ` Nathan Fontenot
  3 siblings, 0 replies; 8+ messages in thread
From: Nathan Fontenot @ 2014-07-24 15:11 UTC (permalink / raw)
  To: Li Zhong, linuxppc-dev; +Cc: paulus

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@linux.vnet.ibm.com>
> Cc: Nathan Fontenot <nfont@linux.vnet.ibm.com>

Acked-by: Nathan Fontenot <nfont@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);
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/4] powerpc: implement vmemmap_remove_mapping() for BOOK3S
  2014-06-11  8:23 ` [PATCH 2/4] powerpc: implement vmemmap_remove_mapping() for BOOK3S Li Zhong
@ 2014-07-24 15:12   ` Nathan Fontenot
  0 siblings, 0 replies; 8+ messages in thread
From: Nathan Fontenot @ 2014-07-24 15:12 UTC (permalink / raw)
  To: Li Zhong, linuxppc-dev; +Cc: paulus

On 06/11/2014 03:23 AM, Li Zhong wrote:
> This is to be called in vmemmap_free(), leave the implementation on BOOK3E 
> empty as before.
> 
> Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
> Cc: Nathan Fontenot <nfont@linux.vnet.ibm.com>

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

> ---
>  arch/powerpc/mm/hash_utils_64.c |    2 +-
>  arch/powerpc/mm/init_64.c       |   22 ++++++++++++++++++++++
>  2 files changed, 23 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> index 88fdd9d..25d9d66 100644
> --- a/arch/powerpc/mm/hash_utils_64.c
> +++ b/arch/powerpc/mm/hash_utils_64.c
> @@ -243,7 +243,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
>  }
>  
>  #ifdef CONFIG_MEMORY_HOTPLUG
> -static int htab_remove_mapping(unsigned long vstart, unsigned long vend,
> +int htab_remove_mapping(unsigned long vstart, unsigned long vend,
>  		      int psize, int ssize)
>  {
>  	unsigned long vaddr;
> diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
> index fa5d28b..69203c8 100644
> --- a/arch/powerpc/mm/init_64.c
> +++ b/arch/powerpc/mm/init_64.c
> @@ -212,6 +212,13 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
>  	for (i = 0; i < page_size; i += PAGE_SIZE)
>  		BUG_ON(map_kernel_page(start + i, phys, flags));
>  }
> +
> +#ifdef CONFIG_MEMORY_HOTPLUG
> +static void vmemmap_remove_mapping(unsigned long start,
> +				   unsigned long page_size)
> +{
> +}
> +#endif
>  #else /* CONFIG_PPC_BOOK3E */
>  static void __meminit vmemmap_create_mapping(unsigned long start,
>  					     unsigned long page_size,
> @@ -223,6 +230,21 @@ static void __meminit vmemmap_create_mapping(unsigned long start,
>  					mmu_kernel_ssize);
>  	BUG_ON(mapped < 0);
>  }
> +
> +#ifdef CONFIG_MEMORY_HOTPLUG
> +extern int htab_remove_mapping(unsigned long vstart, unsigned long vend,
> +			int psize, int ssize);
> +
> +static void vmemmap_remove_mapping(unsigned long start,
> +				   unsigned long page_size)
> +{
> +	int mapped = htab_remove_mapping(start, start + page_size,
> +					 mmu_vmemmap_psize,
> +					 mmu_kernel_ssize);
> +	BUG_ON(mapped < 0);
> +}
> +#endif
> +
>  #endif /* CONFIG_PPC_BOOK3E */
>  
>  struct vmemmap_backing *vmemmap_list;
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/4] powerpc: implement vmemmap_free()
  2014-06-11  8:23 ` [PATCH 3/4] powerpc: implement vmemmap_free() Li Zhong
@ 2014-07-24 15:12   ` Nathan Fontenot
  0 siblings, 0 replies; 8+ messages in thread
From: Nathan Fontenot @ 2014-07-24 15:12 UTC (permalink / raw)
  To: Li Zhong, linuxppc-dev; +Cc: paulus

On 06/11/2014 03:23 AM, Li Zhong wrote:
> vmemmap_free() does the opposite of vmemap_populate().
> This patch also puts vmemmap_free() and vmemmap_list_free() into
>  CONFIG_MEMMORY_HOTPLUG.
> 
> Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
> Cc: Nathan Fontenot <nfont@linux.vnet.ibm.com>

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

> ---
>  arch/powerpc/mm/init_64.c |   85 ++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 64 insertions(+), 21 deletions(-)
> 
> diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
> index 69203c8..4963790 100644
> --- a/arch/powerpc/mm/init_64.c
> +++ b/arch/powerpc/mm/init_64.c
> @@ -298,6 +298,37 @@ static __meminit void vmemmap_list_populate(unsigned long phys,
>  	vmemmap_list = vmem_back;
>  }
>  
> +int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
> +{
> +	unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
> +
> +	/* Align to the page size of the linear mapping. */
> +	start = _ALIGN_DOWN(start, page_size);
> +
> +	pr_debug("vmemmap_populate %lx..%lx, node %d\n", start, end, node);
> +
> +	for (; start < end; start += page_size) {
> +		void *p;
> +
> +		if (vmemmap_populated(start, page_size))
> +			continue;
> +
> +		p = vmemmap_alloc_block(page_size, node);
> +		if (!p)
> +			return -ENOMEM;
> +
> +		vmemmap_list_populate(__pa(p), start, node);
> +
> +		pr_debug("      * %016lx..%016lx allocated at %p\n",
> +			 start, start + page_size, p);
> +
> +		vmemmap_create_mapping(start, page_size, __pa(p));
> +	}
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_MEMORY_HOTPLUG
>  static unsigned long vmemmap_list_free(unsigned long start)
>  {
>  	struct vmemmap_backing *vmem_back, *vmem_back_prev;
> @@ -330,40 +361,52 @@ static unsigned long vmemmap_list_free(unsigned long start)
>  	return vmem_back->phys;
>  }
>  
> -int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
> +void __ref vmemmap_free(unsigned long start, unsigned long end)
>  {
>  	unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
>  
> -	/* Align to the page size of the linear mapping. */
>  	start = _ALIGN_DOWN(start, page_size);
>  
> -	pr_debug("vmemmap_populate %lx..%lx, node %d\n", start, end, node);
> +	pr_debug("vmemmap_free %lx...%lx\n", start, end);
>  
>  	for (; start < end; start += page_size) {
> -		void *p;
> +		unsigned long addr;
>  
> +		/*
> +		 * the section has already be marked as invalid, so
> +		 * vmemmap_populated() true means some other sections still
> +		 * in this page, so skip it.
> +		 */
>  		if (vmemmap_populated(start, page_size))
>  			continue;
>  
> -		p = vmemmap_alloc_block(page_size, node);
> -		if (!p)
> -			return -ENOMEM;
> -
> -		vmemmap_list_populate(__pa(p), start, node);
> -
> -		pr_debug("      * %016lx..%016lx allocated at %p\n",
> -			 start, start + page_size, p);
> -
> -		vmemmap_create_mapping(start, page_size, __pa(p));
> +		addr = vmemmap_list_free(start);
> +		if (addr) {
> +			struct page *page = pfn_to_page(addr >> PAGE_SHIFT);
> +
> +			if (PageReserved(page)) {
> +				/* allocated from bootmem */
> +				if (page_size < PAGE_SIZE) {
> +					/*
> +					 * this shouldn't happen, but if it is
> +					 * the case, leave the memory there
> +					 */
> +					WARN_ON_ONCE(1);
> +				} else {
> +					unsigned int nr_pages =
> +						1 << get_order(page_size);
> +					while (nr_pages--)
> +						free_reserved_page(page++);
> +				}
> +			} else
> +				free_pages((unsigned long)(__va(addr)),
> +							get_order(page_size));
> +
> +			vmemmap_remove_mapping(start, page_size);
> +		}
>  	}
> -
> -	return 0;
> -}
> -
> -void vmemmap_free(unsigned long start, unsigned long end)
> -{
>  }
> -
> +#endif
>  void register_page_bootmem_memmap(unsigned long section_nr,
>  				  struct page *start_page, unsigned long size)
>  {
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/4] powerpc: start loop at section start of start in vmemmap_populated()
  2014-06-11  8:23 ` [PATCH 4/4] powerpc: start loop at section start of start in vmemmap_populated() Li Zhong
@ 2014-07-24 15:13   ` Nathan Fontenot
  0 siblings, 0 replies; 8+ messages in thread
From: Nathan Fontenot @ 2014-07-24 15:13 UTC (permalink / raw)
  To: Li Zhong, linuxppc-dev; +Cc: paulus

On 06/11/2014 03:23 AM, Li Zhong wrote:
> vmemmap_populated() checks whether the [start, start + page_size) has valid
> pfn numbers, to know whether a vmemmap mapping has been created that includes
> this range.
> 
> Some range before end might not be checked by this loop:
>   sec11start......start11..sec11end/sec12start..end....start12..sec12end
> as the above, for start11(section 11), it checks [sec11start, sec11end), and
> loop ends as the next start(start12) is bigger than end. However,
> [sec11end/sec12start, end) is not checked here.
> 
> So before the loop, adjust the start to be the start of the section, so we don't miss ranges like the above.
> 
> After we adjust start to be the start of the section, it also means it's
> aligned with vmemmap as of the sizeof struct page, so we could use
> page_to_pfn directly in the loop.
> 
> Signed-off-by: Li Zhong <zhong@linux.vnet.ibm.com>
> Cc: Nathan Fontenot <nfont@linux.vnet.ibm.com>

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

> ---
>  arch/powerpc/mm/init_64.c |    3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
> index 4963790..253b4b9 100644
> --- a/arch/powerpc/mm/init_64.c
> +++ b/arch/powerpc/mm/init_64.c
> @@ -175,9 +175,10 @@ static unsigned long __meminit vmemmap_section_start(unsigned long page)
>  static int __meminit vmemmap_populated(unsigned long start, int page_size)
>  {
>  	unsigned long end = start + page_size;
> +	start = (unsigned long)(pfn_to_page(vmemmap_section_start(start)));
>  
>  	for (; start < end; start += (PAGES_PER_SECTION * sizeof(struct page)))
> -		if (pfn_valid(vmemmap_section_start(start)))
> +		if (pfn_valid(page_to_pfn((struct page *)start)))
>  			return 1;
>  
>  	return 0;
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-07-24 15:13 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-06-11  8:23 [PATCH 1/4] powerpc: implement vmemmap_list_free() Li Zhong
2014-06-11  8:23 ` [PATCH 2/4] powerpc: implement vmemmap_remove_mapping() for BOOK3S Li Zhong
2014-07-24 15:12   ` Nathan Fontenot
2014-06-11  8:23 ` [PATCH 3/4] powerpc: implement vmemmap_free() Li Zhong
2014-07-24 15:12   ` Nathan Fontenot
2014-06-11  8:23 ` [PATCH 4/4] powerpc: start loop at section start of start in vmemmap_populated() Li Zhong
2014-07-24 15:13   ` Nathan Fontenot
2014-07-24 15:11 ` [PATCH 1/4] powerpc: implement vmemmap_list_free() Nathan Fontenot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).