summaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-16 23:27:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-16 23:27:56 -0400
commit4fc8adcfec3da639da76e8314c9ccefe5bf9a045 (patch)
treee07a2dea8acf04d8bbbecd4fd3a571653ecdd953 /fs/dcache.c
parent84588e7a5d8220446d677d7b909a20ee7a4496b9 (diff)
parentaa4d86163e4e91a1ac560954a554bab417e338f4 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull third hunk of vfs changes from Al Viro: "This contains the ->direct_IO() changes from Omar + saner generic_write_checks() + dealing with fcntl()/{read,write}() races (mirroring O_APPEND/O_DIRECT into iocb->ki_flags and instead of repeatedly looking at ->f_flags, which can be changed by fcntl(2), check ->ki_flags - which cannot) + infrastructure bits for dhowells' d_inode annotations + Christophs switch of /dev/loop to vfs_iter_write()" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (30 commits) block: loop: switch to VFS ITER_BVEC configfs: Fix inconsistent use of file_inode() vs file->f_path.dentry->d_inode VFS: Make pathwalk use d_is_reg() rather than S_ISREG() VFS: Fix up debugfs to use d_is_dir() in place of S_ISDIR() VFS: Combine inode checks with d_is_negative() and d_is_positive() in pathwalk NFS: Don't use d_inode as a variable name VFS: Impose ordering on accesses of d_inode and d_flags VFS: Add owner-filesystem positive/negative dentry checks nfs: generic_write_checks() shouldn't be done on swapout... ocfs2: use __generic_file_write_iter() mirror O_APPEND and O_DIRECT into iocb->ki_flags switch generic_write_checks() to iocb and iter ocfs2: move generic_write_checks() before the alignment checks ocfs2_file_write_iter: stop messing with ppos udf_file_write_iter: reorder and simplify fuse: ->direct_IO() doesn't need generic_write_checks() ext4_file_write_iter: move generic_write_checks() up xfs_file_aio_write_checks: switch to iocb/iov_iter generic_write_checks(): drop isblk argument blkdev_write_iter: expand generic_file_checks() call in there ...
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c47
1 files changed, 39 insertions, 8 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);