Overlayfs can now work on filesystems that support casefolding, provided
the specific subtree overlayfs is using as layers don't have casefolding
enabled.

d_casefold_disabled_get() and put() are used, which check that
casefolding is enabled nowhere on a given subtree, and get and release a
reference that prevents the filesystem from enabling casefolding on that
tree while overlayfs is in use.

We also now check the new SB_CASEFOLD superblock flag; if it's set we
allow for dcache hash and compare ops to be set, relying instead on the
new dcache methods.

Cc: Miklos Szeredi <[email protected]>
Cc: Amir Goldstein <[email protected]>
Cc: [email protected]
Signed-off-by: Kent Overstreet <[email protected]>
---
 fs/overlayfs/params.c | 20 +++++++++++++++++---
 fs/overlayfs/util.c   | 19 +++++++++++++++----
 2 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c
index 6759f7d040c8..ae7424e075a7 100644
--- a/fs/overlayfs/params.c
+++ b/fs/overlayfs/params.c
@@ -287,7 +287,8 @@ static int ovl_mount_dir_check(struct fs_context *fc, const 
struct path *path,
         * with overlayfs.  Check explicitly to prevent post-mount
         * failures.
         */
-       if (sb_has_encoding(path->mnt->mnt_sb))
+       if ((path->mnt->mnt_sb->s_flags & SB_CASEFOLD) &&
+           !(path->dentry->d_inode->i_flags & S_NO_CASEFOLD))
                return invalfc(fc, "case-insensitive capable filesystem on %s 
not supported", name);
 
        if (ovl_dentry_weird(path->dentry))
@@ -411,20 +412,32 @@ static int ovl_do_parse_layer(struct fs_context *fc, 
const char *layer_name,
        if (!name)
                return -ENOMEM;
 
+       if (layer != Opt_workdir &&
+           layer != Opt_upperdir) {
+               err = d_casefold_disabled_get(layer_path->dentry);
+               if (err)
+                       return err;
+       }
+
        upper = is_upper_layer(layer);
        err = ovl_mount_dir_check(fc, layer_path, layer, name, upper);
        if (err)
-               return err;
+               goto err_put;
 
        if (!upper) {
                err = ovl_ctx_realloc_lower(fc);
                if (err)
-                       return err;
+                       goto err_put;
        }
 
        /* Store the user provided path string in ctx to show in mountinfo */
        ovl_add_layer(fc, layer, layer_path, &name);
        return err;
+err_put:
+       if (layer != Opt_workdir &&
+           layer != Opt_upperdir)
+               d_casefold_disabled_put(layer_path->dentry);
+       return err;
 }
 
 static int ovl_parse_layer(struct fs_context *fc, struct fs_parameter *param,
@@ -475,6 +488,7 @@ static void ovl_reset_lowerdirs(struct ovl_fs_context *ctx)
        ctx->lowerdir_all = NULL;
 
        for (size_t nr = 0; nr < ctx->nr; nr++, l++) {
+               d_casefold_disabled_put(l->path.dentry);
                path_put(&l->path);
                kfree(l->name);
                l->name = NULL;
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 0819c739cc2f..c515f260032c 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -205,10 +205,21 @@ bool ovl_dentry_weird(struct dentry *dentry)
        if (!d_can_lookup(dentry) && !d_is_file(dentry) && 
!d_is_symlink(dentry))
                return true;
 
-       return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT |
-                                 DCACHE_MANAGE_TRANSIT |
-                                 DCACHE_OP_HASH |
-                                 DCACHE_OP_COMPARE);
+       if (dentry->d_flags & (DCACHE_NEED_AUTOMOUNT |
+                              DCACHE_MANAGE_TRANSIT))
+               return true;
+
+       /*
+        * The filesystem might support casefolding, but we've already checked
+        * that casefolding isn't present on this tree: we only need to check
+        * for non-casefolding hash/compare ops
+        */
+       if (!(dentry->d_sb->s_flags & SB_CASEFOLD) &&
+           (dentry->d_flags & (DCACHE_OP_HASH |
+                               DCACHE_OP_COMPARE)))
+               return true;
+
+       return false;
 }
 
 enum ovl_path_type ovl_path_type(struct dentry *dentry)
-- 
2.49.0


Reply via email to