X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=mm%2Fmemory.c;h=a596c1172248e56b8fb220408548330ebd1de538;hb=d44ed4f86892e350f4b16a3489b7e7c1a9bb7ead;hp=81d7117aa58b65ec7f93cef8e212a337735ba440;hpb=f33ea7f404e592e4563b12101b7a4d17da6558d7;p=linux-2.6 diff --git a/mm/memory.c b/mm/memory.c index 81d7117aa5..a596c11722 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -498,6 +498,17 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm, unsigned long addr = vma->vm_start; unsigned long end = vma->vm_end; + /* + * Don't copy ptes where a page fault will fill them correctly. + * Fork becomes much lighter when there are big shared or private + * readonly mappings. The tradeoff is that copy_page_range is more + * efficient than faulting. + */ + if (!(vma->vm_flags & (VM_HUGETLB|VM_NONLINEAR|VM_RESERVED))) { + if (!vma->anon_vma) + return 0; + } + if (is_vm_hugetlb_page(vma)) return copy_hugetlb_page_range(dst_mm, src_mm, vma); @@ -949,6 +960,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, cond_resched_lock(&mm->page_table_lock); while (!(page = follow_page(mm, start, write_access))) { + int ret; + /* * Shortcut for anonymous pages. We don't want * to force the creation of pages tables for @@ -961,16 +974,18 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, break; } spin_unlock(&mm->page_table_lock); - switch (__handle_mm_fault(mm, vma, start, - write_access)) { - case VM_FAULT_WRITE: - /* - * do_wp_page has broken COW when - * necessary, even if maybe_mkwrite - * decided not to set pte_write - */ + ret = __handle_mm_fault(mm, vma, start, write_access); + + /* + * The VM_FAULT_WRITE bit tells us that do_wp_page has + * broken COW when necessary, even if maybe_mkwrite + * decided not to set pte_write. We can thus safely do + * subsequent page lookups as if they were reads. + */ + if (ret & VM_FAULT_WRITE) write_access = 0; - /* FALLTHRU */ + + switch (ret & ~VM_FAULT_WRITE) { case VM_FAULT_MINOR: tsk->min_flt++; break;