HWPOISON: Turn ref argument into flags argument
[deliverable/linux.git] / mm / memory-failure.c
index 1ac49fef95ab43b716979a360375c66be706160c..3338c443272c8ea8bf434daec43ab369bed86e98 100644 (file)
@@ -82,6 +82,28 @@ static int kill_proc_ao(struct task_struct *t, unsigned long addr, int trapno,
        return ret;
 }
 
+/*
+ * When a unknown page type is encountered drain as many buffers as possible
+ * in the hope to turn the page into a LRU or free page, which we can handle.
+ */
+void shake_page(struct page *p)
+{
+       if (!PageSlab(p)) {
+               lru_add_drain_all();
+               if (PageLRU(p))
+                       return;
+               drain_all_pages();
+               if (PageLRU(p) || is_free_buddy_page(p))
+                       return;
+       }
+       /*
+        * Could call shrink_slab here (which would also
+        * shrink other caches). Unfortunately that might
+        * also access the corrupted page, which could be fatal.
+        */
+}
+EXPORT_SYMBOL_GPL(shake_page);
+
 /*
  * Kill all processes that have a poisoned page mapped and then isolate
  * the page.
@@ -582,14 +604,11 @@ static struct page_state {
        { unevict|dirty, unevict|dirty, "unevictable LRU", me_pagecache_dirty},
        { unevict,      unevict,        "unevictable LRU", me_pagecache_clean},
 
-#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
        { mlock|dirty,  mlock|dirty,    "mlocked LRU",  me_pagecache_dirty },
        { mlock,        mlock,          "mlocked LRU",  me_pagecache_clean },
-#endif
 
        { lru|dirty,    lru|dirty,      "LRU",          me_pagecache_dirty },
        { lru|dirty,    lru,            "clean LRU",    me_pagecache_clean },
-       { swapbacked,   swapbacked,     "anonymous",    me_pagecache_clean },
 
        /*
         * Catchall entry: must be at end.
@@ -599,18 +618,16 @@ static struct page_state {
 
 static void action_result(unsigned long pfn, char *msg, int result)
 {
-       struct page *page = NULL;
-       if (pfn_valid(pfn))
-               page = pfn_to_page(pfn);
+       struct page *page = pfn_to_page(pfn);
 
        printk(KERN_ERR "MCE %#lx: %s%s page recovery: %s\n",
                pfn,
-               page && PageDirty(page) ? "dirty " : "",
+               PageDirty(page) ? "dirty " : "",
                msg, action_name[result]);
 }
 
 static int page_action(struct page_state *ps, struct page *p,
-                       unsigned long pfn, int ref)
+                       unsigned long pfn)
 {
        int result;
        int count;
@@ -618,7 +635,7 @@ static int page_action(struct page_state *ps, struct page *p,
        result = ps->action(p, pfn);
        action_result(pfn, ps->msg, result);
 
-       count = page_count(p) - 1 - ref;
+       count = page_count(p) - 1;
        if (count != 0)
                printk(KERN_ERR
                       "MCE %#lx: %s page still referenced by %d users\n",
@@ -720,7 +737,7 @@ static void hwpoison_user_mappings(struct page *p, unsigned long pfn,
                      ret != SWAP_SUCCESS, pfn);
 }
 
-int __memory_failure(unsigned long pfn, int trapno, int ref)
+int __memory_failure(unsigned long pfn, int trapno, int flags)
 {
        unsigned long lru_flag;
        struct page_state *ps;
@@ -731,8 +748,10 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
                panic("Memory failure from trap %d on page %lx", trapno, pfn);
 
        if (!pfn_valid(pfn)) {
-               action_result(pfn, "memory outside kernel control", IGNORED);
-               return -EIO;
+               printk(KERN_ERR
+                      "MCE %#lx: memory outside kernel control\n",
+                      pfn);
+               return -ENXIO;
        }
 
        p = pfn_to_page(pfn);
@@ -754,7 +773,8 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
         * In fact it's dangerous to directly bump up page count from 0,
         * that may make page_freeze_refs()/page_unfreeze_refs() mismatch.
         */
-       if (!get_page_unless_zero(compound_head(p))) {
+       if (!(flags & MF_COUNT_INCREASED) &&
+               !get_page_unless_zero(compound_head(p))) {
                action_result(pfn, "free or high order kernel", IGNORED);
                return PageBuddy(compound_head(p)) ? 0 : -EBUSY;
        }
@@ -802,7 +822,7 @@ int __memory_failure(unsigned long pfn, int trapno, int ref)
        res = -EBUSY;
        for (ps = error_states;; ps++) {
                if (((p->flags | lru_flag)& ps->mask) == ps->res) {
-                       res = page_action(ps, p, pfn, ref);
+                       res = page_action(ps, p, pfn);
                        break;
                }
        }
This page took 0.042093 seconds and 5 git commands to generate.