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
> 
> 

Reply via email to