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 | |
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>
-rw-r--r-- | drivers/mtd/devices/block2mtd.c | 6 | ||||
-rw-r--r-- | fs/afs/dir.c | 3 | ||||
-rw-r--r-- | fs/afs/mntpt.c | 11 | ||||
-rw-r--r-- | fs/cramfs/inode.c | 3 | ||||
-rw-r--r-- | fs/ecryptfs/mmap.c | 11 | ||||
-rw-r--r-- | fs/ext2/dir.c | 3 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_subr.c | 3 | ||||
-rw-r--r-- | fs/minix/dir.c | 1 | ||||
-rw-r--r-- | fs/namei.c | 12 | ||||
-rw-r--r-- | fs/nfs/dir.c | 5 | ||||
-rw-r--r-- | fs/nfs/symlink.c | 6 | ||||
-rw-r--r-- | fs/ntfs/aops.h | 3 | ||||
-rw-r--r-- | fs/ntfs/attrib.c | 18 | ||||
-rw-r--r-- | fs/ntfs/file.c | 3 | ||||
-rw-r--r-- | fs/ntfs/super.c | 30 | ||||
-rw-r--r-- | fs/ocfs2/symlink.c | 7 | ||||
-rw-r--r-- | fs/partitions/check.c | 3 | ||||
-rw-r--r-- | fs/reiserfs/xattr.c | 4 | ||||
-rw-r--r-- | fs/sysv/dir.c | 10 | ||||
-rw-r--r-- | fs/ufs/dir.c | 6 | ||||
-rw-r--r-- | fs/ufs/util.c | 6 | ||||
-rw-r--r-- | include/linux/pagemap.h | 11 | ||||
-rw-r--r-- | mm/filemap.c | 49 | ||||
-rw-r--r-- | mm/swapfile.c | 3 |
24 files changed, 71 insertions, 146 deletions
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index ce47544dc120..fc4cc8ba9e29 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
@@ -40,13 +40,11 @@ struct block2mtd_dev { | |||
40 | static LIST_HEAD(blkmtd_device_list); | 40 | static LIST_HEAD(blkmtd_device_list); |
41 | 41 | ||
42 | 42 | ||
43 | static struct page* page_read(struct address_space *mapping, int index) | 43 | static struct page *page_read(struct address_space *mapping, int index) |
44 | { | 44 | { |
45 | filler_t *filler = (filler_t*)mapping->a_ops->readpage; | 45 | return read_mapping_page(mapping, index, NULL); |
46 | return read_cache_page(mapping, index, filler, NULL); | ||
47 | } | 46 | } |
48 | 47 | ||
49 | |||
50 | /* erase a specified part of the device */ | 48 | /* erase a specified part of the device */ |
51 | static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) | 49 | static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) |
52 | { | 50 | { |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index dac5b990c0cd..0c1e902f17a3 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -194,10 +194,7 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index, | |||
194 | 194 | ||
195 | page = read_mapping_page(dir->i_mapping, index, &file); | 195 | page = read_mapping_page(dir->i_mapping, index, &file); |
196 | if (!IS_ERR(page)) { | 196 | if (!IS_ERR(page)) { |
197 | wait_on_page_locked(page); | ||
198 | kmap(page); | 197 | kmap(page); |
199 | if (!PageUptodate(page)) | ||
200 | goto fail; | ||
201 | if (!PageChecked(page)) | 198 | if (!PageChecked(page)) |
202 | afs_dir_check_page(dir, page); | 199 | afs_dir_check_page(dir, page); |
203 | if (PageError(page)) | 200 | if (PageError(page)) |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index b905ae37f912..034fcfd4e330 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
@@ -68,13 +68,11 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) | |||
68 | } | 68 | } |
69 | 69 | ||
70 | ret = -EIO; | 70 | ret = -EIO; |
71 | wait_on_page_locked(page); | ||
72 | buf = kmap(page); | ||
73 | if (!PageUptodate(page)) | ||
74 | goto out_free; | ||
75 | if (PageError(page)) | 71 | if (PageError(page)) |
76 | goto out_free; | 72 | goto out_free; |
77 | 73 | ||
74 | buf = kmap(page); | ||
75 | |||
78 | /* examine the symlink's contents */ | 76 | /* examine the symlink's contents */ |
79 | size = vnode->status.size; | 77 | size = vnode->status.size; |
80 | _debug("symlink to %*.*s", (int) size, (int) size, buf); | 78 | _debug("symlink to %*.*s", (int) size, (int) size, buf); |
@@ -91,8 +89,8 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) | |||
91 | 89 | ||
92 | ret = 0; | 90 | ret = 0; |
93 | 91 | ||
94 | out_free: | ||
95 | kunmap(page); | 92 | kunmap(page); |
93 | out_free: | ||
96 | page_cache_release(page); | 94 | page_cache_release(page); |
97 | out: | 95 | out: |
98 | _leave(" = %d", ret); | 96 | _leave(" = %d", ret); |
@@ -171,8 +169,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
171 | } | 169 | } |
172 | 170 | ||
173 | ret = -EIO; | 171 | ret = -EIO; |
174 | wait_on_page_locked(page); | 172 | if (PageError(page)) |
175 | if (!PageUptodate(page) || PageError(page)) | ||
176 | goto error; | 173 | goto error; |
177 | 174 | ||
178 | buf = kmap(page); | 175 | buf = kmap(page); |
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index facd0c89be8f..3d194a2be3f5 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c | |||
@@ -180,7 +180,8 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i | |||
180 | struct page *page = NULL; | 180 | struct page *page = NULL; |
181 | 181 | ||
182 | if (blocknr + i < devsize) { | 182 | if (blocknr + i < devsize) { |
183 | page = read_mapping_page(mapping, blocknr + i, NULL); | 183 | page = read_mapping_page_async(mapping, blocknr + i, |
184 | NULL); | ||
184 | /* synchronous error? */ | 185 | /* synchronous error? */ |
185 | if (IS_ERR(page)) | 186 | if (IS_ERR(page)) |
186 | page = NULL; | 187 | page = NULL; |
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index b731b09499cb..0770c4b66f53 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c | |||
@@ -46,7 +46,6 @@ struct kmem_cache *ecryptfs_lower_page_cache; | |||
46 | */ | 46 | */ |
47 | static struct page *ecryptfs_get1page(struct file *file, int index) | 47 | static struct page *ecryptfs_get1page(struct file *file, int index) |
48 | { | 48 | { |
49 | struct page *page; | ||
50 | struct dentry *dentry; | 49 | struct dentry *dentry; |
51 | struct inode *inode; | 50 | struct inode *inode; |
52 | struct address_space *mapping; | 51 | struct address_space *mapping; |
@@ -54,14 +53,7 @@ static struct page *ecryptfs_get1page(struct file *file, int index) | |||
54 | dentry = file->f_path.dentry; | 53 | dentry = file->f_path.dentry; |
55 | inode = dentry->d_inode; | 54 | inode = dentry->d_inode; |
56 | mapping = inode->i_mapping; | 55 | mapping = inode->i_mapping; |
57 | page = read_cache_page(mapping, index, | 56 | return read_mapping_page(mapping, index, (void *)file); |
58 | (filler_t *)mapping->a_ops->readpage, | ||
59 | (void *)file); | ||
60 | if (IS_ERR(page)) | ||
61 | goto out; | ||
62 | wait_on_page_locked(page); | ||
63 | out: | ||
64 | return page; | ||
65 | } | 57 | } |
66 | 58 | ||
67 | static | 59 | static |
@@ -233,7 +225,6 @@ int ecryptfs_do_readpage(struct file *file, struct page *page, | |||
233 | ecryptfs_printk(KERN_ERR, "Error reading from page cache\n"); | 225 | ecryptfs_printk(KERN_ERR, "Error reading from page cache\n"); |
234 | goto out; | 226 | goto out; |
235 | } | 227 | } |
236 | wait_on_page_locked(lower_page); | ||
237 | page_data = kmap_atomic(page, KM_USER0); | 228 | page_data = kmap_atomic(page, KM_USER0); |
238 | lower_page_data = kmap_atomic(lower_page, KM_USER1); | 229 | lower_page_data = kmap_atomic(lower_page, KM_USER1); |
239 | memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE); | 230 | memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE); |
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index e89bfc8cf957..1d1e7e30d70e 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c | |||
@@ -161,10 +161,7 @@ static struct page * ext2_get_page(struct inode *dir, unsigned long n) | |||
161 | struct address_space *mapping = dir->i_mapping; | 161 | struct address_space *mapping = dir->i_mapping; |
162 | struct page *page = read_mapping_page(mapping, n, NULL); | 162 | struct page *page = read_mapping_page(mapping, n, NULL); |
163 | if (!IS_ERR(page)) { | 163 | if (!IS_ERR(page)) { |
164 | wait_on_page_locked(page); | ||
165 | kmap(page); | 164 | kmap(page); |
166 | if (!PageUptodate(page)) | ||
167 | goto fail; | ||
168 | if (!PageChecked(page)) | 165 | if (!PageChecked(page)) |
169 | ext2_check_page(page); | 166 | ext2_check_page(page); |
170 | if (PageError(page)) | 167 | if (PageError(page)) |
diff --git a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c index decac62efe57..ed8f0b0dd880 100644 --- a/fs/freevxfs/vxfs_subr.c +++ b/fs/freevxfs/vxfs_subr.c | |||
@@ -74,10 +74,7 @@ vxfs_get_page(struct address_space *mapping, u_long n) | |||
74 | pp = read_mapping_page(mapping, n, NULL); | 74 | pp = read_mapping_page(mapping, n, NULL); |
75 | 75 | ||
76 | if (!IS_ERR(pp)) { | 76 | if (!IS_ERR(pp)) { |
77 | wait_on_page_locked(pp); | ||
78 | kmap(pp); | 77 | kmap(pp); |
79 | if (!PageUptodate(pp)) | ||
80 | goto fail; | ||
81 | /** if (!PageChecked(pp)) **/ | 78 | /** if (!PageChecked(pp)) **/ |
82 | /** vxfs_check_page(pp); **/ | 79 | /** vxfs_check_page(pp); **/ |
83 | if (PageError(pp)) | 80 | if (PageError(pp)) |
diff --git a/fs/minix/dir.c b/fs/minix/dir.c index cb4cb571fddf..e207cbe70951 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c | |||
@@ -65,7 +65,6 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n) | |||
65 | struct address_space *mapping = dir->i_mapping; | 65 | struct address_space *mapping = dir->i_mapping; |
66 | struct page *page = read_mapping_page(mapping, n, NULL); | 66 | struct page *page = read_mapping_page(mapping, n, NULL); |
67 | if (!IS_ERR(page)) { | 67 | if (!IS_ERR(page)) { |
68 | wait_on_page_locked(page); | ||
69 | kmap(page); | 68 | kmap(page); |
70 | if (!PageUptodate(page)) | 69 | if (!PageUptodate(page)) |
71 | goto fail; | 70 | goto fail; |
diff --git a/fs/namei.c b/fs/namei.c index 880052cadbcd..94b2f60aec22 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2671,19 +2671,9 @@ static char *page_getlink(struct dentry * dentry, struct page **ppage) | |||
2671 | struct address_space *mapping = dentry->d_inode->i_mapping; | 2671 | struct address_space *mapping = dentry->d_inode->i_mapping; |
2672 | page = read_mapping_page(mapping, 0, NULL); | 2672 | page = read_mapping_page(mapping, 0, NULL); |
2673 | if (IS_ERR(page)) | 2673 | if (IS_ERR(page)) |
2674 | goto sync_fail; | 2674 | return (char*)page; |
2675 | wait_on_page_locked(page); | ||
2676 | if (!PageUptodate(page)) | ||
2677 | goto async_fail; | ||
2678 | *ppage = page; | 2675 | *ppage = page; |
2679 | return kmap(page); | 2676 | return kmap(page); |
2680 | |||
2681 | async_fail: | ||
2682 | page_cache_release(page); | ||
2683 | return ERR_PTR(-EIO); | ||
2684 | |||
2685 | sync_fail: | ||
2686 | return (char*)page; | ||
2687 | } | 2677 | } |
2688 | 2678 | ||
2689 | int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) | 2679 | int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e59fd31c9a22..625d8e5fb39d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -334,8 +334,6 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
334 | status = PTR_ERR(page); | 334 | status = PTR_ERR(page); |
335 | goto out; | 335 | goto out; |
336 | } | 336 | } |
337 | if (!PageUptodate(page)) | ||
338 | goto read_error; | ||
339 | 337 | ||
340 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ | 338 | /* NOTE: Someone else may have changed the READDIRPLUS flag */ |
341 | desc->page = page; | 339 | desc->page = page; |
@@ -349,9 +347,6 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc) | |||
349 | out: | 347 | out: |
350 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, status); | 348 | dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, status); |
351 | return status; | 349 | return status; |
352 | read_error: | ||
353 | page_cache_release(page); | ||
354 | return -EIO; | ||
355 | } | 350 | } |
356 | 351 | ||
357 | /* | 352 | /* |
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index f4a0548b9ce8..bc2821331c29 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c | |||
@@ -61,15 +61,9 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
61 | err = page; | 61 | err = page; |
62 | goto read_failed; | 62 | goto read_failed; |
63 | } | 63 | } |
64 | if (!PageUptodate(page)) { | ||
65 | err = ERR_PTR(-EIO); | ||
66 | goto getlink_read_error; | ||
67 | } | ||
68 | nd_set_link(nd, kmap(page)); | 64 | nd_set_link(nd, kmap(page)); |
69 | return page; | 65 | return page; |
70 | 66 | ||
71 | getlink_read_error: | ||
72 | page_cache_release(page); | ||
73 | read_failed: | 67 | read_failed: |
74 | nd_set_link(nd, err); | 68 | nd_set_link(nd, err); |
75 | return NULL; | 69 | return NULL; |
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h index 9393f4b1e298..caecc58f529c 100644 --- a/fs/ntfs/aops.h +++ b/fs/ntfs/aops.h | |||
@@ -89,9 +89,8 @@ static inline struct page *ntfs_map_page(struct address_space *mapping, | |||
89 | struct page *page = read_mapping_page(mapping, index, NULL); | 89 | struct page *page = read_mapping_page(mapping, index, NULL); |
90 | 90 | ||
91 | if (!IS_ERR(page)) { | 91 | if (!IS_ERR(page)) { |
92 | wait_on_page_locked(page); | ||
93 | kmap(page); | 92 | kmap(page); |
94 | if (PageUptodate(page) && !PageError(page)) | 93 | if (!PageError(page)) |
95 | return page; | 94 | return page; |
96 | ntfs_unmap_page(page); | 95 | ntfs_unmap_page(page); |
97 | return ERR_PTR(-EIO); | 96 | return ERR_PTR(-EIO); |
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 7659cc192995..1c08fefe487a 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -2532,14 +2532,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) | |||
2532 | page = read_mapping_page(mapping, idx, NULL); | 2532 | page = read_mapping_page(mapping, idx, NULL); |
2533 | if (IS_ERR(page)) { | 2533 | if (IS_ERR(page)) { |
2534 | ntfs_error(vol->sb, "Failed to read first partial " | 2534 | ntfs_error(vol->sb, "Failed to read first partial " |
2535 | "page (sync error, index 0x%lx).", idx); | 2535 | "page (error, index 0x%lx).", idx); |
2536 | return PTR_ERR(page); | ||
2537 | } | ||
2538 | wait_on_page_locked(page); | ||
2539 | if (unlikely(!PageUptodate(page))) { | ||
2540 | ntfs_error(vol->sb, "Failed to read first partial page " | ||
2541 | "(async error, index 0x%lx).", idx); | ||
2542 | page_cache_release(page); | ||
2543 | return PTR_ERR(page); | 2536 | return PTR_ERR(page); |
2544 | } | 2537 | } |
2545 | /* | 2538 | /* |
@@ -2602,14 +2595,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) | |||
2602 | page = read_mapping_page(mapping, idx, NULL); | 2595 | page = read_mapping_page(mapping, idx, NULL); |
2603 | if (IS_ERR(page)) { | 2596 | if (IS_ERR(page)) { |
2604 | ntfs_error(vol->sb, "Failed to read last partial page " | 2597 | ntfs_error(vol->sb, "Failed to read last partial page " |
2605 | "(sync error, index 0x%lx).", idx); | 2598 | "(error, index 0x%lx).", idx); |
2606 | return PTR_ERR(page); | ||
2607 | } | ||
2608 | wait_on_page_locked(page); | ||
2609 | if (unlikely(!PageUptodate(page))) { | ||
2610 | ntfs_error(vol->sb, "Failed to read last partial page " | ||
2611 | "(async error, index 0x%lx).", idx); | ||
2612 | page_cache_release(page); | ||
2613 | return PTR_ERR(page); | 2599 | return PTR_ERR(page); |
2614 | } | 2600 | } |
2615 | kaddr = kmap_atomic(page, KM_USER0); | 2601 | kaddr = kmap_atomic(page, KM_USER0); |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index d69c4595ccd0..dbbac5593106 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -236,8 +236,7 @@ do_non_resident_extend: | |||
236 | err = PTR_ERR(page); | 236 | err = PTR_ERR(page); |
237 | goto init_err_out; | 237 | goto init_err_out; |
238 | } | 238 | } |
239 | wait_on_page_locked(page); | 239 | if (unlikely(PageError(page))) { |
240 | if (unlikely(!PageUptodate(page) || PageError(page))) { | ||
241 | page_cache_release(page); | 240 | page_cache_release(page); |
242 | err = -EIO; | 241 | err = -EIO; |
243 | goto init_err_out; | 242 | goto init_err_out; |
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 1594c90b7164..2ddde534db0a 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
@@ -2471,7 +2471,6 @@ static s64 get_nr_free_clusters(ntfs_volume *vol) | |||
2471 | s64 nr_free = vol->nr_clusters; | 2471 | s64 nr_free = vol->nr_clusters; |
2472 | u32 *kaddr; | 2472 | u32 *kaddr; |
2473 | struct address_space *mapping = vol->lcnbmp_ino->i_mapping; | 2473 | struct address_space *mapping = vol->lcnbmp_ino->i_mapping; |
2474 | filler_t *readpage = (filler_t*)mapping->a_ops->readpage; | ||
2475 | struct page *page; | 2474 | struct page *page; |
2476 | pgoff_t index, max_index; | 2475 | pgoff_t index, max_index; |
2477 | 2476 | ||
@@ -2494,24 +2493,14 @@ static s64 get_nr_free_clusters(ntfs_volume *vol) | |||
2494 | * Read the page from page cache, getting it from backing store | 2493 | * Read the page from page cache, getting it from backing store |
2495 | * if necessary, and increment the use count. | 2494 | * if necessary, and increment the use count. |
2496 | */ | 2495 | */ |
2497 | page = read_cache_page(mapping, index, (filler_t*)readpage, | 2496 | page = read_mapping_page(mapping, index, NULL); |
2498 | NULL); | ||
2499 | /* Ignore pages which errored synchronously. */ | 2497 | /* Ignore pages which errored synchronously. */ |
2500 | if (IS_ERR(page)) { | 2498 | if (IS_ERR(page)) { |
2501 | ntfs_debug("Sync read_cache_page() error. Skipping " | 2499 | ntfs_debug("read_mapping_page() error. Skipping " |
2502 | "page (index 0x%lx).", index); | 2500 | "page (index 0x%lx).", index); |
2503 | nr_free -= PAGE_CACHE_SIZE * 8; | 2501 | nr_free -= PAGE_CACHE_SIZE * 8; |
2504 | continue; | 2502 | continue; |
2505 | } | 2503 | } |
2506 | wait_on_page_locked(page); | ||
2507 | /* Ignore pages which errored asynchronously. */ | ||
2508 | if (!PageUptodate(page)) { | ||
2509 | ntfs_debug("Async read_cache_page() error. Skipping " | ||
2510 | "page (index 0x%lx).", index); | ||
2511 | page_cache_release(page); | ||
2512 | nr_free -= PAGE_CACHE_SIZE * 8; | ||
2513 | continue; | ||
2514 | } | ||
2515 | kaddr = (u32*)kmap_atomic(page, KM_USER0); | 2504 | kaddr = (u32*)kmap_atomic(page, KM_USER0); |
2516 | /* | 2505 | /* |
2517 | * For each 4 bytes, subtract the number of set bits. If this | 2506 | * For each 4 bytes, subtract the number of set bits. If this |
@@ -2562,7 +2551,6 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol, | |||
2562 | { | 2551 | { |
2563 | u32 *kaddr; | 2552 | u32 *kaddr; |
2564 | struct address_space *mapping = vol->mftbmp_ino->i_mapping; | 2553 | struct address_space *mapping = vol->mftbmp_ino->i_mapping; |
2565 | filler_t *readpage = (filler_t*)mapping->a_ops->readpage; | ||
2566 | struct page *page; | 2554 | struct page *page; |
2567 | pgoff_t index; | 2555 | pgoff_t index; |
2568 | 2556 | ||
@@ -2576,21 +2564,11 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol, | |||
2576 | * Read the page from page cache, getting it from backing store | 2564 | * Read the page from page cache, getting it from backing store |
2577 | * if necessary, and increment the use count. | 2565 | * if necessary, and increment the use count. |
2578 | */ | 2566 | */ |
2579 | page = read_cache_page(mapping, index, (filler_t*)readpage, | 2567 | page = read_mapping_page(mapping, index, NULL); |
2580 | NULL); | ||
2581 | /* Ignore pages which errored synchronously. */ | 2568 | /* Ignore pages which errored synchronously. */ |
2582 | if (IS_ERR(page)) { | 2569 | if (IS_ERR(page)) { |
2583 | ntfs_debug("Sync read_cache_page() error. Skipping " | 2570 | ntfs_debug("read_mapping_page() error. Skipping " |
2584 | "page (index 0x%lx).", index); | ||
2585 | nr_free -= PAGE_CACHE_SIZE * 8; | ||
2586 | continue; | ||
2587 | } | ||
2588 | wait_on_page_locked(page); | ||
2589 | /* Ignore pages which errored asynchronously. */ | ||
2590 | if (!PageUptodate(page)) { | ||
2591 | ntfs_debug("Async read_cache_page() error. Skipping " | ||
2592 | "page (index 0x%lx).", index); | 2571 | "page (index 0x%lx).", index); |
2593 | page_cache_release(page); | ||
2594 | nr_free -= PAGE_CACHE_SIZE * 8; | 2572 | nr_free -= PAGE_CACHE_SIZE * 8; |
2595 | continue; | 2573 | continue; |
2596 | } | 2574 | } |
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index 40dc1a51f4a9..7134007ba22f 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c | |||
@@ -67,16 +67,9 @@ static char *ocfs2_page_getlink(struct dentry * dentry, | |||
67 | page = read_mapping_page(mapping, 0, NULL); | 67 | page = read_mapping_page(mapping, 0, NULL); |
68 | if (IS_ERR(page)) | 68 | if (IS_ERR(page)) |
69 | goto sync_fail; | 69 | goto sync_fail; |
70 | wait_on_page_locked(page); | ||
71 | if (!PageUptodate(page)) | ||
72 | goto async_fail; | ||
73 | *ppage = page; | 70 | *ppage = page; |
74 | return kmap(page); | 71 | return kmap(page); |
75 | 72 | ||
76 | async_fail: | ||
77 | page_cache_release(page); | ||
78 | return ERR_PTR(-EIO); | ||
79 | |||
80 | sync_fail: | 73 | sync_fail: |
81 | return (char*)page; | 74 | return (char*)page; |
82 | } | 75 | } |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index f01572fca02f..6b9dae3f0e6c 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -569,9 +569,6 @@ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) | |||
569 | page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), | 569 | page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)), |
570 | NULL); | 570 | NULL); |
571 | if (!IS_ERR(page)) { | 571 | if (!IS_ERR(page)) { |
572 | wait_on_page_locked(page); | ||
573 | if (!PageUptodate(page)) | ||
574 | goto fail; | ||
575 | if (PageError(page)) | 572 | if (PageError(page)) |
576 | goto fail; | 573 | goto fail; |
577 | p->v = page; | 574 | p->v = page; |
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 2cac56210e2b..bf6e58214538 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
@@ -410,11 +410,7 @@ static struct page *reiserfs_get_page(struct inode *dir, unsigned long n) | |||
410 | mapping_set_gfp_mask(mapping, GFP_NOFS); | 410 | mapping_set_gfp_mask(mapping, GFP_NOFS); |
411 | page = read_mapping_page(mapping, n, NULL); | 411 | page = read_mapping_page(mapping, n, NULL); |
412 | if (!IS_ERR(page)) { | 412 | if (!IS_ERR(page)) { |
413 | wait_on_page_locked(page); | ||
414 | kmap(page); | 413 | kmap(page); |
415 | if (!PageUptodate(page)) | ||
416 | goto fail; | ||
417 | |||
418 | if (PageError(page)) | 414 | if (PageError(page)) |
419 | goto fail; | 415 | goto fail; |
420 | } | 416 | } |
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index ebf7007fa161..e566b387fcf9 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c | |||
@@ -54,17 +54,9 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n) | |||
54 | { | 54 | { |
55 | struct address_space *mapping = dir->i_mapping; | 55 | struct address_space *mapping = dir->i_mapping; |
56 | struct page *page = read_mapping_page(mapping, n, NULL); | 56 | struct page *page = read_mapping_page(mapping, n, NULL); |
57 | if (!IS_ERR(page)) { | 57 | if (!IS_ERR(page)) |
58 | wait_on_page_locked(page); | ||
59 | kmap(page); | 58 | kmap(page); |
60 | if (!PageUptodate(page)) | ||
61 | goto fail; | ||
62 | } | ||
63 | return page; | 59 | return page; |
64 | |||
65 | fail: | ||
66 | dir_put_page(page); | ||
67 | return ERR_PTR(-EIO); | ||
68 | } | 60 | } |
69 | 61 | ||
70 | static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) | 62 | static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) |
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 4890ddf1518e..4fb8b2e077ee 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c | |||
@@ -180,13 +180,9 @@ fail: | |||
180 | static struct page *ufs_get_page(struct inode *dir, unsigned long n) | 180 | static struct page *ufs_get_page(struct inode *dir, unsigned long n) |
181 | { | 181 | { |
182 | struct address_space *mapping = dir->i_mapping; | 182 | struct address_space *mapping = dir->i_mapping; |
183 | struct page *page = read_cache_page(mapping, n, | 183 | struct page *page = read_mapping_page(mapping, n, NULL); |
184 | (filler_t*)mapping->a_ops->readpage, NULL); | ||
185 | if (!IS_ERR(page)) { | 184 | if (!IS_ERR(page)) { |
186 | wait_on_page_locked(page); | ||
187 | kmap(page); | 185 | kmap(page); |
188 | if (!PageUptodate(page)) | ||
189 | goto fail; | ||
190 | if (!PageChecked(page)) | 186 | if (!PageChecked(page)) |
191 | ufs_check_page(page); | 187 | ufs_check_page(page); |
192 | if (PageError(page)) | 188 | if (PageError(page)) |
diff --git a/fs/ufs/util.c b/fs/ufs/util.c index 17437574f79c..84357f1ff0ec 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c | |||
@@ -251,13 +251,11 @@ struct page *ufs_get_locked_page(struct address_space *mapping, | |||
251 | 251 | ||
252 | page = find_lock_page(mapping, index); | 252 | page = find_lock_page(mapping, index); |
253 | if (!page) { | 253 | if (!page) { |
254 | page = read_cache_page(mapping, index, | 254 | page = read_mapping_page(mapping, index, NULL); |
255 | (filler_t*)mapping->a_ops->readpage, | ||
256 | NULL); | ||
257 | 255 | ||
258 | if (IS_ERR(page)) { | 256 | if (IS_ERR(page)) { |
259 | printk(KERN_ERR "ufs_change_blocknr: " | 257 | printk(KERN_ERR "ufs_change_blocknr: " |
260 | "read_cache_page error: ino %lu, index: %lu\n", | 258 | "read_mapping_page error: ino %lu, index: %lu\n", |
261 | mapping->host->i_ino, index); | 259 | mapping->host->i_ino, index); |
262 | goto out; | 260 | goto out; |
263 | } | 261 | } |
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 7a8dcb82a699..b4def5e083ed 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h | |||
@@ -95,12 +95,23 @@ static inline struct page *grab_cache_page(struct address_space *mapping, unsign | |||
95 | 95 | ||
96 | extern struct page * grab_cache_page_nowait(struct address_space *mapping, | 96 | extern struct page * grab_cache_page_nowait(struct address_space *mapping, |
97 | unsigned long index); | 97 | unsigned long index); |
98 | extern struct page * read_cache_page_async(struct address_space *mapping, | ||
99 | unsigned long index, filler_t *filler, | ||
100 | void *data); | ||
98 | extern struct page * read_cache_page(struct address_space *mapping, | 101 | extern struct page * read_cache_page(struct address_space *mapping, |
99 | unsigned long index, filler_t *filler, | 102 | unsigned long index, filler_t *filler, |
100 | void *data); | 103 | void *data); |
101 | extern int read_cache_pages(struct address_space *mapping, | 104 | extern int read_cache_pages(struct address_space *mapping, |
102 | struct list_head *pages, filler_t *filler, void *data); | 105 | struct list_head *pages, filler_t *filler, void *data); |
103 | 106 | ||
107 | static inline struct page *read_mapping_page_async( | ||
108 | struct address_space *mapping, | ||
109 | unsigned long index, void *data) | ||
110 | { | ||
111 | filler_t *filler = (filler_t *)mapping->a_ops->readpage; | ||
112 | return read_cache_page_async(mapping, index, filler, data); | ||
113 | } | ||
114 | |||
104 | static inline struct page *read_mapping_page(struct address_space *mapping, | 115 | static inline struct page *read_mapping_page(struct address_space *mapping, |
105 | unsigned long index, void *data) | 116 | unsigned long index, void *data) |
106 | { | 117 | { |
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 | ||