Commit 79ac6ba4 authored by David Gibson's avatar David Gibson Committed by Linus Torvalds

[PATCH] hugepage: Small fixes to hugepage clear/copy path

Move the loops used in mm/hugetlb.c to clear and copy hugepages to their
own functions for clarity.  As we do so, we add some checks of need_resched
- we are, after all copying megabytes of memory here.  We also add
might_sleep() accordingly.  We generally dropped locks around the clear and
copy, already but not everyone has PREEMPT enabled, so we should still be
checking explicitly.

For this to work, we need to remove the clear_huge_page() from
alloc_huge_page(), which is called with the page_table_lock held in the COW
path.  We move the clear_huge_page() to just after the alloc_huge_page() in
the hugepage no-page path.  In the COW path, the new page is about to be
copied over, so clearing it was just a waste of time anyway.  So as a side
effect we also fix the fact that we held the page_table_lock for far too
long in this path by calling alloc_huge_page() under it.

It causes no regressions on the libhugetlbfs testsuite (ppc64, POWER5).
Signed-off-by: default avatarDavid Gibson <dwg@au1.ibm.com>
Cc: William Lee Irwin III <wli@holomorphy.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 8f860591
...@@ -27,6 +27,29 @@ static struct list_head hugepage_freelists[MAX_NUMNODES]; ...@@ -27,6 +27,29 @@ static struct list_head hugepage_freelists[MAX_NUMNODES];
static unsigned int nr_huge_pages_node[MAX_NUMNODES]; static unsigned int nr_huge_pages_node[MAX_NUMNODES];
static unsigned int free_huge_pages_node[MAX_NUMNODES]; static unsigned int free_huge_pages_node[MAX_NUMNODES];
static void clear_huge_page(struct page *page, unsigned long addr)
{
int i;
might_sleep();
for (i = 0; i < (HPAGE_SIZE/PAGE_SIZE); i++) {
cond_resched();
clear_user_highpage(page + i, addr);
}
}
static void copy_huge_page(struct page *dst, struct page *src,
unsigned long addr)
{
int i;
might_sleep();
for (i = 0; i < HPAGE_SIZE/PAGE_SIZE; i++) {
cond_resched();
copy_user_highpage(dst + i, src + i, addr + i*PAGE_SIZE);
}
}
/* /*
* Protects updates to hugepage_freelists, nr_huge_pages, and free_huge_pages * Protects updates to hugepage_freelists, nr_huge_pages, and free_huge_pages
*/ */
...@@ -98,7 +121,6 @@ void free_huge_page(struct page *page) ...@@ -98,7 +121,6 @@ void free_huge_page(struct page *page)
struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr) struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr)
{ {
struct page *page; struct page *page;
int i;
spin_lock(&hugetlb_lock); spin_lock(&hugetlb_lock);
page = dequeue_huge_page(vma, addr); page = dequeue_huge_page(vma, addr);
...@@ -108,8 +130,6 @@ struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr) ...@@ -108,8 +130,6 @@ struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr)
} }
spin_unlock(&hugetlb_lock); spin_unlock(&hugetlb_lock);
set_page_refcounted(page); set_page_refcounted(page);
for (i = 0; i < (HPAGE_SIZE/PAGE_SIZE); ++i)
clear_user_highpage(&page[i], addr);
return page; return page;
} }
...@@ -367,7 +387,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -367,7 +387,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, pte_t *ptep, pte_t pte) unsigned long address, pte_t *ptep, pte_t pte)
{ {
struct page *old_page, *new_page; struct page *old_page, *new_page;
int i, avoidcopy; int avoidcopy;
old_page = pte_page(pte); old_page = pte_page(pte);
...@@ -388,9 +408,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -388,9 +408,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
} }
spin_unlock(&mm->page_table_lock); spin_unlock(&mm->page_table_lock);
for (i = 0; i < HPAGE_SIZE/PAGE_SIZE; i++) copy_huge_page(new_page, old_page, address);
copy_user_highpage(new_page + i, old_page + i,
address + i*PAGE_SIZE);
spin_lock(&mm->page_table_lock); spin_lock(&mm->page_table_lock);
ptep = huge_pte_offset(mm, address & HPAGE_MASK); ptep = huge_pte_offset(mm, address & HPAGE_MASK);
...@@ -435,6 +453,7 @@ int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -435,6 +453,7 @@ int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
ret = VM_FAULT_OOM; ret = VM_FAULT_OOM;
goto out; goto out;
} }
clear_huge_page(page, address);
if (vma->vm_flags & VM_SHARED) { if (vma->vm_flags & VM_SHARED) {
int err; int err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment