[RFC PATCH 2/3] mm: Create snapshot_page()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Move the guts of __dump_page() into a new function called
snapshot_page().  With that done, __dump_page() becomes trivial so
inline it into dump_page().

Signed-off-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx>
---
 mm/debug.c    | 53 +++++++++------------------------------------------
 mm/internal.h |  2 ++
 mm/util.c     | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+), 44 deletions(-)

diff --git a/mm/debug.c b/mm/debug.c
index fa3d9686034c..1ea5dacb1524 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -120,54 +120,19 @@ static void __dump_folio(const struct folio *folio, struct page *page,
 			2 * sizeof(struct page), false);
 }
 
-static void __dump_page(const struct page *page)
-{
-	struct folio *foliop, folio;
-	struct page precise;
-	unsigned long head;
-	unsigned long pfn = page_to_pfn(page);
-	unsigned long idx, nr_pages = 1;
-	int loops = 5;
-
-again:
-	memcpy(&precise, page, sizeof(*page));
-	head = precise.compound_head;
-	if ((head & 1) == 0) {
-		foliop = (struct folio *)&precise;
-		idx = 0;
-		if (!folio_test_large(foliop))
-			goto dump;
-		foliop = (struct folio *)page;
-	} else {
-		foliop = (struct folio *)(head - 1);
-		idx = folio_page_idx(foliop, page);
-	}
-
-	if (idx < MAX_FOLIO_NR_PAGES) {
-		memcpy(&folio, foliop, 2 * sizeof(struct page));
-		nr_pages = folio_nr_pages(&folio);
-		foliop = &folio;
-	}
-
-	if (idx > nr_pages) {
-		if (loops-- > 0)
-			goto again;
-		pr_warn("page does not match folio\n");
-		precise.compound_head &= ~1UL;
-		foliop = (struct folio *)&precise;
-		idx = 0;
-	}
-
-dump:
-	__dump_folio(foliop, &precise, pfn, idx);
-}
-
 void dump_page(const struct page *page, const char *reason)
 {
+	struct folio stack_folio;
+	struct page stack_page;
+	const struct folio *folio;
+	unsigned long idx;
+
 	if (PagePoisoned(page))
 		pr_warn("page:%p is uninitialized and poisoned", page);
-	else
-		__dump_page(page);
+	else {
+		folio = snapshot_page(&stack_folio, &stack_page, &idx, page);
+		__dump_folio(folio, &stack_page, page_to_pfn(page), idx);
+	}
 	if (reason)
 		pr_warn("page dumped because: %s\n", reason);
 	dump_page_owner(page);
diff --git a/mm/internal.h b/mm/internal.h
index 109ef30fee11..8fdfea104068 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -856,6 +856,8 @@ static inline bool free_area_empty(struct free_area *area, int migratetype)
 
 /* mm/util.c */
 struct anon_vma *folio_anon_vma(const struct folio *folio);
+const struct folio *snapshot_page(struct folio *foliop, struct page *precise,
+		unsigned long *idxp, const struct page *unstable);
 
 #ifdef CONFIG_MMU
 void unmap_mapping_folio(struct folio *folio);
diff --git a/mm/util.c b/mm/util.c
index 682ecdb1b1c2..9f9cf3933eb1 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -1239,3 +1239,53 @@ void flush_dcache_folio(struct folio *folio)
 }
 EXPORT_SYMBOL(flush_dcache_folio);
 #endif
+
+/*
+ * If you have an unstable reference to a page, use this to get a
+ * somewhat-consistent (potentially outdated) snapshot.  The consistency
+ * is limited to the page being contained in the folio.  You need to pass in
+ * a scratch folio and scratch page, probably allocated on the stack.
+ * You get back a pointer to the scratch folio you passed in, marked
+ * as const to remind you not to modify this.
+ */
+const struct folio *snapshot_page(struct folio *foliop, struct page *precise,
+		unsigned long *idxp, const struct page *unstable)
+{
+	struct folio *folio;
+	unsigned long head;
+	unsigned long idx, nr_pages = 1;
+	int loops = 5;
+
+again:
+	memcpy(precise, unstable, sizeof(struct page));
+	head = precise->compound_head;
+	/* Open-coded !PageTail because page_is_fake_head() doesn't work here */
+	if ((head & 1) == 0) {
+		folio = (struct folio *)precise;
+		*idxp = 0;
+		/* Not a tail, not a head, we have a single page */
+		if (!folio_test_large(folio))
+			goto out;
+		folio = (struct folio *)unstable;
+	} else {
+		folio = (struct folio *)(head - 1);
+		*idxp = folio_page_idx(folio, unstable);
+	}
+
+	if (idx < MAX_FOLIO_NR_PAGES || folio_test_hugetlb(folio)) {
+		memcpy(foliop, folio, sizeof(struct folio));
+		nr_pages = folio_nr_pages(foliop);
+		folio = foliop;
+	}
+
+	if (idx > nr_pages) {
+		if (loops-- > 0)
+			goto again;
+		pr_warn("page does not match folio\n");
+		precise->compound_head &= ~1UL;
+		folio = (struct folio *)precise;
+		*idxp = 0;
+	}
+out:
+	return folio;
+}
-- 
2.47.2





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux