aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2007-05-06 17:49:04 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:12:51 -0400
commit6fe6900e1e5b6fa9e5c59aa5061f244fe3f467e2 (patch)
tree8bbfe5072279227cc50a941ad4813908082426a1 /mm
parent714b8171af9c930a59a0da8f6fe50518e70ab035 (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.c49
-rw-r--r--mm/swapfile.c3
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)
1726EXPORT_SYMBOL(generic_file_mmap); 1726EXPORT_SYMBOL(generic_file_mmap);
1727EXPORT_SYMBOL(generic_file_readonly_mmap); 1727EXPORT_SYMBOL(generic_file_readonly_mmap);
1728 1728
1729static inline struct page *__read_cache_page(struct address_space *mapping, 1729static 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 */
1776struct page *read_cache_page(struct address_space *mapping, 1770struct 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}
1805EXPORT_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 */
1819struct 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}
1810EXPORT_SYMBOL(read_cache_page); 1837EXPORT_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