Allow arbitrary shared PFNMAP's
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 12 Dec 2005 03:46:02 +0000 (19:46 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 12 Dec 2005 03:46:02 +0000 (19:46 -0800)
A shared mapping doesn't cause COW-pages, so we don't need to worry
about the whole vm_pgoff logic to decide if a PFN-remapped page has
gone through COW or not.

This makes it possible to entirely avoid the special "partial remapping"
logic for the common case.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
mm/memory.c

index aa8af0e20269df2b59fe3d94e3833e470cce7de8..e65f8fc8ea672a26f4a054d474326e14f06822b8 100644 (file)
@@ -377,6 +377,8 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_
                unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT;
                if (pfn == vma->vm_pgoff + off)
                        return NULL;
+               if (vma->vm_flags & VM_SHARED)
+                       return NULL;
        }
 
        /*
@@ -1343,9 +1345,6 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
        struct mm_struct *mm = vma->vm_mm;
        int err;
 
-       if (addr != vma->vm_start || end != vma->vm_end)
-               return incomplete_pfn_remap(vma, addr, end, pfn, prot);
-
        /*
         * Physically remapped pages are special. Tell the
         * rest of the world about it:
@@ -1359,9 +1358,18 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
         *   VM_PFNMAP tells the core MM that the base pages are just
         *      raw PFN mappings, and do not have a "struct page" associated
         *      with them.
+        *
+        * There's a horrible special case to handle copy-on-write
+        * behaviour that some programs depend on. We mark the "original"
+        * un-COW'ed pages by matching them up with "vma->vm_pgoff".
         */
+       if (!(vma->vm_flags & VM_SHARED)) {
+               if (addr != vma->vm_start || end != vma->vm_end)
+                       return incomplete_pfn_remap(vma, addr, end, pfn, prot);
+               vma->vm_pgoff = pfn;
+       }
+
        vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-       vma->vm_pgoff = pfn;
 
        BUG_ON(addr >= end);
        pfn -= addr >> PAGE_SHIFT;