mm/hwpoison: fix refcount of THP head page in no-injection case
[deliverable/linux.git] / mm / memory-failure.c
index 1f4446a90cef07c67ee1082b83f0ca87ebfefea1..5ceb8253e33b0db15e10e9f2ca258e4846469b4f 100644 (file)
@@ -146,7 +146,7 @@ static int hwpoison_filter_task(struct page *p)
        if (!mem)
                return -EINVAL;
 
-       css = mem_cgroup_css(mem);
+       css = &mem->css;
        ino = cgroup_ino(css->cgroup);
        css_put(css);
 
@@ -934,6 +934,27 @@ int get_hwpoison_page(struct page *page)
 }
 EXPORT_SYMBOL_GPL(get_hwpoison_page);
 
+/**
+ * put_hwpoison_page() - Put refcount for memory error handling:
+ * @page:      raw error page (hit by memory error)
+ */
+void put_hwpoison_page(struct page *page)
+{
+       struct page *head = compound_head(page);
+
+       if (PageHuge(head)) {
+               put_page(head);
+               return;
+       }
+
+       if (PageTransHuge(head))
+               if (page != head)
+                       put_page(head);
+
+       put_page(page);
+}
+EXPORT_SYMBOL_GPL(put_hwpoison_page);
+
 /*
  * Do all that is necessary to remove user space mappings. Unmap
  * the pages and send SIGBUS to the processes if the data was dirty.
@@ -1719,12 +1740,16 @@ int soft_offline_page(struct page *page, int flags)
 
        if (PageHWPoison(page)) {
                pr_info("soft offline: %#lx page already poisoned\n", pfn);
+               if (flags & MF_COUNT_INCREASED)
+                       put_page(page);
                return -EBUSY;
        }
        if (!PageHuge(page) && PageTransHuge(hpage)) {
                if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) {
                        pr_info("soft offline: %#lx: failed to split THP\n",
                                pfn);
+                       if (flags & MF_COUNT_INCREASED)
+                               put_page(page);
                        return -EBUSY;
                }
        }
This page took 0.025788 seconds and 5 git commands to generate.