[PATCH 4/4] ovl: lookup in inode cache when decoding lower file handle

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When decoding a lower file handle, we need to check if lower file was
copied up and indexed and if it has a whiteout index, we need to check
if this is an unlinked but open non-dir before returning -ESTALE.

To find out if this is an unlinked but open non-dir we need to lookup
an overlay inode in inode cache with an alias.

Before this change, the overlay inode was looked up by lower inode and
that required decoding the lower file handle before looking in inode
cache. If the lower inode turned out to be a directory, we may have
paid an expensive cost to reconnect that lower directory for nothing.

After this change, we start by looking up an overlay inode in inode
cache by lower file handle. If we don't find an overlay inode and dentry
alias, then we only need to decode the lower file handle in case the
lower file is not indexed or if the index is a non-dir.

Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
---
 fs/overlayfs/export.c | 39 ++++++++++++++++-----------------------
 1 file changed, 16 insertions(+), 23 deletions(-)

diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index 031cbe060e1b..f8dce6976248 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -700,22 +700,26 @@ 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;
+	struct inode *inode;
 	int err;
 
-	/* First lookup indexed upper by fh */
+	/* First lookup overlay inode in inode cache by fh */
+	inode = ovl_lookup_inode_fh(sb, fh);
+	if (IS_ERR(inode))
+		return ERR_CAST(inode);
+	if (inode) {
+		dentry = d_find_any_alias(inode);
+		iput(inode);
+		if (dentry)
+			return dentry;
+	}
+
+	/* Then lookup indexed upper by fh */
 	if (ofs->indexdir) {
 		index = ovl_get_index_fh(ofs, fh);
 		err = PTR_ERR(index);
-		if (IS_ERR(index)) {
-			if (err != -ESTALE)
-				return ERR_PTR(err);
-
-			/* Found a whiteout index - treat as deleted inode */
-			is_deleted = true;
-			index = NULL;
-		}
+		if (IS_ERR(index))
+			return index;
 	}
 
 	/* Then try to get upper dir by index */
@@ -731,7 +735,7 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
 		goto out;
 	}
 
-	/* Then lookup origin by fh */
+	/* Then lookup indexed non-dir origin or non-upper by fh */
 	err = ovl_check_origin_fh(ofs, fh, NULL, &stack);
 	if (err) {
 		goto out_err;
@@ -739,16 +743,6 @@ 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, false);
-		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);
@@ -756,7 +750,6 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
 out:
 	dput(origin.dentry);
 	dput(index);
-	iput(inode);
 	return dentry;
 
 out_err:
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux