Return-Path: Received: from localhost (bix [127.0.0.1]) by localhost.localdomain (8.12.10/8.12.10) with ESMTP id k5SKIKIY012863 for ; Wed, 28 Jun 2006 13:18:23 -0700 Received: from bix [127.0.0.1] by localhost with POP3 (fetchmail-6.2.0) for akpm@localhost (single-drop); Wed, 28 Jun 2006 13:18:23 -0700 (PDT) Received: from smtp.osdl.org (smtp.osdl.org [65.172.181.4]) by shell0.pdx.osdl.net (8.13.1/8.11.6) with ESMTP id k5SKHxm6026172; Wed, 28 Jun 2006 13:17:59 -0700 Received: from amsfep20-int.chello.nl (amsfep17-int.chello.nl [213.46.243.15]) by smtp.osdl.org (8.12.8/8.12.8) with ESMTP id k5SKHvnV007746; Wed, 28 Jun 2006 13:17:57 -0700 Received: from [192.168.0.32] (really [62.194.129.232]) by amsfep20-int.chello.nl (InterMail vM.6.01.04.04 201-2131-118-104-20050224) with ESMTP id <20060628201751.YDHF3918.amsfep20-int.chello.nl@[192.168.0.32]>; Wed, 28 Jun 2006 22:17:51 +0200 From: Peter Zijlstra To: linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: Hugh Dickins , Andrew Morton , David Howells , Peter Zijlstra , Christoph Lameter , Martin Bligh , Nick Piggin , Linus Torvalds Date: Wed, 28 Jun 2006 22:17:47 +0200 Message-Id: <20060628201747.8792.44812.sendpatchset@lappy> In-Reply-To: <20060628201702.8792.69638.sendpatchset@lappy> References: <20060628201702.8792.69638.sendpatchset@lappy> Subject: [PATCH 4/6] mm: optimize the new mprotect() code a bit Received-SPF: pass (domain of a.p.zijlstra@chello.nl designates 213.46.243.15 as permitted sender) X-MIMEDefang-Filter: osdl$Revision: 1.135 $ X-Scanned-By: MIMEDefang 2.36 X-Spam-Checker-Version: SpamAssassin 3.0.2 (2004-11-16) on bix X-Spam-Level: X-Spam-Status: No, score=-1.5 required=2.0 tests=AWL,BAYES_00, FORGED_RCVD_HELO autolearn=ham version=3.0.2 From: Peter Zijlstra mprotect() resets the page protections, which could result in extra write faults for those pages whose dirty state we track using write faults and are dirty already. Signed-off-by: Peter Zijlstra --- mm/mprotect.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) Index: linux-2.6-dirty/mm/mprotect.c =================================================================== --- linux-2.6-dirty.orig/mm/mprotect.c 2006-06-28 19:49:27.000000000 +0200 +++ linux-2.6-dirty/mm/mprotect.c 2006-06-28 20:03:51.000000000 +0200 @@ -27,7 +27,8 @@ #include static void change_pte_range(struct mm_struct *mm, pmd_t *pmd, - unsigned long addr, unsigned long end, pgprot_t newprot) + unsigned long addr, unsigned long end, pgprot_t newprot, + int dirty_accountable) { pte_t *pte, oldpte; spinlock_t *ptl; @@ -42,7 +43,14 @@ static void change_pte_range(struct mm_s * bits by wiping the pte and then setting the new pte * into place. */ - ptent = pte_modify(ptep_get_and_clear(mm, addr, pte), newprot); + ptent = ptep_get_and_clear(mm, addr, pte); + ptent = pte_modify(ptent, newprot); + /* + * Avoid taking write faults for pages we know to be + * dirty. + */ + if (dirty_accountable && pte_dirty(ptent)) + ptent = pte_mkwrite(ptent); set_pte_at(mm, addr, pte, ptent); lazy_mmu_prot_update(ptent); #ifdef CONFIG_MIGRATION @@ -66,7 +74,8 @@ static void change_pte_range(struct mm_s } static inline void change_pmd_range(struct mm_struct *mm, pud_t *pud, - unsigned long addr, unsigned long end, pgprot_t newprot) + unsigned long addr, unsigned long end, pgprot_t newprot, + int dirty_accountable) { pmd_t *pmd; unsigned long next; @@ -76,12 +85,13 @@ static inline void change_pmd_range(stru next = pmd_addr_end(addr, end); if (pmd_none_or_clear_bad(pmd)) continue; - change_pte_range(mm, pmd, addr, next, newprot); + change_pte_range(mm, pmd, addr, next, newprot, dirty_accountable); } while (pmd++, addr = next, addr != end); } static inline void change_pud_range(struct mm_struct *mm, pgd_t *pgd, - unsigned long addr, unsigned long end, pgprot_t newprot) + unsigned long addr, unsigned long end, pgprot_t newprot, + int dirty_accountable) { pud_t *pud; unsigned long next; @@ -91,12 +101,13 @@ static inline void change_pud_range(stru next = pud_addr_end(addr, end); if (pud_none_or_clear_bad(pud)) continue; - change_pmd_range(mm, pud, addr, next, newprot); + change_pmd_range(mm, pud, addr, next, newprot, dirty_accountable); } while (pud++, addr = next, addr != end); } static void change_protection(struct vm_area_struct *vma, - unsigned long addr, unsigned long end, pgprot_t newprot) + unsigned long addr, unsigned long end, pgprot_t newprot, + int dirty_accountable) { struct mm_struct *mm = vma->vm_mm; pgd_t *pgd; @@ -110,7 +121,7 @@ static void change_protection(struct vm_ next = pgd_addr_end(addr, end); if (pgd_none_or_clear_bad(pgd)) continue; - change_pud_range(mm, pgd, addr, next, newprot); + change_pud_range(mm, pgd, addr, next, newprot, dirty_accountable); } while (pgd++, addr = next, addr != end); flush_tlb_range(vma, start, end); } @@ -125,6 +136,7 @@ mprotect_fixup(struct vm_area_struct *vm unsigned long charged = 0; pgoff_t pgoff; int error; + int dirty_accountable = 0; if (newflags == oldflags) { *pprev = vma; @@ -181,14 +193,16 @@ success: vma->vm_flags = newflags; vma->vm_page_prot = protection_map[newflags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]; - if (vma_wants_writenotify(vma)) + if (vma_wants_writenotify(vma)) { vma->vm_page_prot = protection_map[newflags & (VM_READ|VM_WRITE|VM_EXEC)]; + dirty_accountable = 1; + } if (is_vm_hugetlb_page(vma)) hugetlb_change_protection(vma, start, end, vma->vm_page_prot); else - change_protection(vma, start, end, vma->vm_page_prot); + change_protection(vma, start, end, vma->vm_page_prot, dirty_accountable); vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); vm_stat_account(mm, newflags, vma->vm_file, nrpages); return 0;