Merge 24e16e385f ("ovl: add support for appending lowerdirs one by one") into android-mainline
Steps on the way to 6.7-rc1 Change-Id: Ie9eacc88192aafcfe21e15720836ee8f2ce06c08 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -368,10 +368,11 @@ escaping the colons with a single backslash. For example:
|
||||
|
||||
mount -t overlay overlay -olowerdir=/a\:lower\:\:dir /merged
|
||||
|
||||
Since kernel version v6.5, directory names containing colons can also
|
||||
be provided as lower layer using the fsconfig syscall from new mount api:
|
||||
Since kernel version v6.8, directory names containing colons can also
|
||||
be configured as lower layer using the "lowerdir+" mount options and the
|
||||
fsconfig syscall from new mount api. For example:
|
||||
|
||||
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir", "/a:lower::dir", 0);
|
||||
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/a:lower::dir", 0);
|
||||
|
||||
In the latter case, colons in lower layer directory names will be escaped
|
||||
as an octal characters (\072) when displayed in /proc/self/mountinfo.
|
||||
@@ -440,6 +441,16 @@ Only the data of the files in the "data-only" lower layers may be visible
|
||||
when a "metacopy" file in one of the lower layers above it, has a "redirect"
|
||||
to the absolute path of the "lower data" file in the "data-only" lower layer.
|
||||
|
||||
Since kernel version v6.8, "data-only" lower layers can also be added using
|
||||
the "datadir+" mount options and the fsconfig syscall from new mount api.
|
||||
For example:
|
||||
|
||||
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l1", 0);
|
||||
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l2", 0);
|
||||
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l3", 0);
|
||||
fsconfig(fs_fd, FSCONFIG_SET_STRING, "datadir+", "/do1", 0);
|
||||
fsconfig(fs_fd, FSCONFIG_SET_STRING, "datadir+", "/do2", 0);
|
||||
|
||||
|
||||
fs-verity support
|
||||
----------------------
|
||||
|
||||
+76
-2
@@ -50,6 +50,8 @@ MODULE_PARM_DESC(ovl_override_creds_def,
|
||||
|
||||
enum ovl_opt {
|
||||
Opt_lowerdir,
|
||||
Opt_lowerdir_add,
|
||||
Opt_datadir_add,
|
||||
Opt_upperdir,
|
||||
Opt_workdir,
|
||||
Opt_default_permissions,
|
||||
@@ -146,8 +148,11 @@ static int ovl_verity_mode_def(void)
|
||||
#define fsparam_string_empty(NAME, OPT) \
|
||||
__fsparam(fs_param_is_string, NAME, OPT, fs_param_can_be_empty, NULL)
|
||||
|
||||
|
||||
const struct fs_parameter_spec ovl_parameter_spec[] = {
|
||||
fsparam_string_empty("lowerdir", Opt_lowerdir),
|
||||
fsparam_string("lowerdir+", Opt_lowerdir_add),
|
||||
fsparam_string("datadir+", Opt_datadir_add),
|
||||
fsparam_string("upperdir", Opt_upperdir),
|
||||
fsparam_string("workdir", Opt_workdir),
|
||||
fsparam_flag("default_permissions", Opt_default_permissions),
|
||||
@@ -280,12 +285,15 @@ static int ovl_mount_dir(const char *name, struct path *path)
|
||||
static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
|
||||
enum ovl_opt layer, const char *name, bool upper)
|
||||
{
|
||||
struct ovl_fs_context *ctx = fc->fs_private;
|
||||
|
||||
if (ovl_dentry_weird(path->dentry))
|
||||
return invalfc(fc, "filesystem on %s not supported", name);
|
||||
|
||||
if (!d_is_dir(path->dentry))
|
||||
return invalfc(fc, "%s is not a directory", name);
|
||||
|
||||
|
||||
/*
|
||||
* Check whether upper path is read-only here to report failures
|
||||
* early. Don't forget to recheck when the superblock is created
|
||||
@@ -296,16 +304,45 @@ static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
|
||||
return invalfc(fc, "filesystem on %s not supported as upperdir", name);
|
||||
if (__mnt_is_readonly(path->mnt))
|
||||
return invalfc(fc, "filesystem on %s is read-only", name);
|
||||
} else {
|
||||
if (ctx->lowerdir_all && layer != Opt_lowerdir)
|
||||
return invalfc(fc, "lowerdir+ and datadir+ cannot follow lowerdir");
|
||||
if (ctx->nr_data && layer == Opt_lowerdir_add)
|
||||
return invalfc(fc, "regular lower layers cannot follow data layers");
|
||||
if (ctx->nr == OVL_MAX_STACK)
|
||||
return invalfc(fc, "too many lower directories, limit is %d",
|
||||
OVL_MAX_STACK);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ovl_ctx_realloc_lower(struct fs_context *fc)
|
||||
{
|
||||
struct ovl_fs_context *ctx = fc->fs_private;
|
||||
struct ovl_fs_context_layer *l;
|
||||
size_t nr;
|
||||
|
||||
if (ctx->nr < ctx->capacity)
|
||||
return 0;
|
||||
|
||||
nr = min_t(size_t, max(4096 / sizeof(*l), ctx->capacity * 2),
|
||||
OVL_MAX_STACK);
|
||||
l = krealloc_array(ctx->lower, nr, sizeof(*l), GFP_KERNEL_ACCOUNT);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->lower = l;
|
||||
ctx->capacity = nr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ovl_add_layer(struct fs_context *fc, enum ovl_opt layer,
|
||||
struct path *path, char **pname)
|
||||
{
|
||||
struct ovl_fs *ofs = fc->s_fs_info;
|
||||
struct ovl_config *config = &ofs->config;
|
||||
struct ovl_fs_context *ctx = fc->fs_private;
|
||||
struct ovl_fs_context_layer *l;
|
||||
|
||||
switch (layer) {
|
||||
case Opt_workdir:
|
||||
@@ -316,6 +353,16 @@ static void ovl_add_layer(struct fs_context *fc, enum ovl_opt layer,
|
||||
swap(config->upperdir, *pname);
|
||||
swap(ctx->upper, *path);
|
||||
break;
|
||||
case Opt_datadir_add:
|
||||
ctx->nr_data++;
|
||||
fallthrough;
|
||||
case Opt_lowerdir_add:
|
||||
WARN_ON(ctx->nr >= ctx->capacity);
|
||||
l = &ctx->lower[ctx->nr++];
|
||||
memset(l, 0, sizeof(*l));
|
||||
swap(l->name, *pname);
|
||||
swap(l->path, *path);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
@@ -332,7 +379,10 @@ static int ovl_parse_layer(struct fs_context *fc, struct fs_parameter *param,
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
err = ovl_mount_dir(name, &path);
|
||||
if (upper)
|
||||
err = ovl_mount_dir(name, &path);
|
||||
else
|
||||
err = ovl_mount_dir_noesc(name, &path);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
@@ -340,6 +390,12 @@ static int ovl_parse_layer(struct fs_context *fc, struct fs_parameter *param,
|
||||
if (err)
|
||||
goto out_put;
|
||||
|
||||
if (!upper) {
|
||||
err = ovl_ctx_realloc_lower(fc);
|
||||
if (err)
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
/* Store the user provided path string in ctx to show in mountinfo */
|
||||
ovl_add_layer(fc, layer, &path, &name);
|
||||
|
||||
@@ -526,6 +582,8 @@ static int ovl_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
case Opt_lowerdir:
|
||||
err = ovl_parse_param_lowerdir(param->string, fc);
|
||||
break;
|
||||
case Opt_lowerdir_add:
|
||||
case Opt_datadir_add:
|
||||
case Opt_upperdir:
|
||||
case Opt_workdir:
|
||||
err = ovl_parse_layer(fc, param, opt);
|
||||
@@ -904,13 +962,29 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry)
|
||||
{
|
||||
struct super_block *sb = dentry->d_sb;
|
||||
struct ovl_fs *ofs = OVL_FS(sb);
|
||||
size_t nr, nr_merged_lower, nr_lower = 0;
|
||||
char **lowerdirs = ofs->config.lowerdirs;
|
||||
|
||||
/*
|
||||
* lowerdirs[0] holds the colon separated list that user provided
|
||||
* with lowerdir mount option.
|
||||
* lowerdirs[1..numlayer] hold the lowerdir paths that were added
|
||||
* using the lowerdir+ and datadir+ mount options.
|
||||
* For now, we do not allow mixing the legacy lowerdir mount option
|
||||
* with the new lowerdir+ and datadir+ mount options.
|
||||
*/
|
||||
seq_show_option(m, "lowerdir", lowerdirs[0]);
|
||||
if (lowerdirs[0]) {
|
||||
seq_show_option(m, "lowerdir", lowerdirs[0]);
|
||||
} else {
|
||||
nr_lower = ofs->numlayer;
|
||||
nr_merged_lower = nr_lower - ofs->numdatalayer;
|
||||
}
|
||||
for (nr = 1; nr < nr_lower; nr++) {
|
||||
if (nr < nr_merged_lower)
|
||||
seq_show_option(m, "lowerdir+", lowerdirs[nr]);
|
||||
else
|
||||
seq_show_option(m, "datadir+", lowerdirs[nr]);
|
||||
}
|
||||
if (ofs->config.upperdir) {
|
||||
seq_show_option(m, "upperdir", ofs->config.upperdir);
|
||||
seq_show_option(m, "workdir", ofs->config.workdir);
|
||||
|
||||
Reference in New Issue
Block a user