diff options
| author | Andrew Morton <akpm@osdl.org> | 2004-04-17 20:54:52 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-04-17 20:54:52 -0700 |
| commit | c4d92e6b147b133848e8d89a734efdd2c3302d14 (patch) | |
| tree | e314afe99ab66b3ddc53f08d02ad4ff096e4e3dd /include | |
| parent | 1896ae13fb37ccbd62aab739b4ee6ff2be9e21d9 (diff) | |
[PATCH] rmap: flush_dcache revisited
From: Hugh Dickins <hugh@veritas.com>
One of the callers of flush_dcache_page is do_generic_mapping_read, where
file is read without i_sem and without page lock: concurrent truncation may
at any moment remove page from cache, NULLing ->mapping, making
flush_dcache_page liable to oops. Put result of page_mapping in a local
variable and apply mapping_mapped to that (if we were to check for NULL
within mapping_mapped, it's unclear whether to say yes or no).
parisc and arm do have other locking unsafety in their i_mmap(_shared)
searching, but that's a larger issue to be dealt with down the line.
Diffstat (limited to 'include')
| -rw-r--r-- | include/asm-arm/cacheflush.h | 4 | ||||
| -rw-r--r-- | include/asm-parisc/cacheflush.h | 4 | ||||
| -rw-r--r-- | include/asm-sh/pgalloc.h | 7 |
3 files changed, 9 insertions, 6 deletions
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h index 9a950ec8de4d..0e053301c09f 100644 --- a/include/asm-arm/cacheflush.h +++ b/include/asm-arm/cacheflush.h @@ -295,7 +295,9 @@ extern void __flush_dcache_page(struct page *); static inline void flush_dcache_page(struct page *page) { - if (page_mapping(page) && !mapping_mapped(page->mapping)) + struct address_space *mapping = page_mapping(page); + + if (mapping && !mapping_mapped(mapping)) set_bit(PG_dcache_dirty, &page->flags); else __flush_dcache_page(page); diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h index 7a77986e3738..224b3e6a5dd7 100644 --- a/include/asm-parisc/cacheflush.h +++ b/include/asm-parisc/cacheflush.h @@ -69,7 +69,9 @@ extern void __flush_dcache_page(struct page *page); static inline void flush_dcache_page(struct page *page) { - if (page_mapping(page) && !mapping_mapped(page->mapping)) { + struct address_space *mapping = page_mapping(page); + + if (mapping && !mapping_mapped(mapping)) { set_bit(PG_dcache_dirty, &page->flags); } else { __flush_dcache_page(page); diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h index 4584c9e37a75..9b7038442cd6 100644 --- a/include/asm-sh/pgalloc.h +++ b/include/asm-sh/pgalloc.h @@ -97,12 +97,11 @@ static inline pte_t ptep_get_and_clear(pte_t *ptep) pte_clear(ptep); if (!pte_not_present(pte)) { - struct page *page; unsigned long pfn = pte_pfn(pte); if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (!page_mapping(page) || - !mapping_writably_mapped(page->mapping)) + struct page *page = pfn_to_page(pfn); + struct address_space *mapping = page_mapping(page); + if (!mapping || !mapping_writably_mapped(mapping)) __clear_bit(PG_mapped, &page->flags); } } |
