Re: [PATCH v5] erofs: accept source file descriptor via fsconfig

Chao Yu <[email protected]> Mon, 3 Aug 2026 19:24:07 +0800
Newsgroups org.ozlabs.lists.linux-erofs,org.kernel.vger.linux-fsdevel
Message-ID <[email protected]>
On 7/29/26 00:05, Giuseppe Scrivano wrote:
> Allow userspace to pass an already-opened file descriptor as the mount
> source instead of a path string.  This is useful for tools that already
> hold an fd to the image, such as composefs reusing an existing erofs
> backing file.
> 
> Signed-off-by: Giuseppe Scrivano <[email protected]>
> ---
> v4: https://lore.kernel.org/linux-fsdevel/[email protected]/
> v3: https://lore.kernel.org/linux-fsdevel/[email protected]/
> v2: https://lore.kernel.org/linux-fsdevel/[email protected]/
> v1: https://lore.kernel.org/linux-fsdevel/ak5GfvVfWLJU1EwK@debian/
> 
>   Documentation/filesystems/erofs.rst | 15 ++++++
>   fs/erofs/super.c                    | 73 ++++++++++++++++++++++++-----
>   2 files changed, 77 insertions(+), 11 deletions(-)
> 
> diff --git a/Documentation/filesystems/erofs.rst b/Documentation/filesystems/erofs.rst
> index 4230884fb359..774e8b236d09 100644
> --- a/Documentation/filesystems/erofs.rst
> +++ b/Documentation/filesystems/erofs.rst
> @@ -139,6 +139,21 @@ inode_share            Enable inode page sharing for this filesystem.  Inodes wi
>                          page cache.
>   ===================    =========================================================
>   
> +File-backed mounts
> +==================
> +
> +When CONFIG_EROFS_FS_BACKED_BY_FILE is enabled, EROFS file-backed images
> +can be mounted directly without a loopback block device.  The backing file
> +can be given either as a path, or as an already-opened file descriptor.
> +
> +When a file descriptor is used, the kernel resolves its path and records it
> +so that /proc/mounts and similar interfaces can still report the mount
> +source.
> +
> +Only regular files are accepted as backing files; to mount an image that
> +resides on a block device, use the traditional block device mount path
> +instead.

Do we need to add an entry to describe the new mount option source= in
"Mount options" section in erofs.rst?

Thanks,

> +
>   Sysfs Entries
>   =============
>   
> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> index 86fa5c6a0c70..558041011398 100644
> --- a/fs/erofs/super.c
> +++ b/fs/erofs/super.c
> @@ -386,6 +386,7 @@ static void erofs_default_options(struct erofs_sb_info *sbi)
>   enum {
>   	Opt_user_xattr, Opt_acl, Opt_cache_strategy, Opt_dax, Opt_dax_enum,
>   	Opt_device, Opt_domain_id, Opt_directio, Opt_fsoffset, Opt_inode_share,
> +	Opt_source,
>   };
>   
>   static const struct constant_table erofs_param_cache_strategy[] = {
> @@ -402,17 +403,18 @@ static const struct constant_table erofs_dax_param_enums[] = {
>   };
>   
>   static const struct fs_parameter_spec erofs_fs_parameters[] = {
> -	fsparam_flag_no("user_xattr",	Opt_user_xattr),
> -	fsparam_flag_no("acl",		Opt_acl),
> -	fsparam_enum("cache_strategy",	Opt_cache_strategy,
> +	fsparam_flag_no("user_xattr",		Opt_user_xattr),
> +	fsparam_flag_no("acl",			Opt_acl),
> +	fsparam_enum("cache_strategy",		Opt_cache_strategy,
>   		     erofs_param_cache_strategy),
> -	fsparam_flag("dax",             Opt_dax),
> -	fsparam_enum("dax",		Opt_dax_enum, erofs_dax_param_enums),
> -	fsparam_string("device",	Opt_device),
> -	fsparam_string("domain_id",	Opt_domain_id),
> -	fsparam_flag_no("directio",	Opt_directio),
> -	fsparam_u64("fsoffset",		Opt_fsoffset),
> -	fsparam_flag("inode_share",	Opt_inode_share),
> +	fsparam_flag("dax",			Opt_dax),
> +	fsparam_enum("dax",			Opt_dax_enum, erofs_dax_param_enums),
> +	fsparam_string("device",		Opt_device),
> +	fsparam_string("domain_id",		Opt_domain_id),
> +	fsparam_flag_no("directio",		Opt_directio),
> +	fsparam_u64("fsoffset",			Opt_fsoffset),
> +	fsparam_flag("inode_share",		Opt_inode_share),
> +	fsparam_file_or_string("source",	Opt_source),
>   	{}
>   };
>   
> @@ -437,6 +439,40 @@ static bool erofs_fc_set_dax_mode(struct fs_context *fc, unsigned int mode)
>   	return false;
>   }
>   
> +static int erofs_fc_parse_source(struct fs_context *fc,
> +				 struct fs_parameter *param)
> +{
> +	struct erofs_sb_info *sbi = fc->s_fs_info;
> +
> +	if (fc->source || sbi->dif0.file)
> +		return invalf(fc, "Multiple sources");
> +
> +	switch (param->type) {
> +	case fs_value_is_string:
> +		fc->source = param->string;
> +		param->string = NULL;
> +		return 0;
> +	case fs_value_is_file: {
> +		char *buf __free(kfree) = kmalloc(PATH_MAX, GFP_KERNEL);
> +		char *p;
> +
> +		if (!buf)
> +			return -ENOMEM;
> +		p = file_path(param->file, buf, PATH_MAX);
> +		if (IS_ERR(p))
> +			return PTR_ERR(p);
> +		fc->source = kstrdup(p, GFP_KERNEL);
> +		if (!fc->source)
> +			return -ENOMEM;
> +		sbi->dif0.file = no_free_ptr(param->file);
> +		return 0;
> +	}
> +	default:
> +		WARN_ON_ONCE(true);
> +		return -EINVAL;
> +	}
> +}
> +
>   static int erofs_fc_parse_param(struct fs_context *fc,
>   				struct fs_parameter *param)
>   {
> @@ -524,6 +560,8 @@ static int erofs_fc_parse_param(struct fs_context *fc,
>   		else
>   			set_opt(&sbi->opt, INODE_SHARE);
>   		break;
> +	case Opt_source:
> +		return erofs_fc_parse_source(fc, param);
>   	}
>   	return 0;
>   }
> @@ -752,13 +790,26 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
>   
>   static int erofs_fc_get_tree(struct fs_context *fc)
>   {
> +	struct erofs_sb_info *sbi = fc->s_fs_info;
>   	int ret;
>   
> +	if (sbi->dif0.file) {
> +		if (!IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE)) {
> +			errorfc(fc, "source fd option not supported");
> +			return -EINVAL;
> +		}
> +		if (!S_ISREG(file_inode(sbi->dif0.file)->i_mode) ||
> +		    !sbi->dif0.file->f_mapping->a_ops->read_folio) {
> +			errorfc(fc, "source is unsupported");
> +			return -EINVAL;
> +		}
> +		return get_tree_nodev(fc, erofs_fc_fill_super);
> +	}
> +
>   	ret = get_tree_bdev_flags(fc, erofs_fc_fill_super,
>   		IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) ?
>   			GET_TREE_BDEV_QUIET_LOOKUP : 0);
>   	if (IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) && ret == -ENOTBLK) {
> -		struct erofs_sb_info *sbi = fc->s_fs_info;
>   		struct file *file;
>   
>   		if (!fc->source)