mm: make read_cache_page synchronous

Ensure pages are uptodate after returning from read_cache_page, which allows
us to cut out most of the filesystem-internal PageUptodate calls.

I didn't have a great look down the call chains, but this appears to fixes 7
possible use-before uptodate in hfs, 2 in hfsplus, 1 in jfs, a few in
ecryptfs, 1 in jffs2, and a possible cleared data overwritten with readpage in
block2mtd.  All depending on whether the filler is async and/or can return
with a !uptodate page.

Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Nick Piggin
2007-05-06 14:49:04 -07:00
committed by Linus Torvalds
parent 714b8171af
commit 6fe6900e1e
24 changed files with 71 additions and 146 deletions

View File

@@ -1726,7 +1726,7 @@ int generic_file_readonly_mmap(struct file * file, struct vm_area_struct * vma)
EXPORT_SYMBOL(generic_file_mmap);
EXPORT_SYMBOL(generic_file_readonly_mmap);
static inline struct page *__read_cache_page(struct address_space *mapping,
static struct page *__read_cache_page(struct address_space *mapping,
unsigned long index,
int (*filler)(void *,struct page*),
void *data)
@@ -1763,17 +1763,11 @@ repeat:
return page;
}
/**
* read_cache_page - read into page cache, fill it if needed
* @mapping: the page's address_space
* @index: the page index
* @filler: function to perform the read
* @data: destination for read data
*
* Read into the page cache. If a page already exists,
* and PageUptodate() is not set, try to fill the page.
/*
* Same as read_cache_page, but don't wait for page to become unlocked
* after submitting it to the filler.
*/
struct page *read_cache_page(struct address_space *mapping,
struct page *read_cache_page_async(struct address_space *mapping,
unsigned long index,
int (*filler)(void *,struct page*),
void *data)
@@ -1804,6 +1798,39 @@ retry:
page_cache_release(page);
page = ERR_PTR(err);
}
out:
mark_page_accessed(page);
return page;
}
EXPORT_SYMBOL(read_cache_page_async);
/**
* read_cache_page - read into page cache, fill it if needed
* @mapping: the page's address_space
* @index: the page index
* @filler: function to perform the read
* @data: destination for read data
*
* Read into the page cache. If a page already exists, and PageUptodate() is
* not set, try to fill the page then wait for it to become unlocked.
*
* If the page does not get brought uptodate, return -EIO.
*/
struct page *read_cache_page(struct address_space *mapping,
unsigned long index,
int (*filler)(void *,struct page*),
void *data)
{
struct page *page;
page = read_cache_page_async(mapping, index, filler, data);
if (IS_ERR(page))
goto out;
wait_on_page_locked(page);
if (!PageUptodate(page)) {
page_cache_release(page);
page = ERR_PTR(-EIO);
}
out:
return page;
}