[PATCH v3 4/6] fsck.overlay: correct redirect xattr check

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

 



When we found a valid redirect xattr and the lower origin targed was
covered by a directory, it could be 1) an another redirect directory,
or 2) an opaque directory created after rename in overlayfs or 3) a
general directory created in the underlying directory when overlay is
offline. Currently, we only handled case 2, this patch cover the other
two cases.

This patch ask user if we find a covering directory whitout opaque
and another redirect xattr.

Signed-off-by: zhangyi (F) <yi.zhang@xxxxxxxxxx>
---
 README.md | 31 ++++++++++++++-------
 check.c   | 94 ++++++++++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 90 insertions(+), 35 deletions(-)

diff --git a/README.md b/README.md
index a8d0b1c..2e6146f 100644
--- a/README.md
+++ b/README.md
@@ -25,16 +25,27 @@ If an redirect directory is found, the following must be met:
 
 1) The directory path pointed by redirect xattr should exist in one of lower
    layers.
-2) The origin directory should be redirected only once in one layer, which means
-   there is only one redirect xattr point to this origin directory in the
-   specified layer.
-3) A whiteout or an opaque directory with the same name to origin should exist
-   in the same directory as the redirect directory.
-
-If not, 1) The redirect xattr is invalid and need to remove 2) One of the
-redirect xattr is redundant but not sure which one is, ask user or warn in
-auto mode 3) Create a whiteout device or set opaque xattr to an existing
-directory if the parent directory was meregd or remove xattr if not.
+2) The origin directory should be redirected only once in one layer, which
+   means there is only one redirect xattr point to this origin directory in
+   the specified layer.
+3) There must be something with the same name to the rename origin in its
+   origin place, maybe a whiteout/file or a(an) opaque/redirect directory
+   covering the lower target, maybe a new created directory merging with
+   lower origin directory.
+
+If not,
+1) The redirect xattr is invalid and need to remove.
+2) One of the redirect xattr is redundant but not sure which one is, ask user
+   or warn in auto mode.
+3) Create a whiteout device if there nothing exists in its place. If the lower
+   targed was covered by a directory which is not an another redirect directory,
+   it could be created after rename in overlayfs or created in underlying
+   directory when overlay is offline, not sure this directory is merged or not,
+   ask user by default.
+
+If an invalid redirect xattr was removed by fsck and there is a corresponding
+lower directory with the same name exists, not sure this directory is merged
+or not, ask user to make a decision.
 
 Usage
 =====
diff --git a/check.c b/check.c
index 0b5d49b..6db41cd 100644
--- a/check.c
+++ b/check.c
@@ -152,12 +152,29 @@ static inline int ovl_create_whiteout(const char *pathname)
 	return ret;
 }
 
-static inline int ovl_ask_invalid(const char *question, const char *pathname,
-				  int action)
+static inline bool ovl_is_redirect(const char *pathname)
+{
+       bool exist = false;
+       ssize_t ret;
+
+       ret = get_xattr(pathname, OVL_REDIRECT_XATTR, NULL, &exist);
+       return ret ? false : exist;
+}
+
+static inline int ovl_ask_action(const char *description, const char *pathname,
+				 const char *question, int action)
+{
+	print_info(_("%s: %s "), description, pathname);
+
+	return ask_question(question, action);
+}
+
+static inline int ovl_ask_question(const char *question, const char *pathname,
+				   int action)
 {
 	print_info(_("%s: %s "), question, pathname);
 
-	return ask_question("Remove", action);
+	return ask_question("", action);
 }
 
 /*
@@ -233,7 +250,7 @@ remove:
 	sctx->i_whiteouts++;
 
 	/* Remove orphan whiteout directly or ask user */
-	if (!ovl_ask_invalid("Orphan whiteout", pathname, 1))
+	if (!ovl_ask_action("Orphan whiteout", pathname, "Remove", 1))
 		return 0;
 
 	ret = unlink(pathname);
@@ -323,15 +340,21 @@ static void ovl_redirect_free(void)
  * 2) Count how many directories the origin directory was redirected by.
  *    If more than one in the same layer, there must be some inconsistency
  *    but not sure which one is invalid, ask user or warn in auto mode.
- * 3) Check and fix the missing whiteout or opaque in redierct parent dir.
+ * 3) Check and fix the missing whiteout that covering the redirect lower
+ *    target. If the lower targed was covered by a directory which is not
+ *    an another redirect directory, it could be created after rename in
+ *    overlayfs or created in underlying directory when overlay is offline,
+ *    check opaque xattr and ask user by default.
+ * 4) When an invalid redirect xattr is removed, and the lower layers have
+ *    directory with same name, not sure this is a merged directory, ask
+ *    user by default.
  */
 static int ovl_check_redirect(struct scan_ctx *sctx)
 {
 	const char *pathname = sctx->pathname;
 	struct ovl_lower_check chk = {0};
-	char redirect_rpath[PATH_MAX];
 	struct stat rst;
-	char *redirect = NULL;
+	char *redirect = NULL, *cover_path = NULL;
 	int start;
 	int ret = 0;
 
@@ -345,8 +368,10 @@ static int ovl_check_redirect(struct scan_ctx *sctx)
 	sctx->t_redirects++;
 
 	/* Redirect dir in last lower dir ? */
-	if (sctx->dirtype == OVL_LOWER && sctx->num == lower_num-1)
+	if (sctx->dirtype == OVL_LOWER && sctx->num == lower_num-1) {
+		start = lower_num;
 		goto remove;
+	}
 
 	/* Scan lower directories to check redirect dir exist or not */
 	start = (sctx->dirtype == OVL_LOWER) ? sctx->num + 1 : 0;
@@ -359,14 +384,14 @@ static int ovl_check_redirect(struct scan_ctx *sctx)
 		/* Check duplicate in same layer */
 		if (ovl_redirect_entry_find(chk.path, sctx->dirtype,
 					    sctx->num, &tmp)) {
-			print_info("Duplicate redirect directories found:\n");
-			print_info("origin:%s current:%s last:%s\n",
-				   chk.path, pathname, tmp);
+			print_info("Duplicate redirect directory found:%s\n", pathname);
+			print_info("Origin:%s Previous:%s\n", chk.path, tmp);
 
 			sctx->i_redirects++;
 
 			/* Don't remove in auto mode */
-			if (ovl_ask_invalid("Duplicate redirect xattr", pathname, 0))
+			if (ovl_ask_action("Duplicate redirect xattr", pathname,
+					   "Remove", 0))
 				goto remove_d;
 		}
 
@@ -374,25 +399,32 @@ static int ovl_check_redirect(struct scan_ctx *sctx)
 				       sctx->num, chk.path);
 
 		/* Check and fix whiteout or opaque dir */
-		path_pack(redirect_rpath, sizeof(redirect_rpath),
-			  sctx->dirname, redirect);
-		if (lstat(redirect_rpath, &rst) != 0) {
+		cover_path = path_pack(cover_path, 0, sctx->dirname, redirect);
+		if (lstat(cover_path, &rst) != 0) {
 			if (errno != ENOENT && errno != ENOTDIR) {
 				print_err(_("Cannot stat %s: %s\n"),
-					    redirect_rpath, strerror(errno));
+					    cover_path, strerror(errno));
 				goto out;
 			}
 
 			/* Found nothing, create a whiteout */
-			if ((ret = ovl_create_whiteout(redirect_rpath)))
+			if ((ret = ovl_create_whiteout(cover_path)))
 				goto out;
 
 			sctx->t_whiteouts++;
 
-		} else if (is_dir(&rst) && !ovl_is_opaque(redirect_rpath)) {
-			/* Found a directory but not opaqued, fix opaque xattr */
-			if ((ret = ovl_set_opaque(redirect_rpath)))
-				goto out;
+		} else if (is_dir(&rst) && !ovl_is_opaque(cover_path) &&
+			   !ovl_is_redirect(cover_path)) {
+
+			/*
+			 * Found a directory but not opaqued and not even
+			 * an another redirected directory, maybe created
+			 * when overlayfs is offline, ask user to add the
+			 * opaque xattr if this is not a merged dir.
+			 */
+			if (!ovl_ask_question("Is merged dir", cover_path, 1))
+				if ((ret = ovl_set_opaque(cover_path)))
+					goto out;
 		}
 
 		goto out;
@@ -402,13 +434,25 @@ remove:
 	sctx->i_redirects++;
 
 	/* Remove redirect xattr or ask user */
-	if (!ovl_ask_invalid("Invalid redirect xattr", pathname, 1))
+	if (!ovl_ask_action("Invalid redirect xattr", pathname, "Remove", 1))
 		goto out;
 remove_d:
-	ret = ovl_remove_redirect(pathname);
-	if (!ret)
-		sctx->i_redirects--;
+	if ((ret = ovl_remove_redirect(pathname)))
+		goto out;
+
+	sctx->i_redirects--;
+
+	/* If lower directory exist, ask user to add opaque xattr to cover it */
+	if (start < lower_num) {
+		if ((ret = ovl_check_lower(path_pick(pathname, sctx->dirlen),
+					   start, &chk, false)))
+			goto out;
+		if (chk.exist && is_dir(&chk.st) &&
+		    !ovl_ask_question("Is merged dir", pathname, 1))
+			ret = ovl_set_opaque(pathname);
+	}
 out:
+	free(cover_path);
 	free(redirect);
 	return ret;
 }
-- 
2.9.5

--
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