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 /fs/dcache.c | |
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 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 32ceae3e6112..d5ecc6e477da 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1667,7 +1667,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1667 | DCACHE_OP_REVALIDATE | | 1667 | DCACHE_OP_REVALIDATE | |
1668 | DCACHE_OP_WEAK_REVALIDATE | | 1668 | DCACHE_OP_WEAK_REVALIDATE | |
1669 | DCACHE_OP_DELETE | | 1669 | DCACHE_OP_DELETE | |
1670 | DCACHE_OP_SELECT_INODE)); | 1670 | DCACHE_OP_SELECT_INODE | |
1671 | DCACHE_OP_REAL)); | ||
1671 | dentry->d_op = op; | 1672 | dentry->d_op = op; |
1672 | if (!op) | 1673 | if (!op) |
1673 | return; | 1674 | return; |
@@ -1685,6 +1686,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1685 | dentry->d_flags |= DCACHE_OP_PRUNE; | 1686 | dentry->d_flags |= DCACHE_OP_PRUNE; |
1686 | if (op->d_select_inode) | 1687 | if (op->d_select_inode) |
1687 | dentry->d_flags |= DCACHE_OP_SELECT_INODE; | 1688 | dentry->d_flags |= DCACHE_OP_SELECT_INODE; |
1689 | if (op->d_real) | ||
1690 | dentry->d_flags |= DCACHE_OP_REAL; | ||
1688 | 1691 | ||
1689 | } | 1692 | } |
1690 | EXPORT_SYMBOL(d_set_d_op); | 1693 | EXPORT_SYMBOL(d_set_d_op); |