Re: [PATCH v3] ovl: support layers on case-folding capable filesystems

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

 



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
> 




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux