mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
erofs: accept source file descriptor via fsconfig
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 <gscrivan@redhat.com> Reviewed-by: Gao Xiang <xiang@kernel.org> Reviewed-by: Christian Brauner (Amutable) <brauner@kernel.org> Acked-by: Jan Kara <jack@suse.cz> Reviewed-by: Chao Yu <chao@kernel.org> Signed-off-by: Gao Xiang <xiang@kernel.org>
This commit is contained in:
parent
9ba8471dab
commit
058884d234
|
|
@ -137,8 +137,25 @@ fsoffset=%llu Specify block-aligned filesystem offset for the primary d
|
|||
inode_share Enable inode page sharing for this filesystem. Inodes with
|
||||
identical content within the same domain ID can share the
|
||||
page cache.
|
||||
source=%s (For file-backed mounts) Specify the backing image as a path
|
||||
or as an already-opened file descriptor.
|
||||
=================== =========================================================
|
||||
|
||||
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.
|
||||
|
||||
Sysfs Entries
|
||||
=============
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -743,13 +781,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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user