Memory hotplug is leading to hash page table calls, even on radix:
...
arch_add_memory
create_section_mapping
htab_bolt_mapping
BUG_ON(!ppc_md.hpte_insert);
To fix, refactor {create,remove}_section_mapping() into hash__ and radix__
variants. Implement the radix versions by borrowing from existing vmemmap
and x86 code.
This passes basic verification of plugging and removing memory, but this
stuff is tricky and I'd appreciate extra scrutiny of the series for
correctness--in particular, the adaptation of remove_pagetable() from x86.
/* changelog */
v3:
* Port remove_pagetable() et al. from x86 for unmapping.
* [RFC] -> [PATCH]
v2:
* https://lkml.kernel.org/r/1471449083-15931-1-git-send-email-arbab@linux.vnet.ibm.com
* Do not simply fall through to vmemmap_{create,remove}_mapping(). As Aneesh
and Michael pointed out, they are tied to CONFIG_SPARSEMEM_VMEMMAP and only
did what I needed by luck anyway.
v1:
* https://lkml.kernel.org/r/1466699962-22412-1-git-send-email-arbab@linux.vnet.ibm.com
Reza Arbab (5):
powerpc/mm: set the radix linear page mapping size
powerpc/mm: refactor {create,remove}_section_mapping()
powerpc/mm: add radix__create_section_mapping()
powerpc/mm: add radix__remove_section_mapping()
powerpc/mm: unstub radix__vmemmap_remove_mapping()
arch/powerpc/include/asm/book3s/64/hash.h | 5 +
arch/powerpc/include/asm/book3s/64/radix.h | 5 +
arch/powerpc/mm/hash_utils_64.c | 4 +-
arch/powerpc/mm/pgtable-book3s64.c | 18 +++
arch/powerpc/mm/pgtable-radix.c | 207 ++++++++++++++++++++++++++++-
5 files changed, 236 insertions(+), 3 deletions(-)
--
1.8.3.1
Use remove_pagetable() and friends for radix vmemmap removal.
We do not require the special-case handling of vmemmap done in the x86
versions of these functions. This is because vmemmap_free() has already
freed the mapped pages, and calls us with an aligned address range.
So, add a few failsafe WARNs, but otherwise the code to remove linear
mappings is already sufficient for vmemmap.
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/mm/pgtable-radix.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
@@ -662,7 +683,7 @@ int __meminit radix__vmemmap_create_mapping(unsigned long start,#ifdef CONFIG_MEMORY_HOTPLUGvoidradix__vmemmap_remove_mapping(unsignedlongstart,unsignedlongpage_size){-/* FIXME!! intel does more. We should free page tables mapping vmemmap ? */+remove_pagetable(start,start+page_size,page_size);}#endif#endif
Add the linear page mapping function for radix, used by memory hotplug.
This is similar to vmemmap_populate().
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/include/asm/book3s/64/radix.h | 4 ++++
arch/powerpc/mm/pgtable-book3s64.c | 2 +-
arch/powerpc/mm/pgtable-radix.c | 19 +++++++++++++++++++
3 files changed, 24 insertions(+), 1 deletion(-)
@@ -465,6 +465,25 @@ void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,memblock_set_current_limit(first_memblock_base+first_memblock_size);}+#ifdef CONFIG_MEMORY_HOTPLUG+intradix__create_section_mapping(unsignedlongstart,unsignedlongend)+{+unsignedlongpage_size=1<<mmu_psize_defs[mmu_linear_psize].shift;++/* Align to the page size of the linear mapping. */+start=_ALIGN_DOWN(start,page_size);++for(;start<end;start+=page_size){+intrc=radix__map_kernel_page(start,__pa(start),+PAGE_KERNEL,page_size);+if(rc)+returnrc;+}++return0;+}+#endif /* CONFIG_MEMORY_HOTPLUG */+#ifdef CONFIG_SPARSEMEM_VMEMMAPint__meminitradix__vmemmap_create_mapping(unsignedlongstart,unsignedlongpage_size,
Change {create,remove}_section_mapping() to be wrappers around functions
prefixed with "hash__".
This is preparation for the addition of their "radix__" variants. No
functional change.
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/include/asm/book3s/64/hash.h | 5 +++++
arch/powerpc/mm/hash_utils_64.c | 4 ++--
arch/powerpc/mm/pgtable-book3s64.c | 18 ++++++++++++++++++
3 files changed, 25 insertions(+), 2 deletions(-)
@@ -743,7 +743,7 @@ static unsigned long __init htab_get_table_size(void)}#ifdef CONFIG_MEMORY_HOTPLUG-intcreate_section_mapping(unsignedlongstart,unsignedlongend)+inthash__create_section_mapping(unsignedlongstart,unsignedlongend){intrc=htab_bolt_mapping(start,end,__pa(start),pgprot_val(PAGE_KERNEL),mmu_linear_psize,
@@ -757,7 +757,7 @@ int create_section_mapping(unsigned long start, unsigned long end)returnrc;}-intremove_section_mapping(unsignedlongstart,unsignedlongend)+inthash__remove_section_mapping(unsignedlongstart,unsignedlongend){intrc=htab_remove_mapping(start,end,mmu_linear_psize,mmu_kernel_ssize);
Tear down and free the four-level page tables of the linear mapping
during memory hotremove.
We borrow the basic structure of remove_pagetable() and friends from the
identically-named x86 functions.
Signed-off-by: Reza Arbab <redacted>
---
arch/powerpc/include/asm/book3s/64/radix.h | 1 +
arch/powerpc/mm/pgtable-book3s64.c | 2 +-
arch/powerpc/mm/pgtable-radix.c | 163 +++++++++++++++++++++++++++++
3 files changed, 165 insertions(+), 1 deletion(-)
@@ -139,7 +139,7 @@ int create_section_mapping(unsigned long start, unsigned long end)intremove_section_mapping(unsignedlongstart,unsignedlongend){if(radix_enabled())-return-ENODEV;+returnradix__remove_section_mapping(start,end);returnhash__remove_section_mapping(start,end);}
@@ -482,6 +635,16 @@ int radix__create_section_mapping(unsigned long start, unsigned long end)return0;}++intradix__remove_section_mapping(unsignedlongstart,unsignedlongend)+{+unsignedlongpage_size=1<<mmu_psize_defs[mmu_linear_psize].shift;++start=_ALIGN_DOWN(start,page_size);+remove_pagetable(start,end,page_size);++return0;+}#endif /* CONFIG_MEMORY_HOTPLUG */#ifdef CONFIG_SPARSEMEM_VMEMMAP
Memory hotplug is leading to hash page table calls, even on radix:
...
arch_add_memory
create_section_mapping
htab_bolt_mapping
BUG_ON(!ppc_md.hpte_insert);
To fix, refactor {create,remove}_section_mapping() into hash__ and radix__
variants. Implement the radix versions by borrowing from existing vmemmap
and x86 code.
This passes basic verification of plugging and removing memory, but this
stuff is tricky and I'd appreciate extra scrutiny of the series for
correctness--in particular, the adaptation of remove_pagetable() from x86.
On quick glance everything seemed alright to me. I'll review each patch and Ack/provide comments.
Do we care about alt maps yet?
Balbir Singh.
That is not clearly correct, we map the linear address with either 64K,
2M or 1G depending on the memory available. Take a look at
static void __init radix_init_pgtable(void)
Change {create,remove}_section_mapping() to be wrappers around functions
prefixed with "hash__".
This is preparation for the addition of their "radix__" variants. No
functional change.
I think this can go upstream now ? To fixup broken hotplug with radix ?
Reviewed-by: Aneesh Kumar K.V <redacted>
@@ -743,7 +743,7 @@ static unsigned long __init htab_get_table_size(void)}#ifdef CONFIG_MEMORY_HOTPLUG-intcreate_section_mapping(unsignedlongstart,unsignedlongend)+inthash__create_section_mapping(unsignedlongstart,unsignedlongend){intrc=htab_bolt_mapping(start,end,__pa(start),pgprot_val(PAGE_KERNEL),mmu_linear_psize,
@@ -757,7 +757,7 @@ int create_section_mapping(unsigned long start, unsigned long end)returnrc;}-intremove_section_mapping(unsignedlongstart,unsignedlongend)+inthash__remove_section_mapping(unsignedlongstart,unsignedlongend){intrc=htab_remove_mapping(start,end,mmu_linear_psize,mmu_kernel_ssize);
Add the linear page mapping function for radix, used by memory hotplug.
This is similar to vmemmap_populate().
Ok with this patch your first patch becomes useful. Can you merge that
with this and rename mmu_linear_psize to mmu_hotplug_psize or even use
mmu_virtual_psize. The linear naming is confusing.
@@ -465,6 +465,25 @@ void radix__setup_initial_memory_limit(phys_addr_t first_memblock_base,memblock_set_current_limit(first_memblock_base+first_memblock_size);}+#ifdef CONFIG_MEMORY_HOTPLUG+intradix__create_section_mapping(unsignedlongstart,unsignedlongend)+{+unsignedlongpage_size=1<<mmu_psize_defs[mmu_linear_psize].shift;++/* Align to the page size of the linear mapping. */+start=_ALIGN_DOWN(start,page_size);++for(;start<end;start+=page_size){+intrc=radix__map_kernel_page(start,__pa(start),+PAGE_KERNEL,page_size);+if(rc)+returnrc;+}++return0;+}+#endif /* CONFIG_MEMORY_HOTPLUG */+#ifdef CONFIG_SPARSEMEM_VMEMMAPint__meminitradix__vmemmap_create_mapping(unsignedlongstart,unsignedlongpage_size,
Tear down and free the four-level page tables of the linear mapping
during memory hotremove.
We borrow the basic structure of remove_pagetable() and friends from the
identically-named x86 functions.
Can you add more details here, which explain why we don't need to follow
the RCU page table free when doing memory hotunplug ?
So we want to flush the full kernel tlb when we do a hotplug ?
May be check using flush_tlb_kernel_range(). Also that flush_tlb_mm() do
check for mm_is_thread_local(). Do we update init_mm correct to handle
that check ? I assume we want a tlbie() here instead of tlbiel() ?
quoted hunk
+}
+
int radix__create_section_mapping(unsigned long start, unsigned long end)
{
unsigned long page_size = 1 << mmu_psize_defs[mmu_linear_psize].shift;
@@ -482,6 +635,16 @@ int radix__create_section_mapping(unsigned long start, unsigned long end) return 0; }++int radix__remove_section_mapping(unsigned long start, unsigned long end)+{+ unsigned long page_size = 1 << mmu_psize_defs[mmu_linear_psize].shift;++ start = _ALIGN_DOWN(start, page_size);+ remove_pagetable(start, end, page_size);++ return 0;+} #endif /* CONFIG_MEMORY_HOTPLUG */ #ifdef CONFIG_SPARSEMEM_VMEMMAP
On Mon, Dec 19, 2016 at 02:30:28PM +0530, Aneesh Kumar K.V wrote:
Reza Arbab [off-list ref] writes:
quoted
Change {create,remove}_section_mapping() to be wrappers around
functions prefixed with "hash__".
This is preparation for the addition of their "radix__" variants. No
functional change.
I think this can go upstream now ? To fixup broken hotplug with radix ?
Yes, this one might be worth separating as a fix for the BUG() on radix.
--
Reza Arbab
On Mon, Dec 19, 2016 at 02:34:13PM +0530, Aneesh Kumar K.V wrote:
Reza Arbab [off-list ref] writes:
quoted
Add the linear page mapping function for radix, used by memory
hotplug. This is similar to vmemmap_populate().
Ok with this patch your first patch becomes useful. Can you merge that
with this and rename mmu_linear_psize to mmu_hotplug_psize or even use
mmu_virtual_psize. The linear naming is confusing.
Thanks for pointing out radix_init_pgtable(). I think the right thing to
do here is create these mappings the same way it does. We can probably
factor out a common function.
--
Reza Arbab
On Mon, Dec 19, 2016 at 03:18:07PM +0530, Aneesh Kumar K.V wrote:
Reza Arbab [off-list ref] writes:
quoted
+static void remove_pte_table(pte_t *pte_start, unsigned long addr,
+ unsigned long end)
+{
+ unsigned long next;
+ pte_t *pte;
+
+ pte = pte_start + pte_index(addr);
+ for (; addr < end; addr = next, pte++) {
+ next = (addr + PAGE_SIZE) & PAGE_MASK;
+ if (next > end)
+ next = end;
+
+ if (!pte_present(*pte))
+ continue;
+
+ spin_lock(&init_mm.page_table_lock);
+ pte_clear(&init_mm, addr, pte);
+ spin_unlock(&init_mm.page_table_lock);
+ }
+
+ flush_tlb_mm(&init_mm);
Why call a flush here. we do that at the end of remove_page_table .
Isn't that sufficient ?
This was carried over from the x86 version of the function, where they
do flush_tlb_all(). I can experiment to make sure things work without
it.
quoted
+static void remove_pagetable(unsigned long start, unsigned long end,
+ unsigned long map_page_size)
+{
+ unsigned long next;
+ unsigned long addr;
+ pgd_t *pgd;
+ pud_t *pud;
+
+ for (addr = start; addr < end; addr = next) {
+ next = pgd_addr_end(addr, end);
+
+ pgd = pgd_offset_k(addr);
+ if (!pgd_present(*pgd))
+ continue;
+
+ pud = (pud_t *)pgd_page_vaddr(*pgd);
+ remove_pud_table(pud, addr, next, map_page_size);
+ free_pud_table(pud, pgd);
+ }
+
+ flush_tlb_mm(&init_mm);
So we want to flush the full kernel tlb when we do a hotplug ?
May be check using flush_tlb_kernel_range(). Also that flush_tlb_mm() do
check for mm_is_thread_local(). Do we update init_mm correct to handle
that check ? I assume we want a tlbie() here instead of tlbiel() ?
I'll try using flush_tlb_kernel_range() instead. That sure does seem
more appropriate.
--
Reza Arbab
That is not clearly correct, we map the linear address with either
64K,
2M or 1G depending on the memory available. Take a look at
static void __init radix_init_pgtable(void)
So should we fix that initialization regardless or take it out ?
=20
That is not clearly correct, we map the linear address with either
64K,
2M or 1G depending on the memory available. Take a look at
static void __init radix_init_pgtable(void)
=20
So should we fix that initialization regardless or take it out ?
We should not be usuing mmu_linear_psize on radix. Hence we can skip
that initialization.
-aneesh
Change {create,remove}_section_mapping() to be wrappers around functions
prefixed with "hash__".
This is preparation for the addition of their "radix__" variants. No
functional change.
Signed-off-by: Reza Arbab <redacted>
Add the linear page mapping function for radix, used by memory hotplug.
This is similar to vmemmap_populate().
Ok with this patch your first patch becomes useful. Can you merge that
with this and rename mmu_linear_psize to mmu_hotplug_psize or even use
mmu_virtual_psize. The linear naming is confusing.
mmu_linear_psize variable was referring to the page size used to create
kernel linear mapping (the 0xc00.... range) for the newly added memory
section. Why the name should be changed ?