|
@@ -207,6 +207,32 @@ static long madvise_remove(struct vm_area_struct *vma,
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef CONFIG_MEMORY_FAILURE
|
|
|
|
+/*
|
|
|
|
+ * Error injection support for memory error handling.
|
|
|
|
+ */
|
|
|
|
+static int madvise_hwpoison(unsigned long start, unsigned long end)
|
|
|
|
+{
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
|
+ return -EPERM;
|
|
|
|
+ for (; start < end; start += PAGE_SIZE) {
|
|
|
|
+ struct page *p;
|
|
|
|
+ int ret = get_user_pages(current, current->mm, start, 1,
|
|
|
|
+ 0, 0, &p, NULL);
|
|
|
|
+ if (ret != 1)
|
|
|
|
+ return ret;
|
|
|
|
+ printk(KERN_INFO "Injecting memory failure for page %lx at %lx\n",
|
|
|
|
+ page_to_pfn(p), start);
|
|
|
|
+ /* Ignore return value for now */
|
|
|
|
+ __memory_failure(page_to_pfn(p), 0, 1);
|
|
|
|
+ put_page(p);
|
|
|
|
+ }
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
static long
|
|
static long
|
|
madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
|
|
madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
|
|
unsigned long start, unsigned long end, int behavior)
|
|
unsigned long start, unsigned long end, int behavior)
|
|
@@ -307,6 +333,10 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
|
|
int write;
|
|
int write;
|
|
size_t len;
|
|
size_t len;
|
|
|
|
|
|
|
|
+#ifdef CONFIG_MEMORY_FAILURE
|
|
|
|
+ if (behavior == MADV_HWPOISON)
|
|
|
|
+ return madvise_hwpoison(start, start+len_in);
|
|
|
|
+#endif
|
|
if (!madvise_behavior_valid(behavior))
|
|
if (!madvise_behavior_valid(behavior))
|
|
return error;
|
|
return error;
|
|
|
|
|