[PATCH 26 of 31] madvise(MADV_HUGEPAGE)

Andrea Arcangeli
2010-01-25T17:29:52Z

Add madvise MADV_HUGEPAGE to mark regions that are important to be hugepage
backed. Return -EINVAL if the vma is not of an anonymous type, or the feature
isn't built into the kernel. Never silently return success.

Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
---

diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -101,6 +101,7 @@ extern int split_huge_page(struct page *
#endif

extern unsigned long vma_address(struct page *page, struct vm_area_struct *vma);
+extern int hugepage_madvise(unsigned long *vm_flags);
static inline int PageTransHuge(struct page *page)
{
VM_BUG_ON(PageTail(page));
@@ -119,6 +120,11 @@ static inline int split_huge_page(struct
#define wait_split_huge_page(__anon_vma, __pmd) \
do { } while (0)
#define PageTransHuge(page) 0
+static inline int hugepage_madvise(unsigned long *vm_flags)
+{
+ BUG_ON(0);
+ return 0;
+}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */

#endif /* _LINUX_HUGE_MM_H */
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -464,9 +464,11 @@ int do_huge_pmd_wp_page(struct mm_struct
put_page(new_page);
new_page = NULL;
}
- if (unlikely(!new_page))
- return do_huge_pmd_wp_page_fallback(mm, vma, address,
- pmd, orig_pmd, page, haddr);
+ if (unlikely(!new_page)) {
+ ret = do_huge_pmd_wp_page_fallback(mm, vma, address,
+ pmd, orig_pmd, page, haddr);
+ goto out;
+ }

copy_huge_page(new_page, page, haddr, vma, HPAGE_PMD_NR);
__SetPageUptodate(new_page);
@@ -496,6 +498,7 @@ int do_huge_pmd_wp_page(struct mm_struct
}
out_unlock:
spin_unlock(&mm->page_table_lock);
+out:
return ret;
}

@@ -846,3 +849,19 @@ out_unlock:
out:
return ret;
}
+
+int hugepage_madvise(unsigned long *vm_flags)
+{
+ /*
+ * Be somewhat over-protective like KSM for now!
+ */
+ if (*vm_flags & (VM_HUGEPAGE | VM_SHARED | VM_MAYSHARE |
+ VM_PFNMAP | VM_IO | VM_DONTEXPAND |
+ VM_RESERVED | VM_HUGETLB | VM_INSERTPAGE |
+ VM_MIXEDMAP | VM_SAO))
+ return -EINVAL;
+
+ *vm_flags |= VM_HUGEPAGE;
+
+ return 0;
+}
diff --git a/mm/madvise.c b/mm/madvise.c
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -71,6 +71,11 @@ static long madvise_behavior(struct vm_a
if (error)
goto out;
break;
+ case MADV_HUGEPAGE:
+ error = hugepage_madvise(&new_flags);
+ if (error)
+ goto out;
+ break;
}

if (new_flags == vma->vm_flags) {
@@ -283,6 +288,9 @@ madvise_behavior_valid(int behavior)
case MADV_MERGEABLE:
case MADV_UNMERGEABLE:
#endif
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ case MADV_HUGEPAGE:
+#endif
return 1;