ovl: automatically enable redirect_dir on metacopy=on
authorMiklos Szeredi <mszeredi@redhat.com>
Thu, 1 Nov 2018 20:31:39 +0000 (21:31 +0100)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 1 Nov 2018 20:31:39 +0000 (21:31 +0100)
Current behavior is to automatically disable metacopy if redirect_dir is
not enabled and proceed with the mount.

If "metacopy=on" mount option was given, then this behavior can confuse the
user: no mount failure, yet metacopy is disabled.

This patch makes metacopy=on imply redirect_dir=on.

The converse is also true: turning off full redirect with redirect_dir=
{off|follow|nofollow} will disable metacopy.

If both metacopy=on and redirect_dir={off|follow|nofollow} is specified,
then mount will fail, since there's no way to correctly resolve the
conflict.

Reported-by: Daniel Walsh <dwalsh@redhat.com>
Fixes: d5791044d2e5 ("ovl: Provide a mount option metacopy=on/off...")
Cc: <stable@vger.kernel.org> # v4.19
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Documentation/filesystems/overlayfs.txt
fs/overlayfs/super.c

index 51c136c821bfb0a190e7daa67ebdc2e6faaf878b..eef7d9d259e8570d102be8c7f1641158950262c2 100644 (file)
@@ -286,6 +286,12 @@ pointed by REDIRECT. This should not be possible on local system as setting
 "trusted." xattrs will require CAP_SYS_ADMIN. But it should be possible
 for untrusted layers like from a pen drive.
 
+Note: redirect_dir={off|nofollow|follow(*)} conflicts with metacopy=on, and
+results in an error.
+
+(*) redirect_dir=follow only conflicts with metacopy=on if upperdir=... is
+given.
+
 Sharing and copying layers
 --------------------------
 
index 22ffb23ea44d96cf81edbe304b8fb583b0046254..0116735cc32147ca3972275e2baa8a52d296f63f 100644 (file)
@@ -472,6 +472,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
 {
        char *p;
        int err;
+       bool metacopy_opt = false, redirect_opt = false;
 
        config->redirect_mode = kstrdup(ovl_redirect_mode_def(), GFP_KERNEL);
        if (!config->redirect_mode)
@@ -516,6 +517,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
                        config->redirect_mode = match_strdup(&args[0]);
                        if (!config->redirect_mode)
                                return -ENOMEM;
+                       redirect_opt = true;
                        break;
 
                case OPT_INDEX_ON:
@@ -548,6 +550,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
 
                case OPT_METACOPY_ON:
                        config->metacopy = true;
+                       metacopy_opt = true;
                        break;
 
                case OPT_METACOPY_OFF:
@@ -572,13 +575,32 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
        if (err)
                return err;
 
-       /* metacopy feature with upper requires redirect_dir=on */
-       if (config->upperdir && config->metacopy && !config->redirect_dir) {
-               pr_warn("overlayfs: metadata only copy up requires \"redirect_dir=on\", falling back to metacopy=off.\n");
-               config->metacopy = false;
-       } else if (config->metacopy && !config->redirect_follow) {
-               pr_warn("overlayfs: metadata only copy up requires \"redirect_dir=follow\" on non-upper mount, falling back to metacopy=off.\n");
-               config->metacopy = false;
+       /*
+        * This is to make the logic below simpler.  It doesn't make any other
+        * difference, since config->redirect_dir is only used for upper.
+        */
+       if (!config->upperdir && config->redirect_follow)
+               config->redirect_dir = true;
+
+       /* Resolve metacopy -> redirect_dir dependency */
+       if (config->metacopy && !config->redirect_dir) {
+               if (metacopy_opt && redirect_opt) {
+                       pr_err("overlayfs: conflicting options: metacopy=on,redirect_dir=%s\n",
+                              config->redirect_mode);
+                       return -EINVAL;
+               }
+               if (redirect_opt) {
+                       /*
+                        * There was an explicit redirect_dir=... that resulted
+                        * in this conflict.
+                        */
+                       pr_info("overlayfs: disabling metacopy due to redirect_dir=%s\n",
+                               config->redirect_mode);
+                       config->metacopy = false;
+               } else {
+                       /* Automatically enable redirect otherwise. */
+                       config->redirect_follow = config->redirect_dir = true;
+               }
        }
 
        return 0;