mm: make __get_user_pages return -EHWPOISON for HWPOISON page optionally
authorHuang Ying <ying.huang@intel.com>
Sun, 30 Jan 2011 03:15:48 +0000 (11:15 +0800)
committerMarcelo Tosatti <mtosatti@redhat.com>
Thu, 17 Mar 2011 16:08:27 +0000 (13:08 -0300)
Make __get_user_pages return -EHWPOISON for HWPOISON page only if
FOLL_HWPOISON is specified.  With this patch, the interested callers
can distinguish HWPOISON pages from general FAULT pages, while other
callers will still get -EFAULT for all these pages, so the user space
interface need not to be changed.

This feature is needed by KVM, where UCR MCE should be relayed to
guest for HWPOISON page, while instruction emulation and MMIO will be
tried for general FAULT page.

The idea comes from Andrew Morton.

Signed-off-by: Huang Ying <ying.huang@intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/alpha/include/asm/errno.h
arch/mips/include/asm/errno.h
arch/parisc/include/asm/errno.h
arch/sparc/include/asm/errno.h
include/asm-generic/errno.h
include/linux/mm.h
mm/memory.c

index 98099bda937069958f4722715cb4cc16af4398e4..e5f29ca281800feb9f73237e458da4441bb19de4 100644 (file)
 
 #define        ERFKILL         138     /* Operation not possible due to RF-kill */
 
+#define EHWPOISON      139     /* Memory page has hardware error */
+
 #endif
index a0efc73819e4ae832f9b60dd351fb0fcfb37825c..6dcd3583ed042682f30520f27935a0a1c68bcc84 100644 (file)
 
 #define        ERFKILL         167     /* Operation not possible due to RF-kill */
 
+#define EHWPOISON      168     /* Memory page has hardware error */
+
 #define EDQUOT         1133    /* Quota exceeded */
 
 #ifdef __KERNEL__
index 9992abdd782da1fa2edc1ce9231273c93abcaaa5..135ad6047e51e0733347ef7a3cfda3dfe9b0a9f7 100644 (file)
 
 #define        ERFKILL         256     /* Operation not possible due to RF-kill */
 
+#define EHWPOISON      257     /* Memory page has hardware error */
+
 #endif
index 4e2bc490d71412aea2db9428604612143ce74003..c351aba997b7d377f4a1591e8abf0821b9540e51 100644 (file)
 
 #define        ERFKILL         134     /* Operation not possible due to RF-kill */
 
+#define EHWPOISON      135     /* Memory page has hardware error */
+
 #endif
index 28cc03bf19e6e2ed6f9372f6e331fb1a8803de5f..a1331ce5044584eb1266546ae9b79d1e87e26b16 100644 (file)
 
 #define ERFKILL                132     /* Operation not possible due to RF-kill */
 
+#define EHWPOISON      133     /* Memory page has hardware error */
+
 #endif
index 46150c66318e77802c5cd654355a4fa70c640df5..a77c82c56e055abf53aefc83ba9dd772b6579e03 100644 (file)
@@ -1532,6 +1532,7 @@ struct page *follow_page(struct vm_area_struct *, unsigned long address,
 #define FOLL_FORCE     0x10    /* get_user_pages read/write w/o permission */
 #define FOLL_MLOCK     0x40    /* mark page as mlocked */
 #define FOLL_SPLIT     0x80    /* don't return transhuge pages, split them */
+#define FOLL_HWPOISON  0x100   /* check page is hwpoisoned */
 
 typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
                        void *data);
index 806a37ec71bd595289eed44d810e9e1765da8f75..346ee7e041fd1cc9965af6e30d9371e6c5ac0af0 100644 (file)
@@ -1576,9 +1576,16 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                if (ret & VM_FAULT_ERROR) {
                                        if (ret & VM_FAULT_OOM)
                                                return i ? i : -ENOMEM;
-                                       if (ret &
-                                           (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE|
-                                            VM_FAULT_SIGBUS))
+                                       if (ret & (VM_FAULT_HWPOISON |
+                                                  VM_FAULT_HWPOISON_LARGE)) {
+                                               if (i)
+                                                       return i;
+                                               else if (gup_flags & FOLL_HWPOISON)
+                                                       return -EHWPOISON;
+                                               else
+                                                       return -EFAULT;
+                                       }
+                                       if (ret & VM_FAULT_SIGBUS)
                                                return i ? i : -EFAULT;
                                        BUG();
                                }