aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-06-02 18:01:46 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-06-02 18:01:46 -0700
commitdde27822586dd7a89c91c66d11878f8e19e6b823 (patch)
treebe9b2400e9bb5fddf8b496b8f5b81d030acd4d57 /mm
parent0af0d78880a6dc12c569931f1b8cb46a4dcecd59 (diff)
downloadhistory-dde27822586dd7a89c91c66d11878f8e19e6b823.tar.gz
[PATCH] hugetlbpage msync() fix
From: David Gibson <david@gibson.dropbear.id.au> Currently, calling msync() on a hugepage area will cause the kernel to blow up with a bad_page() (at least on ppc64, but I think the problem will exist on other archs too). The msync path attempts to walk pagetables which may not be there, or may have an unusual layout for hugepages. Lucikly we shouldn't need to do anything for an msync on hugetlbfs beyond flushing the cache, so this patch should be sufficient to fix the problem. Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/msync.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/mm/msync.c b/mm/msync.c
index 5467df544970a2..cd5e947dabf298 100644
--- a/mm/msync.c
+++ b/mm/msync.c
@@ -11,6 +11,7 @@
#include <linux/pagemap.h>
#include <linux/mm.h>
#include <linux/mman.h>
+#include <linux/hugetlb.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -106,6 +107,13 @@ static int filemap_sync(struct vm_area_struct * vma, unsigned long address,
dir = pgd_offset(vma->vm_mm, address);
flush_cache_range(vma, address, end);
+
+ /* For hugepages we can't go walking the page table normally,
+ * but that's ok, hugetlbfs is memory based, so we don't need
+ * to do anything more on an msync() */
+ if (is_vm_hugetlb_page(vma))
+ goto out;
+
if (address >= end)
BUG();
do {
@@ -118,7 +126,7 @@ static int filemap_sync(struct vm_area_struct * vma, unsigned long address,
* dirty bits.
*/
flush_tlb_range(vma, end - size, end);
-
+ out:
spin_unlock(&vma->vm_mm->page_table_lock);
return error;