]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
add commit and revert to make tools happy to prevent from coming back...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 27 Jan 2021 09:59:55 +0000 (10:59 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 27 Jan 2021 09:59:55 +0000 (10:59 +0100)
queue-5.10/mm-fix-initialization-of-struct-page-for-holes-in-memory-layout.patch [new file with mode: 0644]
queue-5.10/revert-mm-fix-initialization-of-struct-page-for-holes-in-memory-layout.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/mm-fix-initialization-of-struct-page-for-holes-in-memory-layout.patch b/queue-5.10/mm-fix-initialization-of-struct-page-for-holes-in-memory-layout.patch
new file mode 100644 (file)
index 0000000..41c7137
--- /dev/null
@@ -0,0 +1,192 @@
+From d3921cb8be29ce5668c64e23ffdaeec5f8c69399 Mon Sep 17 00:00:00 2001
+From: Mike Rapoport <rppt@kernel.org>
+Date: Sat, 23 Jan 2021 21:01:02 -0800
+Subject: mm: fix initialization of struct page for holes in memory layout
+
+From: Mike Rapoport <rppt@linux.ibm.com>
+
+commit d3921cb8be29ce5668c64e23ffdaeec5f8c69399 upstream.
+
+There could be struct pages that are not backed by actual physical
+memory.  This can happen when the actual memory bank is not a multiple
+of SECTION_SIZE or when an architecture does not register memory holes
+reserved by the firmware as memblock.memory.
+
+Such pages are currently initialized using init_unavailable_mem()
+function that iterates through PFNs in holes in memblock.memory and if
+there is a struct page corresponding to a PFN, the fields if this page
+are set to default values and the page is marked as Reserved.
+
+init_unavailable_mem() does not take into account zone and node the page
+belongs to and sets both zone and node links in struct page to zero.
+
+On a system that has firmware reserved holes in a zone above ZONE_DMA,
+for instance in a configuration below:
+
+       # grep -A1 E820 /proc/iomem
+       7a17b000-7a216fff : Unknown E820 type
+       7a217000-7bffffff : System RAM
+
+unset zone link in struct page will trigger
+
+       VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page);
+
+because there are pages in both ZONE_DMA32 and ZONE_DMA (unset zone link
+in struct page) in the same pageblock.
+
+Update init_unavailable_mem() to use zone constraints defined by an
+architecture to properly setup the zone link and use node ID of the
+adjacent range in memblock.memory to set the node link.
+
+Link: https://lkml.kernel.org/r/20210111194017.22696-3-rppt@kernel.org
+Fixes: 73a6e474cb37 ("mm: memmap_init: iterate over memblock regions rather that check each PFN")
+Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
+Reported-by: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Baoquan He <bhe@redhat.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: David Hildenbrand <david@redhat.com>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Mel Gorman <mgorman@suse.de>
+Cc: Michal Hocko <mhocko@kernel.org>
+Cc: Qian Cai <cai@lca.pw>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ mm/page_alloc.c |   84 +++++++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 50 insertions(+), 34 deletions(-)
+
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -7003,23 +7003,26 @@ void __init free_area_init_memoryless_no
+  * Initialize all valid struct pages in the range [spfn, epfn) and mark them
+  * PageReserved(). Return the number of struct pages that were initialized.
+  */
+-static u64 __init init_unavailable_range(unsigned long spfn, unsigned long epfn)
++static u64 __init init_unavailable_range(unsigned long spfn, unsigned long epfn,
++                                       int zone, int nid)
+ {
+-      unsigned long pfn;
++      unsigned long pfn, zone_spfn, zone_epfn;
+       u64 pgcnt = 0;
++      zone_spfn = arch_zone_lowest_possible_pfn[zone];
++      zone_epfn = arch_zone_highest_possible_pfn[zone];
++
++      spfn = clamp(spfn, zone_spfn, zone_epfn);
++      epfn = clamp(epfn, zone_spfn, zone_epfn);
++
+       for (pfn = spfn; pfn < epfn; pfn++) {
+               if (!pfn_valid(ALIGN_DOWN(pfn, pageblock_nr_pages))) {
+                       pfn = ALIGN_DOWN(pfn, pageblock_nr_pages)
+                               + pageblock_nr_pages - 1;
+                       continue;
+               }
+-              /*
+-               * Use a fake node/zone (0) for now. Some of these pages
+-               * (in memblock.reserved but not in memblock.memory) will
+-               * get re-initialized via reserve_bootmem_region() later.
+-               */
+-              __init_single_page(pfn_to_page(pfn), pfn, 0, 0);
++
++              __init_single_page(pfn_to_page(pfn), pfn, zone, nid);
+               __SetPageReserved(pfn_to_page(pfn));
+               pgcnt++;
+       }
+@@ -7028,51 +7031,64 @@ static u64 __init init_unavailable_range
+ }
+ /*
+- * Only struct pages that are backed by physical memory are zeroed and
+- * initialized by going through __init_single_page(). But, there are some
+- * struct pages which are reserved in memblock allocator and their fields
+- * may be accessed (for example page_to_pfn() on some configuration accesses
+- * flags). We must explicitly initialize those struct pages.
++ * Only struct pages that correspond to ranges defined by memblock.memory
++ * are zeroed and initialized by going through __init_single_page() during
++ * memmap_init().
+  *
+- * This function also addresses a similar issue where struct pages are left
+- * uninitialized because the physical address range is not covered by
+- * memblock.memory or memblock.reserved. That could happen when memblock
+- * layout is manually configured via memmap=, or when the highest physical
+- * address (max_pfn) does not end on a section boundary.
++ * But, there could be struct pages that correspond to holes in
++ * memblock.memory. This can happen because of the following reasons:
++ * - phyiscal memory bank size is not necessarily the exact multiple of the
++ *   arbitrary section size
++ * - early reserved memory may not be listed in memblock.memory
++ * - memory layouts defined with memmap= kernel parameter may not align
++ *   nicely with memmap sections
++ *
++ * Explicitly initialize those struct pages so that:
++ * - PG_Reserved is set
++ * - zone link is set accorging to the architecture constrains
++ * - node is set to node id of the next populated region except for the
++ *   trailing hole where last node id is used
+  */
+-static void __init init_unavailable_mem(void)
++static void __init init_zone_unavailable_mem(int zone)
+ {
+-      phys_addr_t start, end;
+-      u64 i, pgcnt;
+-      phys_addr_t next = 0;
++      unsigned long start, end;
++      int i, nid;
++      u64 pgcnt;
++      unsigned long next = 0;
+       /*
+-       * Loop through unavailable ranges not covered by memblock.memory.
++       * Loop through holes in memblock.memory and initialize struct
++       * pages corresponding to these holes
+        */
+       pgcnt = 0;
+-      for_each_mem_range(i, &start, &end) {
++      for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, &nid) {
+               if (next < start)
+-                      pgcnt += init_unavailable_range(PFN_DOWN(next),
+-                                                      PFN_UP(start));
++                      pgcnt += init_unavailable_range(next, start, zone, nid);
+               next = end;
+       }
+       /*
+-       * Early sections always have a fully populated memmap for the whole
+-       * section - see pfn_valid(). If the last section has holes at the
+-       * end and that section is marked "online", the memmap will be
+-       * considered initialized. Make sure that memmap has a well defined
+-       * state.
++       * Last section may surpass the actual end of memory (e.g. we can
++       * have 1Gb section and 512Mb of RAM pouplated).
++       * Make sure that memmap has a well defined state in this case.
+        */
+-      pgcnt += init_unavailable_range(PFN_DOWN(next),
+-                                      round_up(max_pfn, PAGES_PER_SECTION));
++      end = round_up(max_pfn, PAGES_PER_SECTION);
++      pgcnt += init_unavailable_range(next, end, zone, nid);
+       /*
+        * Struct pages that do not have backing memory. This could be because
+        * firmware is using some of this memory, or for some other reasons.
+        */
+       if (pgcnt)
+-              pr_info("Zeroed struct page in unavailable ranges: %lld pages", pgcnt);
++              pr_info("Zone %s: zeroed struct page in unavailable ranges: %lld pages", zone_names[zone], pgcnt);
++}
++
++static void __init init_unavailable_mem(void)
++{
++      int zone;
++
++      for (zone = 0; zone < ZONE_MOVABLE; zone++)
++              init_zone_unavailable_mem(zone);
+ }
+ #else
+ static inline void __init init_unavailable_mem(void)
diff --git a/queue-5.10/revert-mm-fix-initialization-of-struct-page-for-holes-in-memory-layout.patch b/queue-5.10/revert-mm-fix-initialization-of-struct-page-for-holes-in-memory-layout.patch
new file mode 100644 (file)
index 0000000..43407ff
--- /dev/null
@@ -0,0 +1,160 @@
+From 377bf660d07a47269510435d11f3b65d53edca20 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Tue, 26 Jan 2021 10:39:46 -0800
+Subject: Revert "mm: fix initialization of struct page for holes in memory layout"
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit 377bf660d07a47269510435d11f3b65d53edca20 upstream.
+
+This reverts commit d3921cb8be29ce5668c64e23ffdaeec5f8c69399.
+
+Chris Wilson reports that it causes boot problems:
+
+ "We have half a dozen or so different machines in CI that are silently
+  failing to boot, that we believe is bisected to this patch"
+
+and the CI team confirmed that a revert fixed the issues.
+
+The cause is unknown for now, so let's revert it.
+
+Link: https://lore.kernel.org/lkml/161160687463.28991.354987542182281928@build.alporthouse.com/
+Reported-and-tested-by: Chris Wilson <chris@chris-wilson.co.uk>
+Acked-by: Mike Rapoport <rppt@linux.ibm.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ mm/page_alloc.c |   84 ++++++++++++++++++++++----------------------------------
+ 1 file changed, 34 insertions(+), 50 deletions(-)
+
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -7003,26 +7003,23 @@ void __init free_area_init_memoryless_no
+  * Initialize all valid struct pages in the range [spfn, epfn) and mark them
+  * PageReserved(). Return the number of struct pages that were initialized.
+  */
+-static u64 __init init_unavailable_range(unsigned long spfn, unsigned long epfn,
+-                                       int zone, int nid)
++static u64 __init init_unavailable_range(unsigned long spfn, unsigned long epfn)
+ {
+-      unsigned long pfn, zone_spfn, zone_epfn;
++      unsigned long pfn;
+       u64 pgcnt = 0;
+-      zone_spfn = arch_zone_lowest_possible_pfn[zone];
+-      zone_epfn = arch_zone_highest_possible_pfn[zone];
+-
+-      spfn = clamp(spfn, zone_spfn, zone_epfn);
+-      epfn = clamp(epfn, zone_spfn, zone_epfn);
+-
+       for (pfn = spfn; pfn < epfn; pfn++) {
+               if (!pfn_valid(ALIGN_DOWN(pfn, pageblock_nr_pages))) {
+                       pfn = ALIGN_DOWN(pfn, pageblock_nr_pages)
+                               + pageblock_nr_pages - 1;
+                       continue;
+               }
+-
+-              __init_single_page(pfn_to_page(pfn), pfn, zone, nid);
++              /*
++               * Use a fake node/zone (0) for now. Some of these pages
++               * (in memblock.reserved but not in memblock.memory) will
++               * get re-initialized via reserve_bootmem_region() later.
++               */
++              __init_single_page(pfn_to_page(pfn), pfn, 0, 0);
+               __SetPageReserved(pfn_to_page(pfn));
+               pgcnt++;
+       }
+@@ -7031,64 +7028,51 @@ static u64 __init init_unavailable_range
+ }
+ /*
+- * Only struct pages that correspond to ranges defined by memblock.memory
+- * are zeroed and initialized by going through __init_single_page() during
+- * memmap_init().
++ * Only struct pages that are backed by physical memory are zeroed and
++ * initialized by going through __init_single_page(). But, there are some
++ * struct pages which are reserved in memblock allocator and their fields
++ * may be accessed (for example page_to_pfn() on some configuration accesses
++ * flags). We must explicitly initialize those struct pages.
+  *
+- * But, there could be struct pages that correspond to holes in
+- * memblock.memory. This can happen because of the following reasons:
+- * - phyiscal memory bank size is not necessarily the exact multiple of the
+- *   arbitrary section size
+- * - early reserved memory may not be listed in memblock.memory
+- * - memory layouts defined with memmap= kernel parameter may not align
+- *   nicely with memmap sections
+- *
+- * Explicitly initialize those struct pages so that:
+- * - PG_Reserved is set
+- * - zone link is set accorging to the architecture constrains
+- * - node is set to node id of the next populated region except for the
+- *   trailing hole where last node id is used
++ * This function also addresses a similar issue where struct pages are left
++ * uninitialized because the physical address range is not covered by
++ * memblock.memory or memblock.reserved. That could happen when memblock
++ * layout is manually configured via memmap=, or when the highest physical
++ * address (max_pfn) does not end on a section boundary.
+  */
+-static void __init init_zone_unavailable_mem(int zone)
++static void __init init_unavailable_mem(void)
+ {
+-      unsigned long start, end;
+-      int i, nid;
+-      u64 pgcnt;
+-      unsigned long next = 0;
++      phys_addr_t start, end;
++      u64 i, pgcnt;
++      phys_addr_t next = 0;
+       /*
+-       * Loop through holes in memblock.memory and initialize struct
+-       * pages corresponding to these holes
++       * Loop through unavailable ranges not covered by memblock.memory.
+        */
+       pgcnt = 0;
+-      for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, &nid) {
++      for_each_mem_range(i, &start, &end) {
+               if (next < start)
+-                      pgcnt += init_unavailable_range(next, start, zone, nid);
++                      pgcnt += init_unavailable_range(PFN_DOWN(next),
++                                                      PFN_UP(start));
+               next = end;
+       }
+       /*
+-       * Last section may surpass the actual end of memory (e.g. we can
+-       * have 1Gb section and 512Mb of RAM pouplated).
+-       * Make sure that memmap has a well defined state in this case.
++       * Early sections always have a fully populated memmap for the whole
++       * section - see pfn_valid(). If the last section has holes at the
++       * end and that section is marked "online", the memmap will be
++       * considered initialized. Make sure that memmap has a well defined
++       * state.
+        */
+-      end = round_up(max_pfn, PAGES_PER_SECTION);
+-      pgcnt += init_unavailable_range(next, end, zone, nid);
++      pgcnt += init_unavailable_range(PFN_DOWN(next),
++                                      round_up(max_pfn, PAGES_PER_SECTION));
+       /*
+        * Struct pages that do not have backing memory. This could be because
+        * firmware is using some of this memory, or for some other reasons.
+        */
+       if (pgcnt)
+-              pr_info("Zone %s: zeroed struct page in unavailable ranges: %lld pages", zone_names[zone], pgcnt);
+-}
+-
+-static void __init init_unavailable_mem(void)
+-{
+-      int zone;
+-
+-      for (zone = 0; zone < ZONE_MOVABLE; zone++)
+-              init_zone_unavailable_mem(zone);
++              pr_info("Zeroed struct page in unavailable ranges: %lld pages", pgcnt);
+ }
+ #else
+ static inline void __init init_unavailable_mem(void)
index 62105821961f17d039f9237c661dd4c0eb9c984a..1197af90e620446d8cd4cb4082b8f8255dae929e 100644 (file)
@@ -200,3 +200,5 @@ kernfs-wire-up-splice_read-and-splice_write.patch
 interconnect-imx8mq-use-icc_sync_state.patch
 fs-pipe-allow-sendfile-to-pipe-again.patch
 commit-9bb48c82aced-tty-implement-write_iter-converted-the-tty-layer-to-use-write_iter.-fix-the-redirected_tty_write-declaration-also-in-n_tty-and-change-the-comparisons-to-use-write_iter-instead-of-write.patch
+mm-fix-initialization-of-struct-page-for-holes-in-memory-layout.patch
+revert-mm-fix-initialization-of-struct-page-for-holes-in-memory-layout.patch