aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ufs
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/ufs
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/ufs')
-rw-r--r--fs/ufs/dir.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 0b1457292734..4c07421453af 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -105,7 +105,7 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
105} 105}
106 106
107 107
108static void ufs_check_page(struct page *page) 108static bool ufs_check_page(struct page *page)
109{ 109{
110 struct inode *dir = page->mapping->host; 110 struct inode *dir = page->mapping->host;
111 struct super_block *sb = dir->i_sb; 111 struct super_block *sb = dir->i_sb;
@@ -143,7 +143,7 @@ static void ufs_check_page(struct page *page)
143 goto Eend; 143 goto Eend;
144out: 144out:
145 SetPageChecked(page); 145 SetPageChecked(page);
146 return; 146 return true;
147 147
148 /* Too bad, we had an error */ 148 /* Too bad, we had an error */
149 149
@@ -180,8 +180,8 @@ Eend:
180 "offset=%lu", 180 "offset=%lu",
181 dir->i_ino, (page->index<<PAGE_SHIFT)+offs); 181 dir->i_ino, (page->index<<PAGE_SHIFT)+offs);
182fail: 182fail:
183 SetPageChecked(page);
184 SetPageError(page); 183 SetPageError(page);
184 return false;
185} 185}
186 186
187static struct page *ufs_get_page(struct inode *dir, unsigned long n) 187static struct page *ufs_get_page(struct inode *dir, unsigned long n)
@@ -190,10 +190,10 @@ static struct page *ufs_get_page(struct inode *dir, unsigned long n)
190 struct page *page = read_mapping_page(mapping, n, NULL); 190 struct page *page = read_mapping_page(mapping, n, NULL);
191 if (!IS_ERR(page)) { 191 if (!IS_ERR(page)) {
192 kmap(page); 192 kmap(page);
193 if (!PageChecked(page)) 193 if (unlikely(!PageChecked(page))) {
194 ufs_check_page(page); 194 if (PageError(page) || !ufs_check_page(page))
195 if (PageError(page)) 195 goto fail;
196 goto fail; 196 }
197 } 197 }
198 return page; 198 return page;
199 199