All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] powerpc/mm/pgtable: Split mappings on hot-unplug
@ 2018-02-07  6:35 Balbir Singh
  2018-02-09  4:00 ` Michael Ellerman
  0 siblings, 1 reply; 2+ messages in thread
From: Balbir Singh @ 2018-02-07  6:35 UTC (permalink / raw)
  To: linuxppc-dev

This patch splits the a linear mapping if the hot-unplug range
is smaller than the mapping size. The code detects if the mapping
needs to be split into a smaller size and if so, uses the stop
machine infrastructure to map the current linear mapping with
a smaller size mapping. Then the requested area is unmapped.

The code will skip any region of the mapping that overlaps with
kernel text and warn about it once. We don't want to remove
a mapping where the kernel text and the LMB we intend to remove
overlap in the same TLB mapping as it may affect the currently
executing code (being cautious, we might be able to remove this
restriction later, see TODOs below)

I've tested these changes under a kvm guest with 2 vcpus, from
a split mapping point of view, some of the caveats mentioned
above applied to the testing I did.

TODOs:
1. Refine the stop machine with an atomic replacement of the
PMD. The code needs to be refactored to support those changes.
I intend to publish those changes, but this is a minimal set
that should be also probably backported to stable

Signed-off-by: Balbir Singh <bsingharora@gmail.com>
---


Changelog
  - Refactored the code based on suggestions from mpe
  - Removed the local tlb flush
  - Skip creating mappings for region to be removed
    and then removing the region, let create_physical_mapping
    deal with that complexity (it already has the code)

 arch/powerpc/mm/pgtable-radix.c | 95 ++++++++++++++++++++++++++++++++---------
 1 file changed, 74 insertions(+), 21 deletions(-)

diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c
index cfbbee941a76..17ae5c15a9e0 100644
--- a/arch/powerpc/mm/pgtable-radix.c
+++ b/arch/powerpc/mm/pgtable-radix.c
@@ -17,6 +17,7 @@
 #include <linux/of_fdt.h>
 #include <linux/mm.h>
 #include <linux/string_helpers.h>
+#include <linux/stop_machine.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -671,6 +672,30 @@ static void free_pmd_table(pmd_t *pmd_start, pud_t *pud)
 	pud_clear(pud);
 }
 
+struct change_mapping_params {
+	pte_t *pte;
+	unsigned long start;
+	unsigned long end;
+	unsigned long aligned_start;
+	unsigned long aligned_end;
+};
+
+static int stop_machine_change_mapping(void *data)
+{
+	struct change_mapping_params *params =
+			(struct change_mapping_params *)data;
+
+	if (!data)
+		return -1;
+
+	spin_unlock(&init_mm.page_table_lock);
+	pte_clear(&init_mm, params->aligned_start, params->pte);
+	create_physical_mapping(params->aligned_start, params->start);
+	create_physical_mapping(params->end, params->aligned_end);
+	spin_lock(&init_mm.page_table_lock);
+	return 0;
+}
+
 static void remove_pte_table(pte_t *pte_start, unsigned long addr,
 			     unsigned long end)
 {
@@ -699,6 +724,52 @@ static void remove_pte_table(pte_t *pte_start, unsigned long addr,
 	}
 }
 
+/*
+ * clear the pte and potentially split the mapping helper
+ */
+static void split_kernel_mapping(unsigned long addr, unsigned long end,
+				unsigned long size, pte_t *pte)
+{
+	unsigned long mask = ~(size - 1);
+	unsigned long aligned_start = addr & mask;
+	unsigned long aligned_end = addr + size;
+	struct change_mapping_params params;
+	bool split_region = false;
+
+	if ((end - addr) < size) {
+		/*
+		 * We're going to clear the PTE, but not flushed
+		 * the mapping, time to remap and flush. The
+		 * effects if visible outside the processor or
+		 * if we are running in code close to the
+		 * mapping we cleared, we are in trouble.
+		 */
+		if (overlaps_kernel_text(aligned_start, addr) ||
+			overlaps_kernel_text(end, aligned_end)) {
+			/*
+			 * Hack, just return, don't pte_clear
+			 */
+			WARN_ONCE(1, "Linear mapping %lx->%lx overlaps kernel "
+				  "text, not splitting\n", addr, end);
+			return;
+		}
+		split_region = true;
+	}
+
+	if (split_region) {
+		params.pte = pte;
+		params.start = addr;
+		params.end = end;
+		params.aligned_start = addr & ~(size - 1);
+		params.aligned_end = min_t(unsigned long, aligned_end,
+				(unsigned long)__va(memblock_end_of_DRAM()));
+		stop_machine(stop_machine_change_mapping, &params, NULL);
+		return;
+	}
+
+	pte_clear(&init_mm, addr, pte);
+}
+
 static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr,
 			     unsigned long end)
 {
@@ -714,13 +785,7 @@ static void remove_pmd_table(pmd_t *pmd_start, unsigned long addr,
 			continue;
 
 		if (pmd_huge(*pmd)) {
-			if (!IS_ALIGNED(addr, PMD_SIZE) ||
-			    !IS_ALIGNED(next, PMD_SIZE)) {
-				WARN_ONCE(1, "%s: unaligned range\n", __func__);
-				continue;
-			}
-
-			pte_clear(&init_mm, addr, (pte_t *)pmd);
+			split_kernel_mapping(addr, end, PMD_SIZE, (pte_t *)pmd);
 			continue;
 		}
 
@@ -745,13 +810,7 @@ static void remove_pud_table(pud_t *pud_start, unsigned long addr,
 			continue;
 
 		if (pud_huge(*pud)) {
-			if (!IS_ALIGNED(addr, PUD_SIZE) ||
-			    !IS_ALIGNED(next, PUD_SIZE)) {
-				WARN_ONCE(1, "%s: unaligned range\n", __func__);
-				continue;
-			}
-
-			pte_clear(&init_mm, addr, (pte_t *)pud);
+			split_kernel_mapping(addr, end, PUD_SIZE, (pte_t *)pud);
 			continue;
 		}
 
@@ -777,13 +836,7 @@ static void remove_pagetable(unsigned long start, unsigned long end)
 			continue;
 
 		if (pgd_huge(*pgd)) {
-			if (!IS_ALIGNED(addr, PGDIR_SIZE) ||
-			    !IS_ALIGNED(next, PGDIR_SIZE)) {
-				WARN_ONCE(1, "%s: unaligned range\n", __func__);
-				continue;
-			}
-
-			pte_clear(&init_mm, addr, (pte_t *)pgd);
+			split_kernel_mapping(addr, end, PGDIR_SIZE, (pte_t *)pgd);
 			continue;
 		}
 
-- 
2.13.6

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

* Re: powerpc/mm/pgtable: Split mappings on hot-unplug
  2018-02-07  6:35 [PATCH] powerpc/mm/pgtable: Split mappings on hot-unplug Balbir Singh
@ 2018-02-09  4:00 ` Michael Ellerman
  0 siblings, 0 replies; 2+ messages in thread
From: Michael Ellerman @ 2018-02-09  4:00 UTC (permalink / raw)
  To: Balbir Singh, linuxppc-dev

On Wed, 2018-02-07 at 06:35:51 UTC, Balbir Singh wrote:
> This patch splits the a linear mapping if the hot-unplug range
> is smaller than the mapping size. The code detects if the mapping
> needs to be split into a smaller size and if so, uses the stop
> machine infrastructure to map the current linear mapping with
> a smaller size mapping. Then the requested area is unmapped.
> 
> The code will skip any region of the mapping that overlaps with
> kernel text and warn about it once. We don't want to remove
> a mapping where the kernel text and the LMB we intend to remove
> overlap in the same TLB mapping as it may affect the currently
> executing code (being cautious, we might be able to remove this
> restriction later, see TODOs below)
> 
> I've tested these changes under a kvm guest with 2 vcpus, from
> a split mapping point of view, some of the caveats mentioned
> above applied to the testing I did.
> 
> TODOs:
> 1. Refine the stop machine with an atomic replacement of the
> PMD. The code needs to be refactored to support those changes.
> I intend to publish those changes, but this is a minimal set
> that should be also probably backported to stable
> 
> Signed-off-by: Balbir Singh <bsingharora@gmail.com>

Applied to powerpc fixes, thanks.

https://git.kernel.org/powerpc/c/4dd5f8a99e791a8c6500e3592f3ce8

cheers

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

end of thread, other threads:[~2018-02-09  4:00 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-07  6:35 [PATCH] powerpc/mm/pgtable: Split mappings on hot-unplug Balbir Singh
2018-02-09  4:00 ` Michael Ellerman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.