summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2015-03-05 09:09:22 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2015-04-15 15:05:28 -0400
commit4bf46a272647d89e780126b52eda04737defd9f4 (patch)
tree989bac3ffce8a0f7f9184e14afb2dd9c28693cfe
parent525d27b23555419e0e7b73fb6e78d4d678cb4f32 (diff)
VFS: Impose ordering on accesses of d_inode and d_flags
Impose ordering on accesses of d_inode and d_flags to avoid the need to do this: if (!dentry->d_inode || d_is_negative(dentry)) { when this: if (d_is_negative(dentry)) { should suffice. This check is especially problematic if a dentry can have its type field set to something other than DENTRY_MISS_TYPE when d_inode is NULL (as in unionmount). What we really need to do is stick a write barrier between setting d_inode and setting d_flags and a read barrier between reading d_flags and reading d_inode. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/dcache.c47
-rw-r--r--include/linux/dcache.h21
2 files changed, 42 insertions, 26 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index d99736a63e3c..656ce522a218 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -269,6 +269,41 @@ 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,
276 struct inode *inode,
277 unsigned type_flags)
278{
279 unsigned flags;
280
281 dentry->d_inode = inode;
282 smp_wmb();
283 flags = READ_ONCE(dentry->d_flags);
284 flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
285 flags |= type_flags;
286 WRITE_ONCE(dentry->d_flags, flags);
287}
288
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)
298{
299 unsigned flags = READ_ONCE(dentry->d_flags);
300
301 flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
302 WRITE_ONCE(dentry->d_flags, flags);
303 smp_wmb();
304 dentry->d_inode = NULL;
305}
306
272static void dentry_free(struct dentry *dentry) 307static void dentry_free(struct dentry *dentry)
273{ 308{
274 WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias)); 309 WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
@@ -311,7 +346,7 @@ static void dentry_iput(struct dentry * dentry)
311{ 346{
312 struct inode *inode = dentry->d_inode; 347 struct inode *inode = dentry->d_inode;
313 if (inode) { 348 if (inode) {
314 dentry->d_inode = NULL; 349 __d_clear_type_and_inode(dentry);
315 hlist_del_init(&dentry->d_u.d_alias); 350 hlist_del_init(&dentry->d_u.d_alias);
316 spin_unlock(&dentry->d_lock); 351 spin_unlock(&dentry->d_lock);
317 spin_unlock(&inode->i_lock); 352 spin_unlock(&inode->i_lock);
@@ -335,8 +370,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
335 __releases(dentry->d_inode->i_lock) 370 __releases(dentry->d_inode->i_lock)
336{ 371{
337 struct inode *inode = dentry->d_inode; 372 struct inode *inode = dentry->d_inode;
338 __d_clear_type(dentry); 373 __d_clear_type_and_inode(dentry);
339 dentry->d_inode = NULL;
340 hlist_del_init(&dentry->d_u.d_alias); 374 hlist_del_init(&dentry->d_u.d_alias);
341 dentry_rcuwalk_barrier(dentry); 375 dentry_rcuwalk_barrier(dentry);
342 spin_unlock(&dentry->d_lock); 376 spin_unlock(&dentry->d_lock);
@@ -1715,11 +1749,9 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
1715 unsigned add_flags = d_flags_for_inode(inode); 1749 unsigned add_flags = d_flags_for_inode(inode);
1716 1750
1717 spin_lock(&dentry->d_lock); 1751 spin_lock(&dentry->d_lock);
1718 dentry->d_flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
1719 dentry->d_flags |= add_flags;
1720 if (inode) 1752 if (inode)
1721 hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); 1753 hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
1722 dentry->d_inode = inode; 1754 __d_set_inode_and_type(dentry, inode, add_flags);
1723 dentry_rcuwalk_barrier(dentry); 1755 dentry_rcuwalk_barrier(dentry);
1724 spin_unlock(&dentry->d_lock); 1756 spin_unlock(&dentry->d_lock);
1725 fsnotify_d_instantiate(dentry, inode); 1757 fsnotify_d_instantiate(dentry, inode);
@@ -1937,8 +1969,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
1937 add_flags |= DCACHE_DISCONNECTED; 1969 add_flags |= DCACHE_DISCONNECTED;
1938 1970
1939 spin_lock(&tmp->d_lock); 1971 spin_lock(&tmp->d_lock);
1940 tmp->d_inode = inode; 1972 __d_set_inode_and_type(tmp, inode, add_flags);
1941 tmp->d_flags |= add_flags;
1942 hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry); 1973 hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry);
1943 hlist_bl_lock(&tmp->d_sb->s_anon); 1974 hlist_bl_lock(&tmp->d_sb->s_anon);
1944 hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); 1975 hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index e83768ee38fc..df334cbacc6d 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -404,26 +404,11 @@ static inline bool d_mountpoint(const struct dentry *dentry)
404/* 404/*
405 * Directory cache entry type accessor functions. 405 * Directory cache entry type accessor functions.
406 */ 406 */
407static inline void __d_set_type(struct dentry *dentry, unsigned type)
408{
409 dentry->d_flags = (dentry->d_flags & ~DCACHE_ENTRY_TYPE) | type;
410}
411
412static inline void __d_clear_type(struct dentry *dentry)
413{
414 __d_set_type(dentry, DCACHE_MISS_TYPE);
415}
416
417static inline void d_set_type(struct dentry *dentry, unsigned type)
418{
419 spin_lock(&dentry->d_lock);
420 __d_set_type(dentry, type);
421 spin_unlock(&dentry->d_lock);
422}
423
424static inline unsigned __d_entry_type(const struct dentry *dentry) 407static inline unsigned __d_entry_type(const struct dentry *dentry)
425{ 408{
426 return dentry->d_flags & DCACHE_ENTRY_TYPE; 409 unsigned type = READ_ONCE(dentry->d_flags);
410 smp_rmb();
411 return type & DCACHE_ENTRY_TYPE;
427} 412}
428 413
429static inline bool d_is_miss(const struct dentry *dentry) 414static inline bool d_is_miss(const struct dentry *dentry)