aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2017-12-24 11:28:04 -0500
committerMiklos Szeredi <mszeredi@redhat.com>2018-01-24 05:26:03 -0500
commit9436a1a339fae84698aaa0b66d7a822018388348 (patch)
tree38d74ccb48e21ade05347aa0e4f2de2ad6bd17c0
parentf71bd9cfb692ec80236b186419bf907eb5fa348c (diff)
ovl: decode lower file handles of unlinked but open files
Lookup overlay inode in cache by origin inode, so we can decode a file handle of an open file even if the index has a whiteout index entry to mark this overlay inode was unlinked. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/export.c23
-rw-r--r--fs/overlayfs/inode.c16
-rw-r--r--fs/overlayfs/overlayfs.h1
3 files changed, 38 insertions, 2 deletions
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index f475a10eec07..0bca38c79244 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -443,14 +443,22 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
443 struct ovl_path *stack = &origin; 443 struct ovl_path *stack = &origin;
444 struct dentry *dentry = NULL; 444 struct dentry *dentry = NULL;
445 struct dentry *index = NULL; 445 struct dentry *index = NULL;
446 struct inode *inode = NULL;
447 bool is_deleted = false;
446 int err; 448 int err;
447 449
448 /* First lookup indexed upper by fh */ 450 /* First lookup indexed upper by fh */
449 if (ofs->indexdir) { 451 if (ofs->indexdir) {
450 index = ovl_get_index_fh(ofs, fh); 452 index = ovl_get_index_fh(ofs, fh);
451 err = PTR_ERR(index); 453 err = PTR_ERR(index);
452 if (IS_ERR(index)) 454 if (IS_ERR(index)) {
453 return ERR_PTR(err); 455 if (err != -ESTALE)
456 return ERR_PTR(err);
457
458 /* Found a whiteout index - treat as deleted inode */
459 is_deleted = true;
460 index = NULL;
461 }
454 } 462 }
455 463
456 /* Then lookup origin by fh */ 464 /* Then lookup origin by fh */
@@ -461,6 +469,16 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
461 err = ovl_verify_origin(index, origin.dentry, false); 469 err = ovl_verify_origin(index, origin.dentry, false);
462 if (err) 470 if (err)
463 goto out_err; 471 goto out_err;
472 } else if (is_deleted) {
473 /* Lookup deleted non-dir by origin inode */
474 if (!d_is_dir(origin.dentry))
475 inode = ovl_lookup_inode(sb, origin.dentry);
476 err = -ESTALE;
477 if (!inode || atomic_read(&inode->i_count) == 1)
478 goto out_err;
479
480 /* Deleted but still open? */
481 index = dget(ovl_i_dentry_upper(inode));
464 } 482 }
465 483
466 dentry = ovl_get_dentry(sb, NULL, &origin, index); 484 dentry = ovl_get_dentry(sb, NULL, &origin, index);
@@ -468,6 +486,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
468out: 486out:
469 dput(origin.dentry); 487 dput(origin.dentry);
470 dput(index); 488 dput(index);
489 iput(inode);
471 return dentry; 490 return dentry;
472 491
473out_err: 492out_err:
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index bfd7c766b5cd..56ba015b9f5e 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -645,6 +645,22 @@ static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry,
645 return true; 645 return true;
646} 646}
647 647
648struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *origin)
649{
650 struct inode *inode, *key = d_inode(origin);
651
652 inode = ilookup5(sb, (unsigned long) key, ovl_inode_test, key);
653 if (!inode)
654 return NULL;
655
656 if (!ovl_verify_inode(inode, origin, NULL)) {
657 iput(inode);
658 return ERR_PTR(-ESTALE);
659 }
660
661 return inode;
662}
663
648struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry, 664struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,
649 struct dentry *lowerdentry, struct dentry *index, 665 struct dentry *lowerdentry, struct dentry *index,
650 unsigned int numlower) 666 unsigned int numlower)
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 40ba11e412b1..a47f9142b6be 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -322,6 +322,7 @@ int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
322bool ovl_is_private_xattr(const char *name); 322bool ovl_is_private_xattr(const char *name);
323 323
324struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev); 324struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev);
325struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *origin);
325struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry, 326struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,
326 struct dentry *lowerdentry, struct dentry *index, 327 struct dentry *lowerdentry, struct dentry *index,
327 unsigned int numlower); 328 unsigned int numlower);