diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2016-03-26 16:14:37 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-03-26 16:14:37 -0400 |
commit | d101a125954eae1d397adda94ca6319485a50493 (patch) | |
tree | 0f5853af51446f389c60f1a25f3875ef8a75ba41 /include/linux/dcache.h | |
parent | c9af28fdd44922a6c10c9f8315718408af98e315 (diff) |
fs: add file_dentry()
This series fixes bugs in nfs and ext4 due to 4bacc9c9234c ("overlayfs:
Make f_path always point to the overlay and f_inode to the underlay").
Regular files opened on overlayfs will result in the file being opened on
the underlying filesystem, while f_path points to the overlayfs
mount/dentry.
This confuses filesystems which get the dentry from struct file and assume
it's theirs.
Add a new helper, file_dentry() [*], to get the filesystem's own dentry
from the file. This checks file->f_path.dentry->d_flags against
DCACHE_OP_REAL, and returns file->f_path.dentry if DCACHE_OP_REAL is not
set (this is the common, non-overlayfs case).
In the uncommon case it will call into overlayfs's ->d_real() to get the
underlying dentry, matching file_inode(file).
The reason we need to check against the inode is that if the file is copied
up while being open, d_real() would return the upper dentry, while the open
file comes from the lower dentry.
[*] If possible, it's better simply to use file_inode() instead.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Tested-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
Reviewed-by: Trond Myklebust <trond.myklebust@primarydata.com>
Cc: <stable@vger.kernel.org> # v4.2
Cc: David Howells <dhowells@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Daniel Axtens <dja@axtens.net>
Diffstat (limited to 'include/linux/dcache.h')
-rw-r--r-- | include/linux/dcache.h | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 7cb043d8f4e8..4bb4de8d95ea 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -161,6 +161,7 @@ struct dentry_operations { | |||
161 | struct vfsmount *(*d_automount)(struct path *); | 161 | struct vfsmount *(*d_automount)(struct path *); |
162 | int (*d_manage)(struct dentry *, bool); | 162 | int (*d_manage)(struct dentry *, bool); |
163 | struct inode *(*d_select_inode)(struct dentry *, unsigned); | 163 | struct inode *(*d_select_inode)(struct dentry *, unsigned); |
164 | struct dentry *(*d_real)(struct dentry *, struct inode *); | ||
164 | } ____cacheline_aligned; | 165 | } ____cacheline_aligned; |
165 | 166 | ||
166 | /* | 167 | /* |
@@ -229,6 +230,7 @@ struct dentry_operations { | |||
229 | #define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ | 230 | #define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ |
230 | 231 | ||
231 | #define DCACHE_ENCRYPTED_WITH_KEY 0x04000000 /* dir is encrypted with a valid key */ | 232 | #define DCACHE_ENCRYPTED_WITH_KEY 0x04000000 /* dir is encrypted with a valid key */ |
233 | #define DCACHE_OP_REAL 0x08000000 | ||
232 | 234 | ||
233 | extern seqlock_t rename_lock; | 235 | extern seqlock_t rename_lock; |
234 | 236 | ||
@@ -555,4 +557,12 @@ static inline struct dentry *d_backing_dentry(struct dentry *upper) | |||
555 | return upper; | 557 | return upper; |
556 | } | 558 | } |
557 | 559 | ||
560 | static inline struct dentry *d_real(struct dentry *dentry) | ||
561 | { | ||
562 | if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) | ||
563 | return dentry->d_op->d_real(dentry, NULL); | ||
564 | else | ||
565 | return dentry; | ||
566 | } | ||
567 | |||
558 | #endif /* __LINUX_DCACHE_H */ | 568 | #endif /* __LINUX_DCACHE_H */ |