[PATCH 1/15] ptwalk: p?d_none_or_clear_bad

From: Hugh Dickins
Date: Wed Mar 09 2005 - 17:35:54 EST


Replace the repetitive p?d_none, p?d_bad, p?d_ERROR, p?d_clear clauses
by pgd_none_or_clear_bad, pud_none_or_clear_bad, pmd_none_or_clear_bad
inlines throughout common and i386 - avoids a sprinkling of "unlikely"s.

Tests inline, but unlikely error handling in mm/memory.c - so the ERROR
file and line won't tell much; but it comes too late anyway, and hardly
ever seen outside development.

Let mremap use them in get_one_pte_map, as it already did in _nested;
but leave follow_page and untouched_anonymous page just skipping _bad
as before - they don't have quite the same ownership of the mm.

Signed-off-by: Hugh Dickins <hugh@xxxxxxxxxxx>
---

arch/i386/kernel/vm86.c | 21 +--------
include/asm-generic/pgtable.h | 44 ++++++++++++++++++++
mm/memory.c | 89 +++++++++++++++---------------------------
mm/mprotect.c | 21 +--------
mm/mremap.c | 24 +++--------
mm/msync.c | 21 +--------
mm/swapfile.c | 21 +--------
mm/vmalloc.c | 21 +--------
8 files changed, 100 insertions(+), 162 deletions(-)

--- 2.6.11-bk5/arch/i386/kernel/vm86.c 2005-03-02 07:38:52.000000000 +0000
+++ ptwalk1/arch/i386/kernel/vm86.c 2005-03-09 01:35:49.000000000 +0000
@@ -145,29 +145,14 @@ static void mark_screen_rdonly(struct ta
preempt_disable();
spin_lock(&tsk->mm->page_table_lock);
pgd = pgd_offset(tsk->mm, 0xA0000);
- if (pgd_none(*pgd))
+ if (pgd_none_or_clear_bad(pgd))
goto out;
- if (pgd_bad(*pgd)) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
- goto out;
- }
pud = pud_offset(pgd, 0xA0000);
- if (pud_none(*pud))
- goto out;
- if (pud_bad(*pud)) {
- pud_ERROR(*pud);
- pud_clear(pud);
+ if (pud_none_or_clear_bad(pud))
goto out;
- }
pmd = pmd_offset(pud, 0xA0000);
- if (pmd_none(*pmd))
- goto out;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
+ if (pmd_none_or_clear_bad(pmd))
goto out;
- }
pte = mapped = pte_offset_map(pmd, 0xA0000);
for (i = 0; i < 32; i++) {
if (pte_present(*pte))
--- 2.6.11-bk5/include/asm-generic/pgtable.h 2005-03-09 01:12:48.000000000 +0000
+++ ptwalk1/include/asm-generic/pgtable.h 2005-03-09 01:35:49.000000000 +0000
@@ -135,4 +135,48 @@ static inline void ptep_set_wrprotect(st
#define pgd_offset_gate(mm, addr) pgd_offset(mm, addr)
#endif

+#ifndef __ASSEMBLY__
+/*
+ * When walking page tables, we usually want to skip any p?d_none entries;
+ * and any p?d_bad entries - reporting the error before resetting to none.
+ * Do the tests inline, but report and clear the bad entry in mm/memory.c.
+ */
+void pgd_clear_bad(pgd_t *);
+void pud_clear_bad(pud_t *);
+void pmd_clear_bad(pmd_t *);
+
+static inline int pgd_none_or_clear_bad(pgd_t *pgd)
+{
+ if (pgd_none(*pgd))
+ return 1;
+ if (unlikely(pgd_bad(*pgd))) {
+ pgd_clear_bad(pgd);
+ return 1;
+ }
+ return 0;
+}
+
+static inline int pud_none_or_clear_bad(pud_t *pud)
+{
+ if (pud_none(*pud))
+ return 1;
+ if (unlikely(pud_bad(*pud))) {
+ pud_clear_bad(pud);
+ return 1;
+ }
+ return 0;
+}
+
+static inline int pmd_none_or_clear_bad(pmd_t *pmd)
+{
+ if (pmd_none(*pmd))
+ return 1;
+ if (unlikely(pmd_bad(*pmd))) {
+ pmd_clear_bad(pmd);
+ return 1;
+ }
+ return 0;
+}
+#endif /* !__ASSEMBLY__ */
+
#endif /* _ASM_GENERIC_PGTABLE_H */
--- 2.6.11-bk5/mm/memory.c 2005-03-09 01:12:53.000000000 +0000
+++ ptwalk1/mm/memory.c 2005-03-09 01:35:49.000000000 +0000
@@ -83,6 +83,30 @@ EXPORT_SYMBOL(high_memory);
EXPORT_SYMBOL(vmalloc_earlyreserve);

/*
+ * If a p?d_bad entry is found while walking page tables, report
+ * the error, before resetting entry to p?d_none. Usually (but
+ * very seldom) called out from the p?d_none_or_clear_bad macros.
+ */
+
+void pgd_clear_bad(pgd_t *pgd)
+{
+ pgd_ERROR(*pgd);
+ pgd_clear(pgd);
+}
+
+void pud_clear_bad(pud_t *pud)
+{
+ pud_ERROR(*pud);
+ pud_clear(pud);
+}
+
+void pmd_clear_bad(pmd_t *pmd)
+{
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+}
+
+/*
* Note: this doesn't free the actual pages themselves. That
* has been handled earlier when unmapping all the memory regions.
*/
@@ -90,13 +114,8 @@ static inline void clear_pmd_range(struc
{
struct page *page;

- if (pmd_none(*pmd))
+ if (pmd_none_or_clear_bad(pmd))
return;
- if (unlikely(pmd_bad(*pmd))) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return;
- }
if (!((start | end) & ~PMD_MASK)) {
/* Only clear full, aligned ranges */
page = pmd_page(*pmd);
@@ -112,14 +131,8 @@ static inline void clear_pud_range(struc
unsigned long addr = start, next;
pmd_t *pmd, *__pmd;

- if (pud_none(*pud))
+ if (pud_none_or_clear_bad(pud))
return;
- if (unlikely(pud_bad(*pud))) {
- pud_ERROR(*pud);
- pud_clear(pud);
- return;
- }
-
pmd = __pmd = pmd_offset(pud, start);
do {
next = (addr + PMD_SIZE) & PMD_MASK;
@@ -144,14 +157,8 @@ static inline void clear_pgd_range(struc
unsigned long addr = start, next;
pud_t *pud, *__pud;

- if (pgd_none(*pgd))
+ if (pgd_none_or_clear_bad(pgd))
return;
- if (unlikely(pgd_bad(*pgd))) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
- return;
- }
-
pud = __pud = pud_offset(pgd, start);
do {
next = (addr + PUD_SIZE) & PUD_MASK;
@@ -374,13 +381,8 @@ static int copy_pmd_range(struct mm_stru
next = (addr + PMD_SIZE) & PMD_MASK;
if (next > end || next <= addr)
next = end;
- if (pmd_none(*src_pmd))
- continue;
- if (pmd_bad(*src_pmd)) {
- pmd_ERROR(*src_pmd);
- pmd_clear(src_pmd);
+ if (pmd_none_or_clear_bad(src_pmd))
continue;
- }
err = copy_pte_range(dst_mm, src_mm, dst_pmd, src_pmd,
vma, addr, next);
if (err)
@@ -406,13 +408,8 @@ static int copy_pud_range(struct mm_stru
next = (addr + PUD_SIZE) & PUD_MASK;
if (next > end || next <= addr)
next = end;
- if (pud_none(*src_pud))
- continue;
- if (pud_bad(*src_pud)) {
- pud_ERROR(*src_pud);
- pud_clear(src_pud);
+ if (pud_none_or_clear_bad(src_pud))
continue;
- }
err = copy_pmd_range(dst_mm, src_mm, dst_pud, src_pud,
vma, addr, next);
if (err)
@@ -441,13 +438,8 @@ int copy_page_range(struct mm_struct *ds
next = (addr + PGDIR_SIZE) & PGDIR_MASK;
if (next > end || next <= addr)
next = end;
- if (pgd_none(*src_pgd))
+ if (pgd_none_or_clear_bad(src_pgd))
goto next_pgd;
- if (pgd_bad(*src_pgd)) {
- pgd_ERROR(*src_pgd);
- pgd_clear(src_pgd);
- goto next_pgd;
- }
err = copy_pud_range(dst, src, dst_pgd, src_pgd,
vma, addr, next);
if (err)
@@ -469,13 +461,8 @@ static void zap_pte_range(struct mmu_gat
unsigned long offset;
pte_t *ptep;

- if (pmd_none(*pmd))
+ if (pmd_none_or_clear_bad(pmd))
return;
- if (unlikely(pmd_bad(*pmd))) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return;
- }
ptep = pte_offset_map(pmd, address);
offset = address & ~PMD_MASK;
if (offset + size > PMD_SIZE)
@@ -553,13 +540,8 @@ static void zap_pmd_range(struct mmu_gat
pmd_t * pmd;
unsigned long end;

- if (pud_none(*pud))
- return;
- if (unlikely(pud_bad(*pud))) {
- pud_ERROR(*pud);
- pud_clear(pud);
+ if (pud_none_or_clear_bad(pud))
return;
- }
pmd = pmd_offset(pud, address);
end = address + size;
if (end > ((address + PUD_SIZE) & PUD_MASK))
@@ -577,13 +559,8 @@ static void zap_pud_range(struct mmu_gat
{
pud_t * pud;

- if (pgd_none(*pgd))
- return;
- if (unlikely(pgd_bad(*pgd))) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
+ if (pgd_none_or_clear_bad(pgd))
return;
- }
pud = pud_offset(pgd, address);
do {
zap_pmd_range(tlb, pud, address, end - address, details);
--- 2.6.11-bk5/mm/mprotect.c 2005-03-09 01:12:53.000000000 +0000
+++ ptwalk1/mm/mprotect.c 2005-03-09 01:35:49.000000000 +0000
@@ -32,13 +32,8 @@ change_pte_range(struct mm_struct *mm, p
pte_t * pte;
unsigned long base, end;

- if (pmd_none(*pmd))
+ if (pmd_none_or_clear_bad(pmd))
return;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return;
- }
pte = pte_offset_map(pmd, address);
base = address & PMD_MASK;
address &= ~PMD_MASK;
@@ -69,13 +64,8 @@ change_pmd_range(struct mm_struct *mm, p
pmd_t * pmd;
unsigned long base, end;

- if (pud_none(*pud))
- return;
- if (pud_bad(*pud)) {
- pud_ERROR(*pud);
- pud_clear(pud);
+ if (pud_none_or_clear_bad(pud))
return;
- }
pmd = pmd_offset(pud, address);
base = address & PUD_MASK;
address &= ~PUD_MASK;
@@ -96,13 +86,8 @@ change_pud_range(struct mm_struct *mm, p
pud_t * pud;
unsigned long base, end;

- if (pgd_none(*pgd))
- return;
- if (pgd_bad(*pgd)) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
+ if (pgd_none_or_clear_bad(pgd))
return;
- }
pud = pud_offset(pgd, address);
base = address & PGDIR_MASK;
address &= ~PGDIR_MASK;
--- 2.6.11-bk5/mm/mremap.c 2005-03-09 01:12:53.000000000 +0000
+++ ptwalk1/mm/mremap.c 2005-03-09 01:35:49.000000000 +0000
@@ -30,26 +30,16 @@ static pte_t *get_one_pte_map_nested(str
pte_t *pte = NULL;

pgd = pgd_offset(mm, addr);
- if (pgd_none(*pgd))
+ if (pgd_none_or_clear_bad(pgd))
goto end;

pud = pud_offset(pgd, addr);
- if (pud_none(*pud))
+ if (pud_none_or_clear_bad(pud))
goto end;
- if (pud_bad(*pud)) {
- pud_ERROR(*pud);
- pud_clear(pud);
- goto end;
- }

pmd = pmd_offset(pud, addr);
- if (pmd_none(*pmd))
- goto end;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
+ if (pmd_none_or_clear_bad(pmd))
goto end;
- }

pte = pte_offset_map_nested(pmd, addr);
if (pte_none(*pte)) {
@@ -67,15 +57,17 @@ static pte_t *get_one_pte_map(struct mm_
pmd_t *pmd;

pgd = pgd_offset(mm, addr);
- if (pgd_none(*pgd))
+ if (pgd_none_or_clear_bad(pgd))
return NULL;

pud = pud_offset(pgd, addr);
- if (pud_none(*pud))
+ if (pud_none_or_clear_bad(pud))
return NULL;
+
pmd = pmd_offset(pud, addr);
- if (!pmd_present(*pmd))
+ if (pmd_none_or_clear_bad(pmd))
return NULL;
+
return pte_offset_map(pmd, addr);
}

--- 2.6.11-bk5/mm/msync.c 2005-03-02 07:38:55.000000000 +0000
+++ ptwalk1/mm/msync.c 2005-03-09 01:35:49.000000000 +0000
@@ -45,13 +45,8 @@ static int filemap_sync_pte_range(pmd_t
pte_t *pte;
int error;

- if (pmd_none(*pmd))
+ if (pmd_none_or_clear_bad(pmd))
return 0;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return 0;
- }
pte = pte_offset_map(pmd, address);
if ((address & PMD_MASK) != (end & PMD_MASK))
end = (address & PMD_MASK) + PMD_SIZE;
@@ -74,13 +69,8 @@ static inline int filemap_sync_pmd_range
pmd_t * pmd;
int error;

- if (pud_none(*pud))
- return 0;
- if (pud_bad(*pud)) {
- pud_ERROR(*pud);
- pud_clear(pud);
+ if (pud_none_or_clear_bad(pud))
return 0;
- }
pmd = pmd_offset(pud, address);
if ((address & PUD_MASK) != (end & PUD_MASK))
end = (address & PUD_MASK) + PUD_SIZE;
@@ -100,13 +90,8 @@ static inline int filemap_sync_pud_range
pud_t *pud;
int error;

- if (pgd_none(*pgd))
- return 0;
- if (pgd_bad(*pgd)) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
+ if (pgd_none_or_clear_bad(pgd))
return 0;
- }
pud = pud_offset(pgd, address);
if ((address & PGDIR_MASK) != (end & PGDIR_MASK))
end = (address & PGDIR_MASK) + PGDIR_SIZE;
--- 2.6.11-bk5/mm/swapfile.c 2005-03-09 01:12:53.000000000 +0000
+++ ptwalk1/mm/swapfile.c 2005-03-09 01:35:49.000000000 +0000
@@ -441,13 +441,8 @@ static unsigned long unuse_pmd(struct vm
pte_t *pte;
pte_t swp_pte = swp_entry_to_pte(entry);

- if (pmd_none(*dir))
+ if (pmd_none_or_clear_bad(dir))
return 0;
- if (pmd_bad(*dir)) {
- pmd_ERROR(*dir);
- pmd_clear(dir);
- return 0;
- }
pte = pte_offset_map(dir, address);
do {
/*
@@ -483,13 +478,8 @@ static unsigned long unuse_pud(struct vm
unsigned long next;
unsigned long foundaddr;

- if (pud_none(*pud))
- return 0;
- if (pud_bad(*pud)) {
- pud_ERROR(*pud);
- pud_clear(pud);
+ if (pud_none_or_clear_bad(pud))
return 0;
- }
pmd = pmd_offset(pud, address);
do {
next = (address + PMD_SIZE) & PMD_MASK;
@@ -513,13 +503,8 @@ static unsigned long unuse_pgd(struct vm
unsigned long next;
unsigned long foundaddr;

- if (pgd_none(*pgd))
- return 0;
- if (pgd_bad(*pgd)) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
+ if (pgd_none_or_clear_bad(pgd))
return 0;
- }
pud = pud_offset(pgd, address);
do {
next = (address + PUD_SIZE) & PUD_MASK;
--- 2.6.11-bk5/mm/vmalloc.c 2005-03-09 01:12:53.000000000 +0000
+++ ptwalk1/mm/vmalloc.c 2005-03-09 01:35:49.000000000 +0000
@@ -29,13 +29,8 @@ static void unmap_area_pte(pmd_t *pmd, u
unsigned long base, end;
pte_t *pte;

- if (pmd_none(*pmd))
+ if (pmd_none_or_clear_bad(pmd))
return;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return;
- }

pte = pte_offset_kernel(pmd, address);
base = address & PMD_MASK;
@@ -63,13 +58,8 @@ static void unmap_area_pmd(pud_t *pud, u
unsigned long base, end;
pmd_t *pmd;

- if (pud_none(*pud))
- return;
- if (pud_bad(*pud)) {
- pud_ERROR(*pud);
- pud_clear(pud);
+ if (pud_none_or_clear_bad(pud))
return;
- }

pmd = pmd_offset(pud, address);
base = address & PUD_MASK;
@@ -91,13 +81,8 @@ static void unmap_area_pud(pgd_t *pgd, u
pud_t *pud;
unsigned long base, end;

- if (pgd_none(*pgd))
- return;
- if (pgd_bad(*pgd)) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
+ if (pgd_none_or_clear_bad(pgd))
return;
- }

pud = pud_offset(pgd, address);
base = address & PGDIR_MASK;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/