summaryrefslogtreecommitdiffstats
path: root/fs/afs/dir.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-04-22 15:06:44 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2016-05-02 19:47:25 -0400
commitbe5b82dbfec2a900925da4437af3c60b61f4c53d (patch)
treea65508f3456f623f51215581e3b00529a9c20ee7 /fs/afs/dir.c
parentb9e1d435fdf4ae0b925070d44b65d608f2707688 (diff)
make ext2_get_page() and friends work without external serialization
Right now ext2_get_page() (and its analogues in a bunch of other filesystems) relies upon the directory being locked - the way it sets and tests Checked and Error bits would be racy without that. Switch to a slightly different scheme, _not_ setting Checked in case of failure. That way the logics becomes if Checked => OK else if Error => fail else if !validate => fail else => OK with validation setting Checked or Error on success and failure resp. and returning which one had happened. Equivalent to the current logics, but unlike the current logics not sensitive to the order of set_bit, test_bit getting reordered by CPU, etc. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/afs/dir.c')
-rw-r--r--fs/afs/dir.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 5fda2bc53cd7..cdf8fbbc0b57 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -128,7 +128,7 @@ struct afs_lookup_cookie {
128/* 128/*
129 * check that a directory page is valid 129 * check that a directory page is valid
130 */ 130 */
131static inline void afs_dir_check_page(struct inode *dir, struct page *page) 131static inline bool afs_dir_check_page(struct inode *dir, struct page *page)
132{ 132{
133 struct afs_dir_page *dbuf; 133 struct afs_dir_page *dbuf;
134 loff_t latter; 134 loff_t latter;
@@ -168,11 +168,11 @@ static inline void afs_dir_check_page(struct inode *dir, struct page *page)
168 } 168 }
169 169
170 SetPageChecked(page); 170 SetPageChecked(page);
171 return; 171 return true;
172 172
173error: 173error:
174 SetPageChecked(page);
175 SetPageError(page); 174 SetPageError(page);
175 return false;
176} 176}
177 177
178/* 178/*
@@ -196,10 +196,10 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
196 page = read_cache_page(dir->i_mapping, index, afs_page_filler, key); 196 page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
197 if (!IS_ERR(page)) { 197 if (!IS_ERR(page)) {
198 kmap(page); 198 kmap(page);
199 if (!PageChecked(page)) 199 if (unlikely(!PageChecked(page))) {
200 afs_dir_check_page(dir, page); 200 if (PageError(page) || !afs_dir_check_page(dir, page))
201 if (PageError(page)) 201 goto fail;
202 goto fail; 202 }
203 } 203 }
204 return page; 204 return page;
205 205