@@ -65,13 +65,31 @@ int sysctl_memory_failure_recovery __read_mostly = 1;
65
65
66
66
atomic_long_t num_poisoned_pages __read_mostly = ATOMIC_LONG_INIT (0 );
67
67
68
- static void page_handle_poison (struct page * page , bool release )
68
+ static bool page_handle_poison (struct page * page , bool hugepage_or_freepage , bool release )
69
69
{
70
+ if (hugepage_or_freepage ) {
71
+ /*
72
+ * Doing this check for free pages is also fine since dissolve_free_huge_page
73
+ * returns 0 for non-hugetlb pages as well.
74
+ */
75
+ if (dissolve_free_huge_page (page ) || !take_page_off_buddy (page ))
76
+ /*
77
+ * We could fail to take off the target page from buddy
78
+ * for example due to racy page allocaiton, but that's
79
+ * acceptable because soft-offlined page is not broken
80
+ * and if someone really want to use it, they should
81
+ * take it.
82
+ */
83
+ return false;
84
+ }
85
+
70
86
SetPageHWPoison (page );
71
87
if (release )
72
88
put_page (page );
73
89
page_ref_inc (page );
74
90
num_poisoned_pages_inc ();
91
+
92
+ return true;
75
93
}
76
94
77
95
#if defined(CONFIG_HWPOISON_INJECT ) || defined(CONFIG_HWPOISON_INJECT_MODULE )
@@ -1725,63 +1743,51 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags)
1725
1743
return ret ;
1726
1744
}
1727
1745
1728
- static int soft_offline_huge_page (struct page * page , int flags )
1746
+ static bool isolate_page (struct page * page , struct list_head * pagelist )
1729
1747
{
1730
- int ret ;
1731
- unsigned long pfn = page_to_pfn (page );
1732
- struct page * hpage = compound_head (page );
1733
- LIST_HEAD (pagelist );
1748
+ bool isolated = false;
1749
+ bool lru = PageLRU (page );
1734
1750
1735
- /*
1736
- * This double-check of PageHWPoison is to avoid the race with
1737
- * memory_failure(). See also comment in __soft_offline_page().
1738
- */
1739
- lock_page ( hpage );
1740
- if ( PageHWPoison ( hpage )) {
1741
- unlock_page ( hpage );
1742
- put_page ( hpage );
1743
- pr_info ( "soft offline: %#lx hugepage already poisoned\n" , pfn );
1744
- return - EBUSY ;
1751
+ if ( PageHuge ( page )) {
1752
+ isolated = isolate_huge_page ( page , pagelist );
1753
+ } else {
1754
+ if ( lru )
1755
+ isolated = ! isolate_lru_page ( page );
1756
+ else
1757
+ isolated = ! isolate_movable_page ( page , ISOLATE_UNEVICTABLE );
1758
+
1759
+ if ( isolated )
1760
+ list_add ( & page -> lru , pagelist ) ;
1745
1761
}
1746
- unlock_page (hpage );
1747
1762
1748
- ret = isolate_huge_page (hpage , & pagelist );
1763
+ if (isolated && lru )
1764
+ inc_node_page_state (page , NR_ISOLATED_ANON +
1765
+ page_is_file_lru (page ));
1766
+
1749
1767
/*
1750
- * get_any_page() and isolate_huge_page() takes a refcount each,
1751
- * so need to drop one here.
1768
+ * If we succeed to isolate the page, we grabbed another refcount on
1769
+ * the page, so we can safely drop the one we got from get_any_pages().
1770
+ * If we failed to isolate the page, it means that we cannot go further
1771
+ * and we will return an error, so drop the reference we got from
1772
+ * get_any_pages() as well.
1752
1773
*/
1753
- put_page (hpage );
1754
- if (!ret ) {
1755
- pr_info ("soft offline: %#lx hugepage failed to isolate\n" , pfn );
1756
- return - EBUSY ;
1757
- }
1758
-
1759
- ret = migrate_pages (& pagelist , new_page , NULL , MPOL_MF_MOVE_ALL ,
1760
- MIGRATE_SYNC , MR_MEMORY_FAILURE );
1761
- if (ret ) {
1762
- pr_info ("soft offline: %#lx: hugepage migration failed %d, type %lx (%pGp)\n" ,
1763
- pfn , ret , page -> flags , & page -> flags );
1764
- if (!list_empty (& pagelist ))
1765
- putback_movable_pages (& pagelist );
1766
- if (ret > 0 )
1767
- ret = - EIO ;
1768
- } else {
1769
- /*
1770
- * We set PG_hwpoison only when we were able to take the page
1771
- * off the buddy.
1772
- */
1773
- if (!dissolve_free_huge_page (page ) && take_page_off_buddy (page ))
1774
- page_handle_poison (page , false);
1775
- else
1776
- ret = - EBUSY ;
1777
- }
1778
- return ret ;
1774
+ put_page (page );
1775
+ return isolated ;
1779
1776
}
1780
1777
1781
- static int __soft_offline_page (struct page * page , int flags )
1778
+ /*
1779
+ * __soft_offline_page handles hugetlb-pages and non-hugetlb pages.
1780
+ * If the page is a non-dirty unmapped page-cache page, it simply invalidates.
1781
+ * If the page is mapped, it migrates the contents over.
1782
+ */
1783
+ static int __soft_offline_page (struct page * page )
1782
1784
{
1783
- int ret ;
1785
+ int ret = 0 ;
1784
1786
unsigned long pfn = page_to_pfn (page );
1787
+ struct page * hpage = compound_head (page );
1788
+ char const * msg_page [] = {"page" , "hugepage" };
1789
+ bool huge = PageHuge (page );
1790
+ LIST_HEAD (pagelist );
1785
1791
1786
1792
/*
1787
1793
* Check PageHWPoison again inside page lock because PageHWPoison
@@ -1790,98 +1796,74 @@ static int __soft_offline_page(struct page *page, int flags)
1790
1796
* so there's no race between soft_offline_page() and memory_failure().
1791
1797
*/
1792
1798
lock_page (page );
1793
- wait_on_page_writeback (page );
1799
+ if (!PageHuge (page ))
1800
+ wait_on_page_writeback (page );
1794
1801
if (PageHWPoison (page )) {
1795
1802
unlock_page (page );
1796
1803
put_page (page );
1797
1804
pr_info ("soft offline: %#lx page already poisoned\n" , pfn );
1798
1805
return - EBUSY ;
1799
1806
}
1800
- /*
1801
- * Try to invalidate first. This should work for
1802
- * non dirty unmapped page cache pages.
1803
- */
1804
- ret = invalidate_inode_page (page );
1807
+
1808
+ if (!PageHuge (page ))
1809
+ /*
1810
+ * Try to invalidate first. This should work for
1811
+ * non dirty unmapped page cache pages.
1812
+ */
1813
+ ret = invalidate_inode_page (page );
1805
1814
unlock_page (page );
1815
+
1806
1816
/*
1807
1817
* RED-PEN would be better to keep it isolated here, but we
1808
1818
* would need to fix isolation locking first.
1809
1819
*/
1810
- if (ret == 1 ) {
1820
+ if (ret ) {
1811
1821
pr_info ("soft_offline: %#lx: invalidated\n" , pfn );
1812
- page_handle_poison (page , true);
1822
+ page_handle_poison (page , false, true);
1813
1823
return 0 ;
1814
1824
}
1815
1825
1816
- /*
1817
- * Simple invalidation didn't work.
1818
- * Try to migrate to a new page instead. migrate.c
1819
- * handles a large number of cases for us.
1820
- */
1821
- if (PageLRU (page ))
1822
- ret = isolate_lru_page (page );
1823
- else
1824
- ret = isolate_movable_page (page , ISOLATE_UNEVICTABLE );
1825
- /*
1826
- * Drop page reference which is came from get_any_page()
1827
- * successful isolate_lru_page() already took another one.
1828
- */
1829
- put_page (page );
1830
- if (!ret ) {
1831
- LIST_HEAD (pagelist );
1832
- /*
1833
- * After isolated lru page, the PageLRU will be cleared,
1834
- * so use !__PageMovable instead for LRU page's mapping
1835
- * cannot have PAGE_MAPPING_MOVABLE.
1836
- */
1837
- if (!__PageMovable (page ))
1838
- inc_node_page_state (page , NR_ISOLATED_ANON +
1839
- page_is_file_lru (page ));
1840
- list_add (& page -> lru , & pagelist );
1826
+ if (isolate_page (hpage , & pagelist )) {
1841
1827
ret = migrate_pages (& pagelist , new_page , NULL , MPOL_MF_MOVE_ALL ,
1842
1828
MIGRATE_SYNC , MR_MEMORY_FAILURE );
1843
1829
if (!ret ) {
1844
- page_handle_poison (page , true);
1830
+ bool release = !huge ;
1831
+
1832
+ if (!page_handle_poison (page , huge , release ))
1833
+ ret = - EBUSY ;
1845
1834
} else {
1846
1835
if (!list_empty (& pagelist ))
1847
1836
putback_movable_pages (& pagelist );
1848
1837
1849
- pr_info ("soft offline: %#lx: migration failed %d, type %lx (%pGp)\n" ,
1850
- pfn , ret , page -> flags , & page -> flags );
1838
+ pr_info ("soft offline: %#lx: %s migration failed %d, type %lx (%pGp)\n" ,
1839
+ pfn , msg_page [ huge ], ret , page -> flags , & page -> flags );
1851
1840
if (ret > 0 )
1852
1841
ret = - EIO ;
1853
1842
}
1854
1843
} else {
1855
- pr_info ("soft offline: %#lx: isolation failed: %d, page count %d, type %lx (%pGp)\n" ,
1856
- pfn , ret , page_count (page ), page -> flags , & page -> flags );
1844
+ pr_info ("soft offline: %#lx: %s isolation failed: %d, page count %d, type %lx (%pGp)\n" ,
1845
+ pfn , msg_page [huge ], ret , page_count (page ), page -> flags , & page -> flags );
1846
+ ret = - EBUSY ;
1857
1847
}
1858
1848
return ret ;
1859
1849
}
1860
1850
1861
- static int soft_offline_in_use_page (struct page * page , int flags )
1851
+ static int soft_offline_in_use_page (struct page * page )
1862
1852
{
1863
- int ret ;
1864
1853
struct page * hpage = compound_head (page );
1865
1854
1866
1855
if (!PageHuge (page ) && PageTransHuge (hpage ))
1867
1856
if (try_to_split_thp_page (page , "soft offline" ) < 0 )
1868
1857
return - EBUSY ;
1869
-
1870
- if (PageHuge (page ))
1871
- ret = soft_offline_huge_page (page , flags );
1872
- else
1873
- ret = __soft_offline_page (page , flags );
1874
- return ret ;
1858
+ return __soft_offline_page (page );
1875
1859
}
1876
1860
1877
1861
static int soft_offline_free_page (struct page * page )
1878
1862
{
1879
- int rc = - EBUSY ;
1863
+ int rc = 0 ;
1880
1864
1881
- if (!dissolve_free_huge_page (page ) && take_page_off_buddy (page )) {
1882
- page_handle_poison (page , false);
1883
- rc = 0 ;
1884
- }
1865
+ if (!page_handle_poison (page , true, false))
1866
+ rc = - EBUSY ;
1885
1867
1886
1868
return rc ;
1887
1869
}
@@ -1932,7 +1914,7 @@ int soft_offline_page(unsigned long pfn, int flags)
1932
1914
put_online_mems ();
1933
1915
1934
1916
if (ret > 0 )
1935
- ret = soft_offline_in_use_page (page , flags );
1917
+ ret = soft_offline_in_use_page (page );
1936
1918
else if (ret == 0 )
1937
1919
ret = soft_offline_free_page (page );
1938
1920
0 commit comments