diff mbox series

[v2,01/10] mm: memory_hotplug: check hwpoisoned page firstly in do_migrate_range()

Message ID 20240425084028.3888403-2-wangkefeng.wang@huawei.com (mailing list archive)
State New
Headers show
Series mm: remove isolate_lru_page() and isolate_movable_page() | expand

Commit Message

Kefeng Wang April 25, 2024, 8:40 a.m. UTC
The commit b15c87263a69 ("hwpoison, memory_hotplug: allow hwpoisoned
pages to be offlined") don't handle the hugetlb pages, the dead loop
still occur if offline a hwpoison hugetlb, luckly, with commit
e591ef7d96d6 ("mm,hwpoison,hugetlb,memory_hotplug: hotremove memory
section with hwpoisoned hugepage"), the HPageMigratable of hugetlb
page will be clear, and the hwpoison hugetlb page will be skipped in
scan_movable_pages(), so the deed loop issue is fixed.

However if the HPageMigratable() check passed(without reference and lock),
the hugetlb page may be hwpoisoned, it won't cause issue since the
hwpoisoned page will be handled correctly in the next scan_movable_pages()
loop, it will be isolated in do_migrate_range() and but fails to migrated,

In order to avoid this isolation and unify all hwpoisoned page handling.
let's unconditionally check hwpoison firstly, and if it is a hwpoisoned
hugetlb page, try to unmap it as the catch all safety net like normal page
does, also add some warn when the folio is still mapped.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 mm/memory_hotplug.c | 62 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 48 insertions(+), 14 deletions(-)

Comments

kernel test robot April 27, 2024, 3:57 a.m. UTC | #1
Hi Kefeng,

kernel test robot noticed the following build warnings:

[auto build test WARNING on akpm-mm/mm-everything]

url:    https://github.com/intel-lab-lkp/linux/commits/Kefeng-Wang/mm-memory_hotplug-check-hwpoisoned-page-firstly-in-do_migrate_range/20240425-164317
base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link:    https://lore.kernel.org/r/20240425084028.3888403-2-wangkefeng.wang%40huawei.com
patch subject: [PATCH v2 01/10] mm: memory_hotplug: check hwpoisoned page firstly in do_migrate_range()
config: arm64-defconfig (https://download.01.org/0day-ci/archive/20240427/202404271110.2fxPtHNB-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240427/202404271110.2fxPtHNB-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202404271110.2fxPtHNB-lkp@intel.com/

All warnings (new ones prefixed by >>):

   mm/memory_hotplug.c: In function 'isolate_and_unmap_hwposion_folio':
   mm/memory_hotplug.c:1786:27: error: implicit declaration of function 'hugetlb_page_mapping_lock_write'; did you mean 'hugetlb_folio_mapping_lock_write'? [-Werror=implicit-function-declaration]
    1786 |                 mapping = hugetlb_page_mapping_lock_write(&folio->page);
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                           hugetlb_folio_mapping_lock_write
>> mm/memory_hotplug.c:1786:25: warning: assignment to 'struct address_space *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
    1786 |                 mapping = hugetlb_page_mapping_lock_write(&folio->page);
         |                         ^
   cc1: some warnings being treated as errors


vim +1786 mm/memory_hotplug.c

  1774	
  1775	static bool isolate_and_unmap_hwposion_folio(struct folio *folio)
  1776	{
  1777		if (WARN_ON(folio_test_lru(folio)))
  1778			folio_isolate_lru(folio);
  1779	
  1780		if (!folio_mapped(folio))
  1781			return true;
  1782	
  1783		if (folio_test_hugetlb(folio) && !folio_test_anon(folio)) {
  1784			struct address_space *mapping;
  1785	
> 1786			mapping = hugetlb_page_mapping_lock_write(&folio->page);
  1787			if (mapping) {
  1788				/*
  1789				 * In shared mappings, try_to_unmap could potentially
  1790				 * call huge_pmd_unshare.  Because of this, take
  1791				 * semaphore in write mode here and set TTU_RMAP_LOCKED
  1792				 * to let lower levels know we have taken the lock.
  1793				 */
  1794				try_to_unmap(folio, TTU_IGNORE_MLOCK | TTU_RMAP_LOCKED);
  1795				i_mmap_unlock_write(mapping);
  1796			}
  1797		} else {
  1798			try_to_unmap(folio, TTU_IGNORE_MLOCK);
  1799		}
  1800	
  1801		return folio_mapped(folio);
  1802	}
  1803
kernel test robot April 27, 2024, 5:40 a.m. UTC | #2
Hi Kefeng,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]

url:    https://github.com/intel-lab-lkp/linux/commits/Kefeng-Wang/mm-memory_hotplug-check-hwpoisoned-page-firstly-in-do_migrate_range/20240425-164317
base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link:    https://lore.kernel.org/r/20240425084028.3888403-2-wangkefeng.wang%40huawei.com
patch subject: [PATCH v2 01/10] mm: memory_hotplug: check hwpoisoned page firstly in do_migrate_range()
config: arm64-defconfig (https://download.01.org/0day-ci/archive/20240427/202404271311.KpDy4akD-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240427/202404271311.KpDy4akD-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202404271311.KpDy4akD-lkp@intel.com/

All errors (new ones prefixed by >>):

   mm/memory_hotplug.c: In function 'isolate_and_unmap_hwposion_folio':
>> mm/memory_hotplug.c:1786:27: error: implicit declaration of function 'hugetlb_page_mapping_lock_write'; did you mean 'hugetlb_folio_mapping_lock_write'? [-Werror=implicit-function-declaration]
    1786 |                 mapping = hugetlb_page_mapping_lock_write(&folio->page);
         |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |                           hugetlb_folio_mapping_lock_write
   mm/memory_hotplug.c:1786:25: warning: assignment to 'struct address_space *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
    1786 |                 mapping = hugetlb_page_mapping_lock_write(&folio->page);
         |                         ^
   cc1: some warnings being treated as errors


vim +1786 mm/memory_hotplug.c

  1774	
  1775	static bool isolate_and_unmap_hwposion_folio(struct folio *folio)
  1776	{
  1777		if (WARN_ON(folio_test_lru(folio)))
  1778			folio_isolate_lru(folio);
  1779	
  1780		if (!folio_mapped(folio))
  1781			return true;
  1782	
  1783		if (folio_test_hugetlb(folio) && !folio_test_anon(folio)) {
  1784			struct address_space *mapping;
  1785	
> 1786			mapping = hugetlb_page_mapping_lock_write(&folio->page);
  1787			if (mapping) {
  1788				/*
  1789				 * In shared mappings, try_to_unmap could potentially
  1790				 * call huge_pmd_unshare.  Because of this, take
  1791				 * semaphore in write mode here and set TTU_RMAP_LOCKED
  1792				 * to let lower levels know we have taken the lock.
  1793				 */
  1794				try_to_unmap(folio, TTU_IGNORE_MLOCK | TTU_RMAP_LOCKED);
  1795				i_mmap_unlock_write(mapping);
  1796			}
  1797		} else {
  1798			try_to_unmap(folio, TTU_IGNORE_MLOCK);
  1799		}
  1800	
  1801		return folio_mapped(folio);
  1802	}
  1803
kernel test robot April 27, 2024, 7:23 a.m. UTC | #3
Hi Kefeng,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]

url:    https://github.com/intel-lab-lkp/linux/commits/Kefeng-Wang/mm-memory_hotplug-check-hwpoisoned-page-firstly-in-do_migrate_range/20240425-164317
base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link:    https://lore.kernel.org/r/20240425084028.3888403-2-wangkefeng.wang%40huawei.com
patch subject: [PATCH v2 01/10] mm: memory_hotplug: check hwpoisoned page firstly in do_migrate_range()
config: s390-defconfig (https://download.01.org/0day-ci/archive/20240427/202404271547.obYnCedG-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 5ef5eb66fb428aaf61fb51b709f065c069c11242)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240427/202404271547.obYnCedG-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202404271547.obYnCedG-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from mm/memory_hotplug.c:9:
   In file included from include/linux/mm.h:2253:
   include/linux/vmstat.h:500:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     500 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     501 |                            item];
         |                            ~~~~
   include/linux/vmstat.h:507:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     507 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     508 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:514:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     514 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
   include/linux/vmstat.h:519:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     519 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     520 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:528:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     528 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     529 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   In file included from mm/memory_hotplug.c:30:
   include/linux/mm_inline.h:47:41: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
      47 |         __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages);
         |                                    ~~~~~~~~~~~ ^ ~~~
   include/linux/mm_inline.h:49:22: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
      49 |                                 NR_ZONE_LRU_BASE + lru, nr_pages);
         |                                 ~~~~~~~~~~~~~~~~ ^ ~~~
   In file included from mm/memory_hotplug.c:34:
   In file included from include/linux/memblock.h:13:
   In file included from arch/s390/include/asm/dma.h:5:
   In file included from include/linux/io.h:14:
   In file included from arch/s390/include/asm/io.h:78:
   include/asm-generic/io.h:548:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     548 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:561:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     561 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/big_endian.h:37:59: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x))
         |                                                           ^
   include/uapi/linux/swab.h:102:54: note: expanded from macro '__swab16'
     102 | #define __swab16(x) (__u16)__builtin_bswap16((__u16)(x))
         |                                                      ^
   In file included from mm/memory_hotplug.c:34:
   In file included from include/linux/memblock.h:13:
   In file included from arch/s390/include/asm/dma.h:5:
   In file included from include/linux/io.h:14:
   In file included from arch/s390/include/asm/io.h:78:
   include/asm-generic/io.h:574:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     574 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/big_endian.h:35:59: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x))
         |                                                           ^
   include/uapi/linux/swab.h:115:54: note: expanded from macro '__swab32'
     115 | #define __swab32(x) (__u32)__builtin_bswap32((__u32)(x))
         |                                                      ^
   In file included from mm/memory_hotplug.c:34:
   In file included from include/linux/memblock.h:13:
   In file included from arch/s390/include/asm/dma.h:5:
   In file included from include/linux/io.h:14:
   In file included from arch/s390/include/asm/io.h:78:
   include/asm-generic/io.h:585:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     585 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:595:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     595 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:605:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     605 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:693:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     693 |         readsb(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:701:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     701 |         readsw(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:709:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     709 |         readsl(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:718:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     718 |         writesb(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
   include/asm-generic/io.h:727:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     727 |         writesw(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
   include/asm-generic/io.h:736:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     736 |         writesl(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
>> mm/memory_hotplug.c:1786:13: error: call to undeclared function 'hugetlb_page_mapping_lock_write'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    1786 |                 mapping = hugetlb_page_mapping_lock_write(&folio->page);
         |                           ^
   mm/memory_hotplug.c:1786:13: note: did you mean 'hugetlb_folio_mapping_lock_write'?
   include/linux/hugetlb.h:181:23: note: 'hugetlb_folio_mapping_lock_write' declared here
     181 | struct address_space *hugetlb_folio_mapping_lock_write(struct folio *folio);
         |                       ^
>> mm/memory_hotplug.c:1786:11: error: incompatible integer to pointer conversion assigning to 'struct address_space *' from 'int' [-Wint-conversion]
    1786 |                 mapping = hugetlb_page_mapping_lock_write(&folio->page);
         |                         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   19 warnings and 2 errors generated.


vim +/hugetlb_page_mapping_lock_write +1786 mm/memory_hotplug.c

  1774	
  1775	static bool isolate_and_unmap_hwposion_folio(struct folio *folio)
  1776	{
  1777		if (WARN_ON(folio_test_lru(folio)))
  1778			folio_isolate_lru(folio);
  1779	
  1780		if (!folio_mapped(folio))
  1781			return true;
  1782	
  1783		if (folio_test_hugetlb(folio) && !folio_test_anon(folio)) {
  1784			struct address_space *mapping;
  1785	
> 1786			mapping = hugetlb_page_mapping_lock_write(&folio->page);
  1787			if (mapping) {
  1788				/*
  1789				 * In shared mappings, try_to_unmap could potentially
  1790				 * call huge_pmd_unshare.  Because of this, take
  1791				 * semaphore in write mode here and set TTU_RMAP_LOCKED
  1792				 * to let lower levels know we have taken the lock.
  1793				 */
  1794				try_to_unmap(folio, TTU_IGNORE_MLOCK | TTU_RMAP_LOCKED);
  1795				i_mmap_unlock_write(mapping);
  1796			}
  1797		} else {
  1798			try_to_unmap(folio, TTU_IGNORE_MLOCK);
  1799		}
  1800	
  1801		return folio_mapped(folio);
  1802	}
  1803
Kefeng Wang April 28, 2024, 12:49 a.m. UTC | #4
On 2024/4/27 11:57, kernel test robot wrote:
> Hi Kefeng,
> 
> kernel test robot noticed the following build warnings:
> 
> [auto build test WARNING on akpm-mm/mm-everything]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Kefeng-Wang/mm-memory_hotplug-check-hwpoisoned-page-firstly-in-do_migrate_range/20240425-164317
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
> patch link:    https://lore.kernel.org/r/20240425084028.3888403-2-wangkefeng.wang%40huawei.com
> patch subject: [PATCH v2 01/10] mm: memory_hotplug: check hwpoisoned page firstly in do_migrate_range()
> config: arm64-defconfig (https://download.01.org/0day-ci/archive/20240427/202404271110.2fxPtHNB-lkp@intel.com/config)
> compiler: aarch64-linux-gcc (GCC) 13.2.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240427/202404271110.2fxPtHNB-lkp@intel.com/reproduce)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202404271110.2fxPtHNB-lkp@intel.com/
> 
> All warnings (new ones prefixed by >>):
> 
>     mm/memory_hotplug.c: In function 'isolate_and_unmap_hwposion_folio':
>     mm/memory_hotplug.c:1786:27: error: implicit declaration of function 'hugetlb_page_mapping_lock_write'; did you mean 'hugetlb_folio_mapping_lock_write'? [-Werror=implicit-function-declaration]
>      1786 |                 mapping = hugetlb_page_mapping_lock_write(&folio->page);
>           |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>           |                           hugetlb_folio_mapping_lock_write
>>> mm/memory_hotplug.c:1786:25: warning: assignment to 'struct address_space *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
>      1786 |                 mapping = hugetlb_page_mapping_lock_write(&folio->page);
>           |                         ^
>     cc1: some warnings being treated as errors


The patch based on next-20240425, but from next-20240426 with
"mm: convert hugetlb_page_mapping_lock_write to folio", so it is easy to
fix by converting to hugetlb_folio_mapping_lock_write() api, but keep it
for a while, see if there are any new comments about this patchset.


Thanks.

> 
> 
> vim +1786 mm/memory_hotplug.c
> 
>    1774	
>    1775	static bool isolate_and_unmap_hwposion_folio(struct folio *folio)
>    1776	{
>    1777		if (WARN_ON(folio_test_lru(folio)))
>    1778			folio_isolate_lru(folio);
>    1779	
>    1780		if (!folio_mapped(folio))
>    1781			return true;
>    1782	
>    1783		if (folio_test_hugetlb(folio) && !folio_test_anon(folio)) {
>    1784			struct address_space *mapping;
>    1785	
>> 1786			mapping = hugetlb_page_mapping_lock_write(&folio->page);
>    1787			if (mapping) {
>    1788				/*
>    1789				 * In shared mappings, try_to_unmap could potentially
>    1790				 * call huge_pmd_unshare.  Because of this, take
>    1791				 * semaphore in write mode here and set TTU_RMAP_LOCKED
>    1792				 * to let lower levels know we have taken the lock.
>    1793				 */
>    1794				try_to_unmap(folio, TTU_IGNORE_MLOCK | TTU_RMAP_LOCKED);
>    1795				i_mmap_unlock_write(mapping);
>    1796			}
>    1797		} else {
>    1798			try_to_unmap(folio, TTU_IGNORE_MLOCK);
>    1799		}
>    1800	
>    1801		return folio_mapped(folio);
>    1802	}
>    1803	
>
diff mbox series

Patch

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 431b1f6753c0..1985caf73e5a 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1772,6 +1772,35 @@  static int scan_movable_pages(unsigned long start, unsigned long end,
 	return 0;
 }
 
+static bool isolate_and_unmap_hwposion_folio(struct folio *folio)
+{
+	if (WARN_ON(folio_test_lru(folio)))
+		folio_isolate_lru(folio);
+
+	if (!folio_mapped(folio))
+		return true;
+
+	if (folio_test_hugetlb(folio) && !folio_test_anon(folio)) {
+		struct address_space *mapping;
+
+		mapping = hugetlb_page_mapping_lock_write(&folio->page);
+		if (mapping) {
+			/*
+			 * In shared mappings, try_to_unmap could potentially
+			 * call huge_pmd_unshare.  Because of this, take
+			 * semaphore in write mode here and set TTU_RMAP_LOCKED
+			 * to let lower levels know we have taken the lock.
+			 */
+			try_to_unmap(folio, TTU_IGNORE_MLOCK | TTU_RMAP_LOCKED);
+			i_mmap_unlock_write(mapping);
+		}
+	} else {
+		try_to_unmap(folio, TTU_IGNORE_MLOCK);
+	}
+
+	return folio_mapped(folio);
+}
+
 static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 {
 	unsigned long pfn;
@@ -1790,28 +1819,33 @@  static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 		folio = page_folio(page);
 		head = &folio->page;
 
-		if (PageHuge(page)) {
-			pfn = page_to_pfn(head) + compound_nr(head) - 1;
-			isolate_hugetlb(folio, &source);
-			continue;
-		} else if (PageTransHuge(page))
-			pfn = page_to_pfn(head) + thp_nr_pages(page) - 1;
-
 		/*
 		 * HWPoison pages have elevated reference counts so the migration would
 		 * fail on them. It also doesn't make any sense to migrate them in the
 		 * first place. Still try to unmap such a page in case it is still mapped
-		 * (e.g. current hwpoison implementation doesn't unmap KSM pages but keep
-		 * the unmap as the catch all safety net).
+		 * (keep the unmap as the catch all safety net).
 		 */
-		if (PageHWPoison(page)) {
-			if (WARN_ON(folio_test_lru(folio)))
-				folio_isolate_lru(folio);
-			if (folio_mapped(folio))
-				try_to_unmap(folio, TTU_IGNORE_MLOCK);
+		if (unlikely(PageHWPoison(page))) {
+			folio = page_folio(page);
+			if (isolate_and_unmap_hwposion_folio(folio)) {
+				if (__ratelimit(&migrate_rs)) {
+					pr_warn("%#lx: failed to unmap hwpoison folio\n",
+						pfn);
+				}
+			}
+
+			if (folio_test_large(folio))
+				pfn = folio_pfn(folio) + folio_nr_pages(folio) - 1;
 			continue;
 		}
 
+		if (PageHuge(page)) {
+			pfn = page_to_pfn(head) + compound_nr(head) - 1;
+			isolate_hugetlb(folio, &source);
+			continue;
+		} else if (PageTransHuge(page))
+			pfn = page_to_pfn(head) + thp_nr_pages(page) - 1;
+
 		if (!get_page_unless_zero(page))
 			continue;
 		/*