diff options
author | Amir Goldstein <amir73il@gmail.com> | 2017-12-24 18:28:04 +0200 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-01-24 11:26:03 +0100 |
commit | 9436a1a339fae84698aaa0b66d7a822018388348 (patch) | |
tree | 38d74ccb48e21ade05347aa0e4f2de2ad6bd17c0 /fs/overlayfs/export.c | |
parent | f71bd9cfb692ec80236b186419bf907eb5fa348c (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>
Diffstat (limited to 'fs/overlayfs/export.c')
-rw-r--r-- | fs/overlayfs/export.c | 23 |
1 files changed, 21 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, struct ovl_path *stack = &origin; struct dentry *dentry = NULL; struct dentry *index = NULL; + struct inode *inode = NULL; + bool is_deleted = false; int err; /* First lookup indexed upper by fh */ if (ofs->indexdir) { index = ovl_get_index_fh(ofs, fh); err = PTR_ERR(index); - if (IS_ERR(index)) - return ERR_PTR(err); + if (IS_ERR(index)) { + if (err != -ESTALE) + return ERR_PTR(err); + + /* Found a whiteout index - treat as deleted inode */ + is_deleted = true; + index = NULL; + } } /* Then lookup origin by fh */ @@ -461,6 +469,16 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb, err = ovl_verify_origin(index, origin.dentry, false); if (err) goto out_err; + } else if (is_deleted) { + /* Lookup deleted non-dir by origin inode */ + if (!d_is_dir(origin.dentry)) + inode = ovl_lookup_inode(sb, origin.dentry); + err = -ESTALE; + if (!inode || atomic_read(&inode->i_count) == 1) + goto out_err; + + /* Deleted but still open? */ + index = dget(ovl_i_dentry_upper(inode)); } dentry = ovl_get_dentry(sb, NULL, &origin, index); @@ -468,6 +486,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb, out: dput(origin.dentry); dput(index); + iput(inode); return dentry; out_err: |