[PATCH 7/7] ovl: follow decoded origin file handle of merge dir

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

 



When 'verify_dir' feature is enabled, if lower dir does not match the
origin fh stored in upper dir, or if no lower dir was found by name,
try to decode the stored origin fh and use the result as the merge dir
lower dentry.

When there is more than a single lower layer, a lower merge directory
followed from upper dir by origin fh is not followed down again to lower
layers by name.

This is going to be used for overlayfs snapshots and NFS export.

Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
---
 Documentation/filesystems/overlayfs.txt |  6 +++++-
 fs/dcache.c                             |  1 +
 fs/overlayfs/namei.c                    | 37 ++++++++++++++++++++++++++++++---
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt
index 17a3c9196fd3..d89041baceb9 100644
--- a/Documentation/filesystems/overlayfs.txt
+++ b/Documentation/filesystems/overlayfs.txt
@@ -279,7 +279,11 @@ the "trusted.overlay.redirect" extended attribute, will verify that the
 found lower directory file handle and lower filesystem UUID match the
 origin file handle that was stored at copy_up time.  If a found lower
 directory does not match the stored origin, that directory will be not be
-merged with the upper directory.
+merged with the upper directory.  If the stored origin file handle can be
+decoded to an existing lower directory, the decoded directory will be
+merged with the upper directory instead.  The "verify_dir" feature,
+therefore, makes an overlay mount cope better with the situations of
+lower directory rename and delete.
 
 Testsuite
 ---------
diff --git a/fs/dcache.c b/fs/dcache.c
index f90141387f01..f61e03a38a30 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -3529,6 +3529,7 @@ bool is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
 
 	return result;
 }
+EXPORT_SYMBOL(is_subdir);
 
 static enum d_walk_ret d_genocide_kill(void *data, struct dentry *dentry)
 {
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 988cb5496474..5de7aa60a7a6 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -83,9 +83,21 @@ static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d,
 	goto err_free;
 }
 
-static int ovl_acceptable(void *ctx, struct dentry *dentry)
+static int ovl_acceptable(void *mnt, struct dentry *dentry)
 {
-	return 1;
+	/*
+	 * A non-dir origin may be disconnected, which is fine, because
+	 * we only need it for its unique inode number.
+	 */
+	if (!d_is_dir(dentry))
+		return 1;
+
+	/* Don't want to follow a deleted empty lower directory */
+	if (d_unhashed(dentry))
+		return 0;
+
+	/* Check if directory belongs to the layer mounted at mnt */
+	return is_subdir(dentry, ((struct vfsmount *)mnt)->mnt_root);
 }
 
 static struct ovl_fh *ovl_get_origin_fh(struct dentry *dentry)
@@ -160,7 +172,7 @@ static struct dentry *ovl_get_origin(struct dentry *dentry,
 	bytes = (fh->len - offsetof(struct ovl_fh, fid));
 	origin = exportfs_decode_fh(mnt, (struct fid *)fh->fid,
 				    bytes >> 2, (int)fh->type,
-				    ovl_acceptable, NULL);
+				    ovl_acceptable, mnt);
 	if (IS_ERR(origin)) {
 		/* Treat stale file handle as "origin unknown" */
 		if (origin == ERR_PTR(-ESTALE))
@@ -697,6 +709,25 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 		}
 	}
 
+	/*
+	 * If lower not found by name or couldn't verify origin fh, try to
+	 * follow the decoded origin fh in upper to the first lower dir.
+	 */
+	if (!d.stop && poe->numlower && upperdentry && !ctr &&
+	    ovl_verify_dir(dentry->d_sb)) {
+		err = ovl_check_origin(upperdentry, roe->lowerstack,
+				       roe->numlower, &stack, &ctr);
+		if (err)
+			goto out_put;
+		/*
+		 * XXX: We do not continue layers lookup from decoded origin for
+		 * more than a single lower layer. This would require setting
+		 * d.redirect to decoded origin path and jump back to the
+		 * lowerstack layers lookup loop with 'i' set to the root layer
+		 * number where we found the decoded origin.
+		 */
+	}
+
 	/* Lookup index by lower inode and verify it matches upper inode */
 	if (ctr && !d.is_dir && ovl_indexdir(dentry->d_sb)) {
 		struct dentry *origin = stack[0].dentry;
-- 
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