
From: Hugh Dickins <hugh@veritas.com>

Test for pte_young before going to the costlier atomic test_and_clear, as
asm-generic does.  Test for pte_dirty before going to the costlier atomic
test_and_clear, as asm-generic does (I said before that I would not do so for
pte_dirty, but was missing the point: there is nothing atomic about deciding
to do nothing).  But I've not touched the rather different ppc and ppc64.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/include/asm-i386/pgtable.h   |   16 ++++++++++++++--
 25-akpm/include/asm-ia64/pgtable.h   |    4 ++++
 25-akpm/include/asm-parisc/pgtable.h |    4 ++++
 25-akpm/include/asm-x86_64/pgtable.h |   17 +++++++++++++++--
 4 files changed, 37 insertions(+), 4 deletions(-)

diff -puN include/asm-i386/pgtable.h~mm-pretest-pte_young-and-pte_dirty include/asm-i386/pgtable.h
--- 25/include/asm-i386/pgtable.h~mm-pretest-pte_young-and-pte_dirty	Wed Jun  2 15:12:32 2004
+++ 25-akpm/include/asm-i386/pgtable.h	Wed Jun  2 15:12:32 2004
@@ -220,8 +220,20 @@ static inline pte_t pte_mkdirty(pte_t pt
 static inline pte_t pte_mkyoung(pte_t pte)	{ (pte).pte_low |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ (pte).pte_low |= _PAGE_RW; return pte; }
 
-static inline  int ptep_test_and_clear_dirty(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); }
-static inline  int ptep_test_and_clear_young(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low); }
+static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+{
+	if (!pte_dirty(*ptep))
+		return 0;
+	return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low);
+}
+
+static inline int ptep_test_and_clear_young(pte_t *ptep)
+{
+	if (!pte_young(*ptep))
+		return 0;
+	return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
+}
+
 static inline void ptep_set_wrprotect(pte_t *ptep)		{ clear_bit(_PAGE_BIT_RW, &ptep->pte_low); }
 static inline void ptep_mkdirty(pte_t *ptep)			{ set_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); }
 
diff -puN include/asm-ia64/pgtable.h~mm-pretest-pte_young-and-pte_dirty include/asm-ia64/pgtable.h
--- 25/include/asm-ia64/pgtable.h~mm-pretest-pte_young-and-pte_dirty	Wed Jun  2 15:12:32 2004
+++ 25-akpm/include/asm-ia64/pgtable.h	Wed Jun  2 15:12:32 2004
@@ -346,6 +346,8 @@ static inline int
 ptep_test_and_clear_young (pte_t *ptep)
 {
 #ifdef CONFIG_SMP
+	if (!pte_young(*ptep))
+		return 0;
 	return test_and_clear_bit(_PAGE_A_BIT, ptep);
 #else
 	pte_t pte = *ptep;
@@ -360,6 +362,8 @@ static inline int
 ptep_test_and_clear_dirty (pte_t *ptep)
 {
 #ifdef CONFIG_SMP
+	if (!pte_dirty(*ptep))
+		return 0;
 	return test_and_clear_bit(_PAGE_D_BIT, ptep);
 #else
 	pte_t pte = *ptep;
diff -puN include/asm-parisc/pgtable.h~mm-pretest-pte_young-and-pte_dirty include/asm-parisc/pgtable.h
--- 25/include/asm-parisc/pgtable.h~mm-pretest-pte_young-and-pte_dirty	Wed Jun  2 15:12:32 2004
+++ 25-akpm/include/asm-parisc/pgtable.h	Wed Jun  2 15:12:32 2004
@@ -417,6 +417,8 @@ extern void update_mmu_cache(struct vm_a
 static inline int ptep_test_and_clear_young(pte_t *ptep)
 {
 #ifdef CONFIG_SMP
+	if (!pte_young(*ptep))
+		return 0;
 	return test_and_clear_bit(xlate_pabit(_PAGE_ACCESSED_BIT), ptep);
 #else
 	pte_t pte = *ptep;
@@ -430,6 +432,8 @@ static inline int ptep_test_and_clear_yo
 static inline int ptep_test_and_clear_dirty(pte_t *ptep)
 {
 #ifdef CONFIG_SMP
+	if (!pte_dirty(*ptep))
+		return 0;
 	return test_and_clear_bit(xlate_pabit(_PAGE_DIRTY_BIT), ptep);
 #else
 	pte_t pte = *ptep;
diff -puN include/asm-x86_64/pgtable.h~mm-pretest-pte_young-and-pte_dirty include/asm-x86_64/pgtable.h
--- 25/include/asm-x86_64/pgtable.h~mm-pretest-pte_young-and-pte_dirty	Wed Jun  2 15:12:32 2004
+++ 25-akpm/include/asm-x86_64/pgtable.h	Wed Jun  2 15:12:32 2004
@@ -262,8 +262,21 @@ extern inline pte_t pte_mkexec(pte_t pte
 extern inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
 extern inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
-static inline  int ptep_test_and_clear_dirty(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep); }
-static inline  int ptep_test_and_clear_young(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep); }
+
+static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+{
+	if (!pte_dirty(*ptep))
+		return 0;
+	return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
+}
+
+static inline int ptep_test_and_clear_young(pte_t *ptep)
+{
+	if (!pte_young(*ptep))
+		return 0;
+	return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
+}
+
 static inline void ptep_set_wrprotect(pte_t *ptep)		{ clear_bit(_PAGE_BIT_RW, ptep); }
 static inline void ptep_mkdirty(pte_t *ptep)			{ set_bit(_PAGE_BIT_DIRTY, ptep); }
 
_
