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 <miklos@xxxxxxxxxx> Cc: Amir Goldstein <amir73il@xxxxxxxxx> Cc: linux-unionfs@xxxxxxxxxxxxxxx Signed-off-by: Kent Overstreet <kent.overstreet@xxxxxxxxx> --- 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