diff options
author | Hugh Dickins <hugh@veritas.com> | 2005-10-29 21:16:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-30 00:40:42 -0400 |
commit | 92dc6fcc845d99e87d8168e0786796525832d130 (patch) | |
tree | ac36da7e3dc3e0ba62d4139443beb7eb7c25288d /include/asm-parisc/cacheflush.h | |
parent | 69b0475456ff7ef520e16f69d7a15c0d68b74e64 (diff) |
[PATCH] mm: parisc pte atomicity
There's a worrying function translation_exists in parisc cacheflush.h,
unaffected by split ptlock since flush_dcache_page is using it on some other
mm, without any relevant lock. Oh well, make it a slightly more robust by
factoring the pfn check within it. And it looked liable to confuse a
camouflaged swap or file entry with a good pte: fix that too.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include/asm-parisc/cacheflush.h')
-rw-r--r-- | include/asm-parisc/cacheflush.h | 35 |
1 files changed, 19 insertions, 16 deletions
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h index aa592d8c0e39..1bc3c83ee74b 100644 --- a/include/asm-parisc/cacheflush.h +++ b/include/asm-parisc/cacheflush.h | |||
@@ -100,30 +100,34 @@ static inline void flush_cache_range(struct vm_area_struct *vma, | |||
100 | 100 | ||
101 | /* Simple function to work out if we have an existing address translation | 101 | /* Simple function to work out if we have an existing address translation |
102 | * for a user space vma. */ | 102 | * for a user space vma. */ |
103 | static inline pte_t *__translation_exists(struct mm_struct *mm, | 103 | static inline int translation_exists(struct vm_area_struct *vma, |
104 | unsigned long addr) | 104 | unsigned long addr, unsigned long pfn) |
105 | { | 105 | { |
106 | pgd_t *pgd = pgd_offset(mm, addr); | 106 | pgd_t *pgd = pgd_offset(vma->vm_mm, addr); |
107 | pmd_t *pmd; | 107 | pmd_t *pmd; |
108 | pte_t *pte; | 108 | pte_t pte; |
109 | 109 | ||
110 | if(pgd_none(*pgd)) | 110 | if(pgd_none(*pgd)) |
111 | return NULL; | 111 | return 0; |
112 | 112 | ||
113 | pmd = pmd_offset(pgd, addr); | 113 | pmd = pmd_offset(pgd, addr); |
114 | if(pmd_none(*pmd) || pmd_bad(*pmd)) | 114 | if(pmd_none(*pmd) || pmd_bad(*pmd)) |
115 | return NULL; | 115 | return 0; |
116 | 116 | ||
117 | pte = pte_offset_map(pmd, addr); | 117 | /* We cannot take the pte lock here: flush_cache_page is usually |
118 | * called with pte lock already held. Whereas flush_dcache_page | ||
119 | * takes flush_dcache_mmap_lock, which is lower in the hierarchy: | ||
120 | * the vma itself is secure, but the pte might come or go racily. | ||
121 | */ | ||
122 | pte = *pte_offset_map(pmd, addr); | ||
123 | /* But pte_unmap() does nothing on this architecture */ | ||
118 | 124 | ||
119 | /* The PA flush mappings show up as pte_none, but they're | 125 | /* Filter out coincidental file entries and swap entries */ |
120 | * valid none the less */ | 126 | if (!(pte_val(pte) & (_PAGE_FLUSH|_PAGE_PRESENT))) |
121 | if(pte_none(*pte) && ((pte_val(*pte) & _PAGE_FLUSH) == 0)) | 127 | return 0; |
122 | return NULL; | ||
123 | return pte; | ||
124 | } | ||
125 | #define translation_exists(vma, addr) __translation_exists((vma)->vm_mm, addr) | ||
126 | 128 | ||
129 | return pte_pfn(pte) == pfn; | ||
130 | } | ||
127 | 131 | ||
128 | /* Private function to flush a page from the cache of a non-current | 132 | /* Private function to flush a page from the cache of a non-current |
129 | * process. cr25 contains the Page Directory of the current user | 133 | * process. cr25 contains the Page Directory of the current user |
@@ -175,9 +179,8 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long | |||
175 | { | 179 | { |
176 | BUG_ON(!vma->vm_mm->context); | 180 | BUG_ON(!vma->vm_mm->context); |
177 | 181 | ||
178 | if(likely(translation_exists(vma, vmaddr))) | 182 | if (likely(translation_exists(vma, vmaddr, pfn))) |
179 | __flush_cache_page(vma, vmaddr); | 183 | __flush_cache_page(vma, vmaddr); |
180 | 184 | ||
181 | } | 185 | } |
182 | #endif | 186 | #endif |
183 | |||