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:
committed by
Linus Torvalds
parent
714b8171af
commit
6fe6900e1e
49
mm/filemap.c
49
mm/filemap.c
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user