aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2004-07-28 08:58:01 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-07-28 08:58:01 -0700
commit5136181d5b8bbb2c94d163a6d3362bfea9fdd99d (patch)
tree76cb2ce062ca4010a369e06e0c4260b4eed1d72c /mm
parentddd443e4d88c6e39bc3a6d249a980ccc438544cb (diff)
downloadhistory-5136181d5b8bbb2c94d163a6d3362bfea9fdd99d.tar.gz
[PATCH] install_page vs. vmtruncate
BK is still missing one piece for Oleg's install_page/vmtruncate races. Oleg didn't explicitly ACK this, but I think he did implicitly: Oleg? The previous patch to install_page, returning an error if !page_mapping once page_table_lock is held, is not enough to guard against vmtruncate. When unmap_mapping_range already did this vma, but truncate_inode_pages has not yet done this page, page->mapping will still be set, but we must now refrain from inserting the page into the page table. Could check truncate_count, but that would need caller to read and pass it down. Instead, recheck page->index against i_size, which is updated before unmap_mapping_range. Better check page->mapping too: not really necessary, but it's accidental that index is left when mapping is reset. Also, callers are expecting -EINVAL for beyond end of file, not -EAGAIN. 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 'mm')
-rw-r--r--mm/fremap.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/mm/fremap.c b/mm/fremap.c
index f5c8b64ffb711f..dc64dd9dbe0bec 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -55,6 +55,8 @@ static inline void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, struct page *page, pgprot_t prot)
{
+ struct inode *inode;
+ pgoff_t size;
int err = -ENOMEM;
pte_t *pte;
pgd_t *pgd;
@@ -76,8 +78,10 @@ int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
* This page may have been truncated. Tell the
* caller about it.
*/
- err = -EAGAIN;
- if (!page_mapping(page))
+ err = -EINVAL;
+ inode = vma->vm_file->f_mapping->host;
+ size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (!page->mapping || page->index >= size)
goto err_unlock;
zap_pte(mm, vma, addr, pte);