[PATCH] powerpc/fadump: add reschedule point while releasing memory

Hari Bathini hbathini at linux.vnet.ibm.com
Tue May 23 17:54:03 AEST 2017


Around 95% of memory is reserved by fadump/capture kernel. All this
memory is freed, one page at a time, on writing '1' to the node
/sys/kernel/fadump_release_mem. On systems with large memory, this
can take a long time to complete, leading to soft lockup warning
messages. To avoid this, add reschedule points at regular intervals.

Suggested-by: Michael Ellerman <mpe at ellerman.id.au>
Signed-off-by: Hari Bathini <hbathini at linux.vnet.ibm.com>
---
 arch/powerpc/kernel/fadump.c |   60 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 49 insertions(+), 11 deletions(-)

diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 466569e..0babefc 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -1046,28 +1046,66 @@ void fadump_cleanup(void)
 	}
 }
 
+/* Time to wait before a reschedule point */
+#define RELEASE_TIME_LIMIT			500	/* in milliseconds */
+
+/* Release memory in batches of 'N' pages each */
+#define RELEASE_PAGES_BATCH			(1 << 22)
+
+static void fadump_free_reserved_memory(unsigned long start, unsigned long end)
+{
+	unsigned long pfn, start_pfn, end_pfn;
+	unsigned int remaining = end > start ? (end - start) >> PAGE_SHIFT : 0;
+	unsigned long time_limit = jiffies +
+					msecs_to_jiffies(RELEASE_TIME_LIMIT);
+
+	while (remaining) {
+		/* A reschedule point for every 'X' milliseconds */
+		if (time_after_eq(jiffies, time_limit)) {
+			cond_resched();
+			time_limit = jiffies +
+					msecs_to_jiffies(RELEASE_TIME_LIMIT);
+		}
+
+		/* release memory in batches of 'N' pages */
+		start_pfn = start >> PAGE_SHIFT;
+		if (remaining > RELEASE_PAGES_BATCH) {
+			end_pfn = start_pfn + RELEASE_PAGES_BATCH;
+			remaining -= RELEASE_PAGES_BATCH;
+		} else {
+			end_pfn = end >> PAGE_SHIFT;
+			remaining = 0;
+		}
+
+		for (pfn = start_pfn; pfn < end_pfn; pfn++)
+			free_reserved_page(pfn_to_page(pfn));
+
+		start = end_pfn << PAGE_SHIFT;
+	}
+}
+
 /*
  * Release the memory that was reserved in early boot to preserve the memory
  * contents. The released memory will be available for general use.
  */
 static void fadump_release_memory(unsigned long begin, unsigned long end)
 {
-	unsigned long addr;
 	unsigned long ra_start, ra_end;
 
 	ra_start = fw_dump.reserve_dump_area_start;
 	ra_end = ra_start + fw_dump.reserve_dump_area_size;
 
-	for (addr = begin; addr < end; addr += PAGE_SIZE) {
-		/*
-		 * exclude the dump reserve area. Will reuse it for next
-		 * fadump registration.
-		 */
-		if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start))
-			continue;
-
-		free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
-	}
+	/*
+	 * exclude the dump reserve area. Will reuse it for next
+	 * fadump registration.
+	 */
+	if (begin < ra_end && end > ra_start) {
+		if (begin < ra_start)
+			fadump_free_reserved_memory(begin, ra_start);
+		if (end > ra_end)
+			fadump_free_reserved_memory(ra_end, end);
+	} else
+		fadump_free_reserved_memory(begin, end);
 }
 
 static void fadump_invalidate_release_mem(void)



More information about the Linuxppc-dev mailing list