summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/afs/dir.c14
-rw-r--r--fs/exofs/dir.c14
-rw-r--r--fs/ext2/dir.c14
-rw-r--r--fs/nilfs2/dir.c14
-rw-r--r--fs/ufs/dir.c14
5 files changed, 35 insertions, 35 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
diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c
index 547b93cbea63..a7661aaead9a 100644
--- a/fs/exofs/dir.c
+++ b/fs/exofs/dir.c
@@ -79,7 +79,7 @@ static int exofs_commit_chunk(struct page *page, loff_t pos, unsigned len)
79 return err; 79 return err;
80} 80}
81 81
82static void exofs_check_page(struct page *page) 82static bool exofs_check_page(struct page *page)
83{ 83{
84 struct inode *dir = page->mapping->host; 84 struct inode *dir = page->mapping->host;
85 unsigned chunk_size = exofs_chunk_size(dir); 85 unsigned chunk_size = exofs_chunk_size(dir);
@@ -114,7 +114,7 @@ static void exofs_check_page(struct page *page)
114 goto Eend; 114 goto Eend;
115out: 115out:
116 SetPageChecked(page); 116 SetPageChecked(page);
117 return; 117 return true;
118 118
119Ebadsize: 119Ebadsize:
120 EXOFS_ERR("ERROR [exofs_check_page]: " 120 EXOFS_ERR("ERROR [exofs_check_page]: "
@@ -150,8 +150,8 @@ Eend:
150 dir->i_ino, (page->index<<PAGE_SHIFT)+offs, 150 dir->i_ino, (page->index<<PAGE_SHIFT)+offs,
151 _LLU(le64_to_cpu(p->inode_no))); 151 _LLU(le64_to_cpu(p->inode_no)));
152fail: 152fail:
153 SetPageChecked(page);
154 SetPageError(page); 153 SetPageError(page);
154 return false;
155} 155}
156 156
157static struct page *exofs_get_page(struct inode *dir, unsigned long n) 157static struct page *exofs_get_page(struct inode *dir, unsigned long n)
@@ -161,10 +161,10 @@ static struct page *exofs_get_page(struct inode *dir, unsigned long n)
161 161
162 if (!IS_ERR(page)) { 162 if (!IS_ERR(page)) {
163 kmap(page); 163 kmap(page);
164 if (!PageChecked(page)) 164 if (unlikely(!PageChecked(page))) {
165 exofs_check_page(page); 165 if (PageError(page) || !exofs_check_page(page))
166 if (PageError(page)) 166 goto fail;
167 goto fail; 167 }
168 } 168 }
169 return page; 169 return page;
170 170
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 7ff6fcfa685d..f0f4363a15b2 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -110,7 +110,7 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
110 return err; 110 return err;
111} 111}
112 112
113static void ext2_check_page(struct page *page, int quiet) 113static bool ext2_check_page(struct page *page, int quiet)
114{ 114{
115 struct inode *dir = page->mapping->host; 115 struct inode *dir = page->mapping->host;
116 struct super_block *sb = dir->i_sb; 116 struct super_block *sb = dir->i_sb;
@@ -148,7 +148,7 @@ static void ext2_check_page(struct page *page, int quiet)
148 goto Eend; 148 goto Eend;
149out: 149out:
150 SetPageChecked(page); 150 SetPageChecked(page);
151 return; 151 return true;
152 152
153 /* Too bad, we had an error */ 153 /* Too bad, we had an error */
154 154
@@ -190,8 +190,8 @@ Eend:
190 (unsigned long) le32_to_cpu(p->inode)); 190 (unsigned long) le32_to_cpu(p->inode));
191 } 191 }
192fail: 192fail:
193 SetPageChecked(page);
194 SetPageError(page); 193 SetPageError(page);
194 return false;
195} 195}
196 196
197static struct page * ext2_get_page(struct inode *dir, unsigned long n, 197static struct page * ext2_get_page(struct inode *dir, unsigned long n,
@@ -201,10 +201,10 @@ static struct page * ext2_get_page(struct inode *dir, unsigned long n,
201 struct page *page = read_mapping_page(mapping, n, NULL); 201 struct page *page = read_mapping_page(mapping, n, NULL);
202 if (!IS_ERR(page)) { 202 if (!IS_ERR(page)) {
203 kmap(page); 203 kmap(page);
204 if (!PageChecked(page)) 204 if (unlikely(!PageChecked(page))) {
205 ext2_check_page(page, quiet); 205 if (PageError(page) || !ext2_check_page(page, quiet))
206 if (PageError(page)) 206 goto fail;
207 goto fail; 207 }
208 } 208 }
209 return page; 209 return page;
210 210
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c
index e08f064e4bd7..2eaed9254eb2 100644
--- a/fs/nilfs2/dir.c
+++ b/fs/nilfs2/dir.c
@@ -102,7 +102,7 @@ static void nilfs_commit_chunk(struct page *page,
102 unlock_page(page); 102 unlock_page(page);
103} 103}
104 104
105static void nilfs_check_page(struct page *page) 105static bool nilfs_check_page(struct page *page)
106{ 106{
107 struct inode *dir = page->mapping->host; 107 struct inode *dir = page->mapping->host;
108 struct super_block *sb = dir->i_sb; 108 struct super_block *sb = dir->i_sb;
@@ -137,7 +137,7 @@ static void nilfs_check_page(struct page *page)
137 goto Eend; 137 goto Eend;
138out: 138out:
139 SetPageChecked(page); 139 SetPageChecked(page);
140 return; 140 return true;
141 141
142 /* Too bad, we had an error */ 142 /* Too bad, we had an error */
143 143
@@ -173,8 +173,8 @@ Eend:
173 dir->i_ino, (page->index<<PAGE_SHIFT)+offs, 173 dir->i_ino, (page->index<<PAGE_SHIFT)+offs,
174 (unsigned long) le64_to_cpu(p->inode)); 174 (unsigned long) le64_to_cpu(p->inode));
175fail: 175fail:
176 SetPageChecked(page);
177 SetPageError(page); 176 SetPageError(page);
177 return false;
178} 178}
179 179
180static struct page *nilfs_get_page(struct inode *dir, unsigned long n) 180static struct page *nilfs_get_page(struct inode *dir, unsigned long n)
@@ -184,10 +184,10 @@ static struct page *nilfs_get_page(struct inode *dir, unsigned long n)
184 184
185 if (!IS_ERR(page)) { 185 if (!IS_ERR(page)) {
186 kmap(page); 186 kmap(page);
187 if (!PageChecked(page)) 187 if (unlikely(!PageChecked(page))) {
188 nilfs_check_page(page); 188 if (PageError(page) || !nilfs_check_page(page))
189 if (PageError(page)) 189 goto fail;
190 goto fail; 190 }
191 } 191 }
192 return page; 192 return page;
193 193
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