]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] hugetlb mremap fix
authorAndrew Morton <akpm@digeo.com>
Thu, 6 Feb 2003 00:58:57 +0000 (16:58 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Thu, 6 Feb 2003 00:58:57 +0000 (16:58 -0800)
If you attempt to perform a relocating 4k-aligned mremap and the new address
for the map lands on top of a hugepage VMA, do_mremap() will attempt to
perform a 4k-aligned unmap inside the hugetlb VMA.  The hugetlb layer goes
BUG.

Fix that by trapping the poorly-aligned unmap attempt in do_munmap().
do_remap() will then fall through without having done anything to the place
where it tests for a hugetlb VMA.

It would be neater to perform these checks on entry to do_mremap(), but that
would incur another VMA lookup.

Also, if you attempt to perform a 4k-aligned and/or sized munmap() inside a
hugepage VMA the same BUG happens.  This patch fixes that too.

This all means that an mremap attempt against a hugetlb area will fail, but
only after having unmapped the source pages.  That's a bit messy, but
supporting hugetlb mremap doesn't seem worth it, and completely disallowing
it will add overhead to normal mremaps.

include/linux/hugetlb.h
mm/mmap.c

index b51d51d05190750b1d2baedbb1cf1db7516fe5bb..370411eaaba2028dd0fb72ebc641d10e6e6a40fd 100644 (file)
@@ -58,6 +58,10 @@ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
 #define follow_huge_pmd(mm, addr, pmd, write)  0
 #define pmd_huge(x)    0
 
+#ifndef HPAGE_MASK
+#define HPAGE_MASK     0               /* Keep the compiler happy */
+#endif
+
 #endif /* !CONFIG_HUGETLB_PAGE */
 
 #ifdef CONFIG_HUGETLBFS
index d3b14b17da38bfbd4563ea7083b82def758bb564..af3d4a272ad7ca054aa037d4f493e86f06fe1311 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1223,6 +1223,11 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
                return 0;
        /* we have  start < mpnt->vm_end  */
 
+       if (is_vm_hugetlb_page(mpnt)) {
+               if ((start & ~HPAGE_MASK) || (len & ~HPAGE_MASK))
+                       return -EINVAL;
+       }
+
        /* if it doesn't overlap, we have nothing.. */
        end = start + len;
        if (mpnt->vm_start >= end)