]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - mm/memory-failure.c
fs/ncpfs/dir.c: remove unnecessary new_valid_dev() check
[karo-tx-linux.git] / mm / memory-failure.c
index 95882692e747c2a534488190287e5954fba35d39..a2c987df80ebb8357556da359e50c9746b4e7721 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/memory_hotplug.h>
 #include <linux/mm_inline.h>
 #include <linux/kfifo.h>
+#include <linux/ratelimit.h>
 #include "internal.h"
 #include "ras/ras_event.h"
 
@@ -775,8 +776,6 @@ static int me_huge_page(struct page *p, unsigned long pfn)
 #define lru            (1UL << PG_lru)
 #define swapbacked     (1UL << PG_swapbacked)
 #define head           (1UL << PG_head)
-#define tail           (1UL << PG_tail)
-#define compound       (1UL << PG_compound)
 #define slab           (1UL << PG_slab)
 #define reserved       (1UL << PG_reserved)
 
@@ -799,12 +798,7 @@ static struct page_state {
         */
        { slab,         slab,           MF_MSG_SLAB,    me_kernel },
 
-#ifdef CONFIG_PAGEFLAGS_EXTENDED
        { head,         head,           MF_MSG_HUGE,            me_huge_page },
-       { tail,         tail,           MF_MSG_HUGE,            me_huge_page },
-#else
-       { compound,     compound,       MF_MSG_HUGE,            me_huge_page },
-#endif
 
        { sc|dirty,     sc|dirty,       MF_MSG_DIRTY_SWAPCACHE, me_swapcache_dirty },
        { sc|dirty,     sc,             MF_MSG_CLEAN_SWAPCACHE, me_swapcache_clean },
@@ -1155,7 +1149,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        }
 
        if (!PageHuge(p) && PageTransHuge(hpage)) {
+               lock_page(hpage);
                if (!PageAnon(hpage) || unlikely(split_huge_page(hpage))) {
+                       unlock_page(hpage);
                        if (!PageAnon(hpage))
                                pr_err("MCE: %#lx: non anonymous thp\n", pfn);
                        else
@@ -1165,6 +1161,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
                        put_hwpoison_page(p);
                        return -EBUSY;
                }
+               unlock_page(hpage);
                VM_BUG_ON_PAGE(!page_count(p), p);
                hpage = compound_head(p);
        }
@@ -1172,7 +1169,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        /*
         * We ignore non-LRU pages for good reasons.
         * - PG_locked is only well defined for LRU pages and a few others
-        * - to avoid races with __set_page_locked()
+        * - to avoid races with __SetPageLocked()
         * - to avoid races with __SetPageSlab*() (and more non-atomic ops)
         * The check (unnecessarily) ignores LRU pages being isolated and
         * walked by the page reclaim code, however that's not a big loss.
@@ -1403,6 +1400,12 @@ static int __init memory_failure_init(void)
 }
 core_initcall(memory_failure_init);
 
+#define unpoison_pr_info(fmt, pfn, rs)                 \
+({                                                     \
+       if (__ratelimit(rs))                            \
+               pr_info(fmt, pfn);                      \
+})
+
 /**
  * unpoison_memory - Unpoison a previously poisoned page
  * @pfn: Page number of the to be unpoisoned page
@@ -1421,6 +1424,8 @@ int unpoison_memory(unsigned long pfn)
        struct page *p;
        int freeit = 0;
        unsigned int nr_pages;
+       static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL,
+                                       DEFAULT_RATELIMIT_BURST);
 
        if (!pfn_valid(pfn))
                return -ENXIO;
@@ -1429,23 +1434,26 @@ int unpoison_memory(unsigned long pfn)
        page = compound_head(p);
 
        if (!PageHWPoison(p)) {
-               pr_info("MCE: Page was already unpoisoned %#lx\n", pfn);
+               unpoison_pr_info("MCE: Page was already unpoisoned %#lx\n",
+                                pfn, &unpoison_rs);
                return 0;
        }
 
        if (page_count(page) > 1) {
-               pr_info("MCE: Someone grabs the hwpoison page %#lx\n", pfn);
+               unpoison_pr_info("MCE: Someone grabs the hwpoison page %#lx\n",
+                                pfn, &unpoison_rs);
                return 0;
        }
 
        if (page_mapped(page)) {
-               pr_info("MCE: Someone maps the hwpoison page %#lx\n", pfn);
+               unpoison_pr_info("MCE: Someone maps the hwpoison page %#lx\n",
+                                pfn, &unpoison_rs);
                return 0;
        }
 
        if (page_mapping(page)) {
-               pr_info("MCE: the hwpoison page has non-NULL mapping %#lx\n",
-                       pfn);
+               unpoison_pr_info("MCE: the hwpoison page has non-NULL mapping %#lx\n",
+                                pfn, &unpoison_rs);
                return 0;
        }
 
@@ -1455,7 +1463,8 @@ int unpoison_memory(unsigned long pfn)
         * In such case, we yield to memory_failure() and make unpoison fail.
         */
        if (!PageHuge(page) && PageTransHuge(page)) {
-               pr_info("MCE: Memory failure is now running on %#lx\n", pfn);
+               unpoison_pr_info("MCE: Memory failure is now running on %#lx\n",
+                                pfn, &unpoison_rs);
                return 0;
        }
 
@@ -1469,12 +1478,14 @@ int unpoison_memory(unsigned long pfn)
                 * to the end.
                 */
                if (PageHuge(page)) {
-                       pr_info("MCE: Memory failure is now running on free hugepage %#lx\n", pfn);
+                       unpoison_pr_info("MCE: Memory failure is now running on free hugepage %#lx\n",
+                                        pfn, &unpoison_rs);
                        return 0;
                }
                if (TestClearPageHWPoison(p))
                        num_poisoned_pages_dec();
-               pr_info("MCE: Software-unpoisoned free page %#lx\n", pfn);
+               unpoison_pr_info("MCE: Software-unpoisoned free page %#lx\n",
+                                pfn, &unpoison_rs);
                return 0;
        }
 
@@ -1486,7 +1497,8 @@ int unpoison_memory(unsigned long pfn)
         * the free buddy page pool.
         */
        if (TestClearPageHWPoison(page)) {
-               pr_info("MCE: Software-unpoisoned page %#lx\n", pfn);
+               unpoison_pr_info("MCE: Software-unpoisoned page %#lx\n",
+                                pfn, &unpoison_rs);
                num_poisoned_pages_sub(nr_pages);
                freeit = 1;
                if (PageHuge(page))
@@ -1742,7 +1754,10 @@ int soft_offline_page(struct page *page, int flags)
                return -EBUSY;
        }
        if (!PageHuge(page) && PageTransHuge(hpage)) {
-               if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) {
+               lock_page(page);
+               ret = split_huge_page(hpage);
+               unlock_page(page);
+               if (unlikely(ret)) {
                        pr_info("soft offline: %#lx: failed to split THP\n",
                                pfn);
                        if (flags & MF_COUNT_INCREASED)