mm/hwpoison: introduce copy_mc_highpage
authorJiaqi Yan <jiaqiyan@google.com>
Wed, 29 Mar 2023 15:11:20 +0000 (08:11 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Tue, 18 Apr 2023 23:29:51 +0000 (16:29 -0700)
Similar to how copy_mc_user_highpage is implemented for copy_user_highpage
on #MC supported architecture, introduce the #MC handled version of
copy_highpage.

This helper has immediate usage when khugepaged wants to copy file-backed
memory pages and tolerate #MC.

Link: https://lkml.kernel.org/r/20230329151121.949896-3-jiaqiyan@google.com
Signed-off-by: Jiaqi Yan <jiaqiyan@google.com>
Reviewed-by: Yang Shi <shy828301@gmail.com>
Cc: David Stevens <stevensd@chromium.org>
Cc: Hugh Dickins <hughd@google.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: "Kirill A. Shutemov" <kirill@shutemov.name>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Naoya Horiguchi <naoya.horiguchi@nec.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Tong Tiangen <tongtiangen@huawei.com>
Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/highmem.h

index 9c7cdaa..4de1dbc 100644 (file)
@@ -315,7 +315,29 @@ static inline void copy_user_highpage(struct page *to, struct page *from,
 
 #endif
 
+#ifndef __HAVE_ARCH_COPY_HIGHPAGE
+
+static inline void copy_highpage(struct page *to, struct page *from)
+{
+       char *vfrom, *vto;
+
+       vfrom = kmap_local_page(from);
+       vto = kmap_local_page(to);
+       copy_page(vto, vfrom);
+       kmsan_copy_page_meta(to, from);
+       kunmap_local(vto);
+       kunmap_local(vfrom);
+}
+
+#endif
+
 #ifdef copy_mc_to_kernel
+/*
+ * If architecture supports machine check exception handling, define the
+ * #MC versions of copy_user_highpage and copy_highpage. They copy a memory
+ * page with #MC in source page (@from) handled, and return the number
+ * of bytes not copied if there was a #MC, otherwise 0 for success.
+ */
 static inline int copy_mc_user_highpage(struct page *to, struct page *from,
                                        unsigned long vaddr, struct vm_area_struct *vma)
 {
@@ -332,29 +354,35 @@ static inline int copy_mc_user_highpage(struct page *to, struct page *from,
 
        return ret;
 }
-#else
-static inline int copy_mc_user_highpage(struct page *to, struct page *from,
-                                       unsigned long vaddr, struct vm_area_struct *vma)
-{
-       copy_user_highpage(to, from, vaddr, vma);
-       return 0;
-}
-#endif
 
-#ifndef __HAVE_ARCH_COPY_HIGHPAGE
-
-static inline void copy_highpage(struct page *to, struct page *from)
+static inline int copy_mc_highpage(struct page *to, struct page *from)
 {
+       unsigned long ret;
        char *vfrom, *vto;
 
        vfrom = kmap_local_page(from);
        vto = kmap_local_page(to);
-       copy_page(vto, vfrom);
-       kmsan_copy_page_meta(to, from);
+       ret = copy_mc_to_kernel(vto, vfrom, PAGE_SIZE);
+       if (!ret)
+               kmsan_copy_page_meta(to, from);
        kunmap_local(vto);
        kunmap_local(vfrom);
+
+       return ret;
+}
+#else
+static inline int copy_mc_user_highpage(struct page *to, struct page *from,
+                                       unsigned long vaddr, struct vm_area_struct *vma)
+{
+       copy_user_highpage(to, from, vaddr, vma);
+       return 0;
 }
 
+static inline int copy_mc_highpage(struct page *to, struct page *from)
+{
+       copy_highpage(to, from);
+       return 0;
+}
 #endif
 
 static inline void memcpy_page(struct page *dst_page, size_t dst_off,