diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-16 23:27:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-16 23:27:56 -0400 |
commit | 4fc8adcfec3da639da76e8314c9ccefe5bf9a045 (patch) | |
tree | e07a2dea8acf04d8bbbecd4fd3a571653ecdd953 /fs/dcache.c | |
parent | 84588e7a5d8220446d677d7b909a20ee7a4496b9 (diff) | |
parent | aa4d86163e4e91a1ac560954a554bab417e338f4 (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.c | 47 |
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 | */ | ||
275 | static 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 | */ | ||
297 | static 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 | |||
272 | static void dentry_free(struct dentry *dentry) | 307 | static 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); |