On Mon, Jun 02, 2025 at 07:17:02PM +0200, Amir Goldstein wrote: > Case folding is often applied to subtrees and not on an entire > filesystem. > > Disallowing layers from filesystems that support case folding is over > limiting. > > Replace the rule that case-folding capable are not allowed as layers > with a rule that case folded directories are not allowed in a merged > directory stack. > > Should case folding be enabled on an underlying directory while > overlayfs is mounted the outcome is generally undefined. > > Specifically in ovl_lookup(), we check the base underlying directory > and fail with -ESTALE and write a warning to kmsg if an underlying > directory case folding is enabled. > > Suggested-by: Kent Overstreet <kent.overstreet@xxxxxxxxx> > Link: https://lore.kernel.org/linux-fsdevel/20250520051600.1903319-1-kent.overstreet@xxxxxxxxx/ > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> > --- > > Miklos, > > This is my solution to Kent's request to allow overlayfs mount on > bcachefs subtrees that do not have casefolding enabled, while other > subtrees do have casefolding enabled. > > I have written a test to cover the change of behavior [1]. > This test does not run on old kernel's where the mount always fails > with casefold capable layers. > > Let me know what you think. > > Kent, > > I have tested this on ext4. > Please test on bcachefs. This one fails with the proper error message in dmesg, and no other errors :) Reviewed-by: Kent Overstreet <kent.overstreet@xxxxxxxxx> > > Thanks, > Amir. > > Changes since v1,v2: > - Add ratelimited warnings for the lookup error cases > - Add helper ovl_dentry_casefolded() > - Write fstest [1] > > [1] https://github.com/amir73il/xfstests/commits/ovl-casefold/ > > fs/overlayfs/namei.c | 31 ++++++++++++++++++++++++++++--- > fs/overlayfs/overlayfs.h | 6 ++++++ > fs/overlayfs/params.c | 10 ++++------ > fs/overlayfs/util.c | 15 +++++++++++---- > 4 files changed, 49 insertions(+), 13 deletions(-) > > diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c > index d489e80feb6f..733beef7b810 100644 > --- a/fs/overlayfs/namei.c > +++ b/fs/overlayfs/namei.c > @@ -230,13 +230,26 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, > struct dentry **ret, bool drop_negative) > { > struct ovl_fs *ofs = OVL_FS(d->sb); > - struct dentry *this; > + struct dentry *this = NULL; > + const char *warn; > struct path path; > int err; > bool last_element = !post[0]; > bool is_upper = d->layer->idx == 0; > char val; > > + /* > + * We allow filesystems that are case-folding capable but deny composing > + * ovl stack from case-folded directories. If someone has enabled case > + * folding on a directory on underlying layer, the warranty of the ovl > + * stack is voided. > + */ > + if (ovl_dentry_casefolded(base)) { > + warn = "case folded parent"; > + err = -ESTALE; > + goto out_warn; > + } > + > this = ovl_lookup_positive_unlocked(d, name, base, namelen, drop_negative); > if (IS_ERR(this)) { > err = PTR_ERR(this); > @@ -246,10 +259,17 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, > goto out_err; > } > > + if (ovl_dentry_casefolded(this)) { > + warn = "case folded child"; > + err = -EREMOTE; > + goto out_warn; > + } > + > if (ovl_dentry_weird(this)) { > /* Don't support traversing automounts and other weirdness */ > + warn = "unsupported object type"; > err = -EREMOTE; > - goto out_err; > + goto out_warn; > } > > path.dentry = this; > @@ -283,8 +303,9 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, > } else { > if (ovl_lookup_trap_inode(d->sb, this)) { > /* Caught in a trap of overlapping layers */ > + warn = "overlapping layers"; > err = -ELOOP; > - goto out_err; > + goto out_warn; > } > > if (last_element) > @@ -316,6 +337,10 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, > this = NULL; > goto out; > > +out_warn: > + pr_warn_ratelimited("failed lookup in %s (%pd2, name='%.*s', err=%i): %s\n", > + is_upper ? "upper" : "lower", base, > + namelen, name, err, warn); > out_err: > dput(this); > return err; > diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h > index aef942a758ce..6c51103d9305 100644 > --- a/fs/overlayfs/overlayfs.h > +++ b/fs/overlayfs/overlayfs.h > @@ -446,6 +446,12 @@ void ovl_dentry_init_reval(struct dentry *dentry, struct dentry *upperdentry, > void ovl_dentry_init_flags(struct dentry *dentry, struct dentry *upperdentry, > struct ovl_entry *oe, unsigned int mask); > bool ovl_dentry_weird(struct dentry *dentry); > + > +static inline bool ovl_dentry_casefolded(struct dentry *dentry) > +{ > + return sb_has_encoding(dentry->d_sb) && IS_CASEFOLDED(d_inode(dentry)); > +} > + > enum ovl_path_type ovl_path_type(struct dentry *dentry); > void ovl_path_upper(struct dentry *dentry, struct path *path); > void ovl_path_lower(struct dentry *dentry, struct path *path); > diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c > index f42488c01957..2b9b31524c38 100644 > --- a/fs/overlayfs/params.c > +++ b/fs/overlayfs/params.c > @@ -282,13 +282,11 @@ static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path, > return invalfc(fc, "%s is not a directory", name); > > /* > - * Root dentries of case-insensitive capable filesystems might > - * not have the dentry operations set, but still be incompatible > - * with overlayfs. Check explicitly to prevent post-mount > - * failures. > + * Allow filesystems that are case-folding capable but deny composing > + * ovl stack from case-folded directories. > */ > - if (sb_has_encoding(path->mnt->mnt_sb)) > - return invalfc(fc, "case-insensitive capable filesystem on %s not supported", name); > + if (ovl_dentry_casefolded(path->dentry)) > + return invalfc(fc, "case-insensitive directory on %s not supported", name); > > if (ovl_dentry_weird(path->dentry)) > return invalfc(fc, "filesystem on %s not supported", name); > diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c > index dcccb4b4a66c..593c4da107d6 100644 > --- a/fs/overlayfs/util.c > +++ b/fs/overlayfs/util.c > @@ -206,10 +206,17 @@ 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; > + > + /* > + * Allow filesystems that are case-folding capable but deny composing > + * ovl stack from case-folded directories. > + */ > + if (sb_has_encoding(dentry->d_sb)) > + return IS_CASEFOLDED(d_inode(dentry)); > + > + return dentry->d_flags & (DCACHE_OP_HASH | DCACHE_OP_COMPARE); > } > > enum ovl_path_type ovl_path_type(struct dentry *dentry) > -- > 2.34.1 >