Make sure we copy pages inserted with "vm_insert_page()" on fork
authorLinus Torvalds <torvalds@g5.osdl.org>
Fri, 16 Dec 2005 18:21:23 +0000 (10:21 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 16 Dec 2005 18:21:23 +0000 (10:21 -0800)
The logic that decides that a fork() might be able to avoid copying a VM
area when it can be re-created by page faults didn't know about the new
vm_insert_page() case.

Also make some things a bit more anal wrt VM_PFNMAP.

Pointed out by Hugh Dickins <hugh@veritas.com>

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
include/linux/mm.h
mm/memory.c
mm/mmap.c
mm/mremap.c

index e5677f4..a06a84d 100644 (file)
@@ -163,6 +163,7 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_HUGETLB     0x00400000      /* Huge TLB Page VM */
 #define VM_NONLINEAR   0x00800000      /* Is non-linear (remap_file_pages) */
 #define VM_MAPPED_COPY 0x01000000      /* T if mapped copy of data (nommu mmap) */
+#define VM_INSERTPAGE  0x02000000      /* The vma has had "vm_insert_page()" done on it */
 
 #ifndef VM_STACK_DEFAULT_FLAGS         /* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
index d22f78c..d8dde07 100644 (file)
@@ -574,7 +574,7 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
         * readonly mappings. The tradeoff is that copy_page_range is more
         * efficient than faulting.
         */
-       if (!(vma->vm_flags & (VM_HUGETLB|VM_NONLINEAR|VM_PFNMAP))) {
+       if (!(vma->vm_flags & (VM_HUGETLB|VM_NONLINEAR|VM_PFNMAP|VM_INSERTPAGE))) {
                if (!vma->anon_vma)
                        return 0;
        }
@@ -1228,6 +1228,7 @@ int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *
                return -EFAULT;
        if (!page_count(page))
                return -EINVAL;
+       vma->vm_flags |= VM_INSERTPAGE;
        return insert_page(vma->vm_mm, addr, page, vma->vm_page_prot);
 }
 EXPORT_SYMBOL(vm_insert_page);
index 11ca592..64ba4db 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -611,7 +611,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
  * If the vma has a ->close operation then the driver probably needs to release
  * per-vma resources, so we don't attempt to merge those.
  */
-#define VM_SPECIAL (VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED)
+#define VM_SPECIAL (VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED | VM_PFNMAP)
 
 static inline int is_mergeable_vma(struct vm_area_struct *vma,
                        struct file *file, unsigned long vm_flags)
index b535438..ddaeee9 100644 (file)
@@ -323,7 +323,7 @@ unsigned long do_mremap(unsigned long addr,
        /* We can't remap across vm area boundaries */
        if (old_len > vma->vm_end - addr)
                goto out;
-       if (vma->vm_flags & VM_DONTEXPAND) {
+       if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) {
                if (new_len > old_len)
                        goto out;
        }