hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/mm/memory-failure.c
....@@ -1690,70 +1690,51 @@
16901690
16911691 /*
16921692 * Safely get reference count of an arbitrary page.
1693
- * Returns 0 for a free page, -EIO for a zero refcount page
1694
- * that is not free, and 1 for any other page type.
1695
- * For 1 the page is returned with increased page count, otherwise not.
1693
+ * Returns 0 for a free page, 1 for an in-use page, -EIO for a page-type we
1694
+ * cannot handle and -EBUSY if we raced with an allocation.
1695
+ * We only incremented refcount in case the page was already in-use and it is
1696
+ * a known type we can handle.
16961697 */
1697
-static int __get_any_page(struct page *p, unsigned long pfn, int flags)
1698
+static int get_any_page(struct page *p, int flags)
16981699 {
1699
- int ret;
1700
+ int ret = 0, pass = 0;
1701
+ bool count_increased = false;
17001702
17011703 if (flags & MF_COUNT_INCREASED)
1702
- return 1;
1704
+ count_increased = true;
17031705
1704
- /*
1705
- * When the target page is a free hugepage, just remove it
1706
- * from free hugepage list.
1707
- */
1708
- if (!get_hwpoison_page(p)) {
1709
- if (PageHuge(p)) {
1710
- pr_info("%s: %#lx free huge page\n", __func__, pfn);
1711
- ret = 0;
1712
- } else if (is_free_buddy_page(p)) {
1713
- pr_info("%s: %#lx free buddy page\n", __func__, pfn);
1714
- ret = 0;
1715
- } else if (page_count(p)) {
1716
- /* raced with allocation */
1706
+try_again:
1707
+ if (!count_increased && !get_hwpoison_page(p)) {
1708
+ if (page_count(p)) {
1709
+ /* We raced with an allocation, retry. */
1710
+ if (pass++ < 3)
1711
+ goto try_again;
17171712 ret = -EBUSY;
1718
- } else {
1719
- pr_info("%s: %#lx: unknown zero refcount page type %lx\n",
1720
- __func__, pfn, p->flags);
1713
+ } else if (!PageHuge(p) && !is_free_buddy_page(p)) {
1714
+ /* We raced with put_page, retry. */
1715
+ if (pass++ < 3)
1716
+ goto try_again;
17211717 ret = -EIO;
17221718 }
17231719 } else {
1724
- /* Not a free page */
1725
- ret = 1;
1726
- }
1727
- return ret;
1728
-}
1729
-
1730
-static int get_any_page(struct page *page, unsigned long pfn, int flags)
1731
-{
1732
- int ret = __get_any_page(page, pfn, flags);
1733
-
1734
- if (ret == -EBUSY)
1735
- ret = __get_any_page(page, pfn, flags);
1736
-
1737
- if (ret == 1 && !PageHuge(page) &&
1738
- !PageLRU(page) && !__PageMovable(page)) {
1739
- /*
1740
- * Try to free it.
1741
- */
1742
- put_page(page);
1743
- shake_page(page, 1);
1744
-
1745
- /*
1746
- * Did it turn free?
1747
- */
1748
- ret = __get_any_page(page, pfn, 0);
1749
- if (ret == 1 && !PageLRU(page)) {
1750
- /* Drop page reference which is from __get_any_page() */
1751
- put_page(page);
1752
- pr_info("soft_offline: %#lx: unknown non LRU page type %lx (%pGp)\n",
1753
- pfn, page->flags, &page->flags);
1754
- return -EIO;
1720
+ if (PageHuge(p) || PageLRU(p) || __PageMovable(p)) {
1721
+ ret = 1;
1722
+ } else {
1723
+ /*
1724
+ * A page we cannot handle. Check whether we can turn
1725
+ * it into something we can handle.
1726
+ */
1727
+ if (pass++ < 3) {
1728
+ put_page(p);
1729
+ shake_page(p, 1);
1730
+ count_increased = false;
1731
+ goto try_again;
1732
+ }
1733
+ put_page(p);
1734
+ ret = -EIO;
17551735 }
17561736 }
1737
+
17571738 return ret;
17581739 }
17591740
....@@ -1763,7 +1744,7 @@
17631744 bool lru = PageLRU(page);
17641745
17651746 if (PageHuge(page)) {
1766
- isolated = isolate_huge_page(page, pagelist);
1747
+ isolated = !isolate_hugetlb(page, pagelist);
17671748 } else {
17681749 if (lru)
17691750 isolated = !isolate_lru_page(page);
....@@ -1876,14 +1857,10 @@
18761857 return __soft_offline_page(page);
18771858 }
18781859
1879
-static int soft_offline_free_page(struct page *page)
1860
+static void put_ref_page(struct page *page)
18801861 {
1881
- int rc = 0;
1882
-
1883
- if (!page_handle_poison(page, true, false))
1884
- rc = -EBUSY;
1885
-
1886
- return rc;
1862
+ if (page)
1863
+ put_page(page);
18871864 }
18881865
18891866 /**
....@@ -1911,36 +1888,49 @@
19111888 int soft_offline_page(unsigned long pfn, int flags)
19121889 {
19131890 int ret;
1914
- struct page *page;
19151891 bool try_again = true;
1892
+ struct page *page, *ref_page = NULL;
1893
+
1894
+ WARN_ON_ONCE(!pfn_valid(pfn) && (flags & MF_COUNT_INCREASED));
19161895
19171896 if (!pfn_valid(pfn))
19181897 return -ENXIO;
1898
+ if (flags & MF_COUNT_INCREASED)
1899
+ ref_page = pfn_to_page(pfn);
1900
+
19191901 /* Only online pages can be soft-offlined (esp., not ZONE_DEVICE). */
19201902 page = pfn_to_online_page(pfn);
1921
- if (!page)
1903
+ if (!page) {
1904
+ put_ref_page(ref_page);
19221905 return -EIO;
1906
+ }
19231907
19241908 if (PageHWPoison(page)) {
1925
- pr_info("soft offline: %#lx page already poisoned\n", pfn);
1926
- if (flags & MF_COUNT_INCREASED)
1927
- put_page(page);
1909
+ pr_info("%s: %#lx page already poisoned\n", __func__, pfn);
1910
+ put_ref_page(ref_page);
19281911 return 0;
19291912 }
19301913
19311914 retry:
19321915 get_online_mems();
1933
- ret = get_any_page(page, pfn, flags);
1916
+ ret = get_any_page(page, flags);
19341917 put_online_mems();
19351918
1936
- if (ret > 0)
1919
+ if (ret > 0) {
19371920 ret = soft_offline_in_use_page(page);
1938
- else if (ret == 0)
1939
- if (soft_offline_free_page(page) && try_again) {
1940
- try_again = false;
1941
- flags &= ~MF_COUNT_INCREASED;
1942
- goto retry;
1921
+ } else if (ret == 0) {
1922
+ if (!page_handle_poison(page, true, false)) {
1923
+ if (try_again) {
1924
+ try_again = false;
1925
+ flags &= ~MF_COUNT_INCREASED;
1926
+ goto retry;
1927
+ }
1928
+ ret = -EBUSY;
19431929 }
1930
+ } else if (ret == -EIO) {
1931
+ pr_info("%s: %#lx: unknown page type: %lx (%pGp)\n",
1932
+ __func__, pfn, page->flags, &page->flags);
1933
+ }
19441934
19451935 return ret;
19461936 }