@@ -960,30 +960,43 @@ static int __get_hwpoison_page(struct pa
{
struct page *head = compound_head(page);
- if (!PageHuge(head) && PageTransHuge(head)) {
- /*
- * Non anonymous thp exists only in allocation/free time. We
- * can't handle such a case correctly, so let's give it up.
- * This should be better than triggering BUG_ON when kernel
- * tries to touch the "partially handled" page.
- */
- if (!PageAnon(head)) {
- pr_err("Memory failure: %#lx: non anonymous thp\n",
- page_to_pfn(page));
- return 0;
- }
- }
+ if (PageCompound(page)) {
+ if (PageSlab(page)) {
+ return get_page_unless_zero(page);
+ } else if (PageHuge(head)) {
+ int ret = 0;
- if (get_page_unless_zero(head)) {
- if (head == compound_head(page))
- return 1;
-
- pr_info("Memory failure: %#lx cannot catch tail\n",
- page_to_pfn(page));
- put_page(head);
+ spin_lock(&hugetlb_lock);
+ if (!PageHuge(head))
+ ret = -EBUSY;
+ else if (HPageFreed(head) || HPageMigratable(head))
+ ret = get_page_unless_zero(head);
+ spin_unlock(&hugetlb_lock);
+ return ret;
+ } else if (PageTransHuge(head)) {
+ /*
+ * Non anonymous thp exists only in allocation/free time. We
+ * can't handle such a case correctly, so let's give it up.
+ * This should be better than triggering BUG_ON when kernel
+ * tries to touch the "partially handled" page.
+ */
+ if (!PageAnon(head)) {
+ pr_err("Memory failure: %#lx: non anonymous thp\n",
+ page_to_pfn(page));
+ return 0;
+ }
+ if (get_page_unless_zero(head)) {
+ if (head == compound_head(page))
+ return 1;
+ pr_info("Memory failure: %#lx cannot catch tail\n",
+ page_to_pfn(page));
+ put_page(head);
+ }
+ }
+ return 0;
}
- return 0;
+ return get_page_unless_zero(page);
}
/*