diff options
author | Nick Piggin <npiggin@suse.de> | 2007-05-06 17:49:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:12:51 -0400 |
commit | 6fe6900e1e5b6fa9e5c59aa5061f244fe3f467e2 (patch) | |
tree | 8bbfe5072279227cc50a941ad4813908082426a1 /mm | |
parent | 714b8171af9c930a59a0da8f6fe50518e70ab035 (diff) |
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>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 49 | ||||
-rw-r--r-- | mm/swapfile.c | 3 |
2 files changed, 38 insertions, 14 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 5dfc093ceb3d..070e7547d5b5 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1726,7 +1726,7 @@ int generic_file_readonly_mmap(struct file * file, struct vm_area_struct * vma) | |||
1726 | EXPORT_SYMBOL(generic_file_mmap); | 1726 | EXPORT_SYMBOL(generic_file_mmap); |
1727 | EXPORT_SYMBOL(generic_file_readonly_mmap); | 1727 | EXPORT_SYMBOL(generic_file_readonly_mmap); |
1728 | 1728 | ||
1729 | static inline struct page *__read_cache_page(struct address_space *mapping, | 1729 | static struct page *__read_cache_page(struct address_space *mapping, |
1730 | unsigned long index, | 1730 | unsigned long index, |
1731 | int (*filler)(void *,struct page*), | 1731 | int (*filler)(void *,struct page*), |
1732 | void *data) | 1732 | void *data) |
@@ -1763,17 +1763,11 @@ repeat: | |||
1763 | return page; | 1763 | return page; |
1764 | } | 1764 | } |
1765 | 1765 | ||
1766 | /** | 1766 | /* |
1767 | * read_cache_page - read into page cache, fill it if needed | 1767 | * Same as read_cache_page, but don't wait for page to become unlocked |
1768 | * @mapping: the page's address_space | 1768 | * after submitting it to the filler. |
1769 | * @index: the page index | ||
1770 | * @filler: function to perform the read | ||
1771 | * @data: destination for read data | ||
1772 | * | ||
1773 | * Read into the page cache. If a page already exists, | ||
1774 | * and PageUptodate() is not set, try to fill the page. | ||
1775 | */ | 1769 | */ |
1776 | struct page *read_cache_page(struct address_space *mapping, | 1770 | struct page *read_cache_page_async(struct address_space *mapping, |
1777 | unsigned long index, | 1771 | unsigned long index, |
1778 | int (*filler)(void *,struct page*), | 1772 | int (*filler)(void *,struct page*), |
1779 | void *data) | 1773 | void *data) |
@@ -1805,6 +1799,39 @@ retry: | |||
1805 | page = ERR_PTR(err); | 1799 | page = ERR_PTR(err); |
1806 | } | 1800 | } |
1807 | out: | 1801 | out: |
1802 | mark_page_accessed(page); | ||
1803 | return page; | ||
1804 | } | ||
1805 | EXPORT_SYMBOL(read_cache_page_async); | ||
1806 | |||
1807 | /** | ||
1808 | * read_cache_page - read into page cache, fill it if needed | ||
1809 | * @mapping: the page's address_space | ||
1810 | * @index: the page index | ||
1811 | * @filler: function to perform the read | ||
1812 | * @data: destination for read data | ||
1813 | * | ||
1814 | * Read into the page cache. If a page already exists, and PageUptodate() is | ||
1815 | * not set, try to fill the page then wait for it to become unlocked. | ||
1816 | * | ||
1817 | * If the page does not get brought uptodate, return -EIO. | ||
1818 | */ | ||
1819 | struct page *read_cache_page(struct address_space *mapping, | ||
1820 | unsigned long index, | ||
1821 | int (*filler)(void *,struct page*), | ||
1822 | void *data) | ||
1823 | { | ||
1824 | struct page *page; | ||
1825 | |||
1826 | page = read_cache_page_async(mapping, index, filler, data); | ||
1827 | if (IS_ERR(page)) | ||
1828 | goto out; | ||
1829 | wait_on_page_locked(page); | ||
1830 | if (!PageUptodate(page)) { | ||
1831 | page_cache_release(page); | ||
1832 | page = ERR_PTR(-EIO); | ||
1833 | } | ||
1834 | out: | ||
1808 | return page; | 1835 | return page; |
1809 | } | 1836 | } |
1810 | EXPORT_SYMBOL(read_cache_page); | 1837 | EXPORT_SYMBOL(read_cache_page); |
diff --git a/mm/swapfile.c b/mm/swapfile.c index a2d9bb4e80df..acc172cbe3aa 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -1531,9 +1531,6 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) | |||
1531 | error = PTR_ERR(page); | 1531 | error = PTR_ERR(page); |
1532 | goto bad_swap; | 1532 | goto bad_swap; |
1533 | } | 1533 | } |
1534 | wait_on_page_locked(page); | ||
1535 | if (!PageUptodate(page)) | ||
1536 | goto bad_swap; | ||
1537 | kmap(page); | 1534 | kmap(page); |
1538 | swap_header = page_address(page); | 1535 | swap_header = page_address(page); |
1539 | 1536 | ||