aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-02-29 12:12:46 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2016-02-29 12:16:43 -0500
commita528aca7f359f4b0b1d72ae406097e491a5ba9ea (patch)
tree26b95bc4e207d3bd6afc11affbfa0fe85ac53b6a /fs/dcache.c
parent5129fa482b16615fd4464d2f5d23acb1b7056c66 (diff)
use ->d_seq to get coherency between ->d_inode and ->d_flags
Games with ordering and barriers are way too brittle. Just bump ->d_seq before and after updating ->d_inode and ->d_flags type bits, so that verifying ->d_seq would guarantee they are coherent. Cc: stable@vger.kernel.org # v3.13+ Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c20
1 files changed, 5 insertions, 15 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 92d5140de851..2398f9f94337 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -269,9 +269,6 @@ static inline int dname_external(const struct dentry *dentry)
269 return dentry->d_name.name != dentry->d_iname; 269 return dentry->d_name.name != dentry->d_iname;
270} 270}
271 271
272/*
273 * Make sure other CPUs see the inode attached before the type is set.
274 */
275static inline void __d_set_inode_and_type(struct dentry *dentry, 272static inline void __d_set_inode_and_type(struct dentry *dentry,
276 struct inode *inode, 273 struct inode *inode,
277 unsigned type_flags) 274 unsigned type_flags)
@@ -279,28 +276,18 @@ static inline void __d_set_inode_and_type(struct dentry *dentry,
279 unsigned flags; 276 unsigned flags;
280 277
281 dentry->d_inode = inode; 278 dentry->d_inode = inode;
282 smp_wmb();
283 flags = READ_ONCE(dentry->d_flags); 279 flags = READ_ONCE(dentry->d_flags);
284 flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); 280 flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
285 flags |= type_flags; 281 flags |= type_flags;
286 WRITE_ONCE(dentry->d_flags, flags); 282 WRITE_ONCE(dentry->d_flags, flags);
287} 283}
288 284
289/*
290 * Ideally, we want to make sure that other CPUs see the flags cleared before
291 * the inode is detached, but this is really a violation of RCU principles
292 * since the ordering suggests we should always set inode before flags.
293 *
294 * We should instead replace or discard the entire dentry - but that sucks
295 * performancewise on mass deletion/rename.
296 */
297static inline void __d_clear_type_and_inode(struct dentry *dentry) 285static inline void __d_clear_type_and_inode(struct dentry *dentry)
298{ 286{
299 unsigned flags = READ_ONCE(dentry->d_flags); 287 unsigned flags = READ_ONCE(dentry->d_flags);
300 288
301 flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); 289 flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
302 WRITE_ONCE(dentry->d_flags, flags); 290 WRITE_ONCE(dentry->d_flags, flags);
303 smp_wmb();
304 dentry->d_inode = NULL; 291 dentry->d_inode = NULL;
305} 292}
306 293
@@ -370,9 +357,11 @@ static void dentry_unlink_inode(struct dentry * dentry)
370 __releases(dentry->d_inode->i_lock) 357 __releases(dentry->d_inode->i_lock)
371{ 358{
372 struct inode *inode = dentry->d_inode; 359 struct inode *inode = dentry->d_inode;
360
361 raw_write_seqcount_begin(&dentry->d_seq);
373 __d_clear_type_and_inode(dentry); 362 __d_clear_type_and_inode(dentry);
374 hlist_del_init(&dentry->d_u.d_alias); 363 hlist_del_init(&dentry->d_u.d_alias);
375 dentry_rcuwalk_invalidate(dentry); 364 raw_write_seqcount_end(&dentry->d_seq);
376 spin_unlock(&dentry->d_lock); 365 spin_unlock(&dentry->d_lock);
377 spin_unlock(&inode->i_lock); 366 spin_unlock(&inode->i_lock);
378 if (!inode->i_nlink) 367 if (!inode->i_nlink)
@@ -1758,8 +1747,9 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
1758 spin_lock(&dentry->d_lock); 1747 spin_lock(&dentry->d_lock);
1759 if (inode) 1748 if (inode)
1760 hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); 1749 hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
1750 raw_write_seqcount_begin(&dentry->d_seq);
1761 __d_set_inode_and_type(dentry, inode, add_flags); 1751 __d_set_inode_and_type(dentry, inode, add_flags);
1762 dentry_rcuwalk_invalidate(dentry); 1752 raw_write_seqcount_end(&dentry->d_seq);
1763 spin_unlock(&dentry->d_lock); 1753 spin_unlock(&dentry->d_lock);
1764 fsnotify_d_instantiate(dentry, inode); 1754 fsnotify_d_instantiate(dentry, inode);
1765} 1755}