aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2016-03-26 16:14:37 -0400
committerTheodore Ts'o <tytso@mit.edu>2016-03-26 16:14:37 -0400
commitd101a125954eae1d397adda94ca6319485a50493 (patch)
tree0f5853af51446f389c60f1a25f3875ef8a75ba41 /fs/overlayfs
parentc9af28fdd44922a6c10c9f8315718408af98e315 (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/overlayfs')
-rw-r--r--fs/overlayfs/super.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index ef64984c9bbc..5d972e6cd3fe 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -295,6 +295,37 @@ static void ovl_dentry_release(struct dentry *dentry)
295 } 295 }
296} 296}
297 297
298static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode)
299{
300 struct dentry *real;
301
302 if (d_is_dir(dentry)) {
303 if (!inode || inode == d_inode(dentry))
304 return dentry;
305 goto bug;
306 }
307
308 real = ovl_dentry_upper(dentry);
309 if (real && (!inode || inode == d_inode(real)))
310 return real;
311
312 real = ovl_dentry_lower(dentry);
313 if (!real)
314 goto bug;
315
316 if (!inode || inode == d_inode(real))
317 return real;
318
319 /* Handle recursion */
320 if (real->d_flags & DCACHE_OP_REAL)
321 return real->d_op->d_real(real, inode);
322
323bug:
324 WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry,
325 inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0);
326 return dentry;
327}
328
298static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags) 329static int ovl_dentry_revalidate(struct dentry *dentry, unsigned int flags)
299{ 330{
300 struct ovl_entry *oe = dentry->d_fsdata; 331 struct ovl_entry *oe = dentry->d_fsdata;
@@ -339,11 +370,13 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
339static const struct dentry_operations ovl_dentry_operations = { 370static const struct dentry_operations ovl_dentry_operations = {
340 .d_release = ovl_dentry_release, 371 .d_release = ovl_dentry_release,
341 .d_select_inode = ovl_d_select_inode, 372 .d_select_inode = ovl_d_select_inode,
373 .d_real = ovl_d_real,
342}; 374};
343 375
344static const struct dentry_operations ovl_reval_dentry_operations = { 376static const struct dentry_operations ovl_reval_dentry_operations = {
345 .d_release = ovl_dentry_release, 377 .d_release = ovl_dentry_release,
346 .d_select_inode = ovl_d_select_inode, 378 .d_select_inode = ovl_d_select_inode,
379 .d_real = ovl_d_real,
347 .d_revalidate = ovl_dentry_revalidate, 380 .d_revalidate = ovl_dentry_revalidate,
348 .d_weak_revalidate = ovl_dentry_weak_revalidate, 381 .d_weak_revalidate = ovl_dentry_weak_revalidate,
349}; 382};