Re: [PATCH 1/2] erofs: accept source file descriptor via fsconfig

Gao Xiang <[email protected]> Wed, 8 Jul 2026 20:45:50 +0800
Newsgroups org.kernel.vger.linux-api,org.kernel.vger.linux-fsdevel,org.ozlabs.lists.linux-erofs
Message-ID <ak5GfvVfWLJU1EwK@debian>
Hi Giuseppe,

On Wed, Jul 08, 2026 at 11:34:26AM +0200, Giuseppe Scrivano wrote:
> Add fsparam_fd("source") so that userspace can pass an already-opened
> file descriptor instead of a path string.  When the fd is provided via
> fsconfig(FSCONFIG_SET_FD, "source", NULL, fd), it is stored directly
> in sbi->dif0.file and erofs_fc_get_tree() skips the filp_open() call.
> 
> This is useful for mount namespaces where the backing file may not be
> reachable by path, and for tools that already hold an fd to the image
> (e.g. composefs reusing an erofs mount's backing file).
> 
> Signed-off-by: Giuseppe Scrivano <[email protected]>
> ---
>  fs/erofs/super.c | 36 +++++++++++++++++++++++++-----------
>  1 file changed, 25 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> index 86fa5c6a0c70..8ad1689f74b2 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_fd,
>  };
>  
>  static const struct constant_table erofs_param_cache_strategy[] = {
> @@ -413,6 +414,7 @@ static const struct fs_parameter_spec erofs_fs_parameters[] = {
>  	fsparam_flag_no("directio",	Opt_directio),
>  	fsparam_u64("fsoffset",		Opt_fsoffset),
>  	fsparam_flag("inode_share",	Opt_inode_share),
> +	fsparam_fd("source",		Opt_source_fd),
>  	{}
>  };
>  
> @@ -524,6 +526,15 @@ static int erofs_fc_parse_param(struct fs_context *fc,
>  		else
>  			set_opt(&sbi->opt, INODE_SHARE);
>  		break;
> +	case Opt_source_fd:
> +		if (!IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE)) {
> +			errorfc(fc, "source fd option not supported");

Thanks for the patch!
For this commit, it looks good to me overall, just some nits:

I guess we could just move this one into erofs_fc_get_tree(), see below.

> +			return -EINVAL;
> +		}
> +		if (sbi->dif0.file)

Do we need to allow multi-shot source_fd?

I guess we could just bail out directly instead.

> +			fput(sbi->dif0.file);
> +		sbi->dif0.file = get_file(param->file);
> +		break;
>  	}
>  	return 0;
>  }
> @@ -752,14 +763,18 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
>  
>  static int erofs_fc_get_tree(struct fs_context *fc)
>  {
> -	int ret;
> +	struct erofs_sb_info *sbi = fc->s_fs_info;

Nit:

	struct file *file = sbi->dif0.file;

>  
> -	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;
> +	if (!IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) || !sbi->dif0.file) {

	if (!IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) || !file) {

>  		struct file *file;
> +		int ret;
> +
> +		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)
> +			return ret;
>  
>  		if (!fc->source)
>  			return invalf(fc, "No source specified");
> @@ -767,12 +782,11 @@ static int erofs_fc_get_tree(struct fs_context *fc)
>  		if (IS_ERR(file))
>  			return PTR_ERR(file);
>  		sbi->dif0.file = file;
> -
> -		if (S_ISREG(file_inode(sbi->dif0.file)->i_mode) &&
> -		    sbi->dif0.file->f_mapping->a_ops->read_folio)
> -			return get_tree_nodev(fc, erofs_fc_fill_super);
>  	}
> -	return ret;
> +	if (S_ISREG(file_inode(sbi->dif0.file)->i_mode) &&
> +	    sbi->dif0.file->f_mapping->a_ops->read_folio)
> +		return get_tree_nodev(fc, erofs_fc_fill_super);
> +	return -EINVAL;

Currently we don't support bdev-backed mounts for this, so I'm fine to
support file-backed mounts only for now.

So nit:

	if (!S_ISREG(file_inode(file)->i_mode) ||
	    !file->f_mapping->a_ops->read_folio) {
		errorfc(fc, "source is unsupported");
		return -EINVAL;
	}
	return get_tree_nodev(fc, erofs_fc_fill_super);

Thanks,
Gao Xiang

>  }
>  
>  static int erofs_fc_reconfigure(struct fs_context *fc)
> -- 
> 2.55.0
> 
>