Commit 819829f0 authored by Amir Goldstein's avatar Amir Goldstein

ovl: refactor layer parsing helpers

In preparation for new mount options to add lowerdirs one by one,
generalize ovl_parse_param_upperdir() into helper ovl_parse_layer()
that will be used for parsing a single lower layers.
Suggested-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
Link: https://lore.kernel.org/r/CAJfpegt7VC94KkRtb1dfHG8+4OzwPBLYqhtc8=QFUxpFJE+=RQ@mail.gmail.com/Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
parent 0cea4c09
...@@ -43,7 +43,7 @@ module_param_named(metacopy, ovl_metacopy_def, bool, 0644); ...@@ -43,7 +43,7 @@ module_param_named(metacopy, ovl_metacopy_def, bool, 0644);
MODULE_PARM_DESC(metacopy, MODULE_PARM_DESC(metacopy,
"Default to on or off for the metadata only copy up feature"); "Default to on or off for the metadata only copy up feature");
enum { enum ovl_opt {
Opt_lowerdir, Opt_lowerdir,
Opt_upperdir, Opt_upperdir,
Opt_workdir, Opt_workdir,
...@@ -238,19 +238,8 @@ static int ovl_mount_dir_noesc(const char *name, struct path *path) ...@@ -238,19 +238,8 @@ static int ovl_mount_dir_noesc(const char *name, struct path *path)
pr_err("failed to resolve '%s': %i\n", name, err); pr_err("failed to resolve '%s': %i\n", name, err);
goto out; goto out;
} }
err = -EINVAL;
if (ovl_dentry_weird(path->dentry)) {
pr_err("filesystem on '%s' not supported\n", name);
goto out_put;
}
if (!d_is_dir(path->dentry)) {
pr_err("'%s' not a directory\n", name);
goto out_put;
}
return 0; return 0;
out_put:
path_put_init(path);
out: out:
return err; return err;
} }
...@@ -268,7 +257,7 @@ static void ovl_unescape(char *s) ...@@ -268,7 +257,7 @@ static void ovl_unescape(char *s)
} }
} }
static int ovl_mount_dir(const char *name, struct path *path, bool upper) static int ovl_mount_dir(const char *name, struct path *path)
{ {
int err = -ENOMEM; int err = -ENOMEM;
char *tmp = kstrdup(name, GFP_KERNEL); char *tmp = kstrdup(name, GFP_KERNEL);
...@@ -276,60 +265,82 @@ static int ovl_mount_dir(const char *name, struct path *path, bool upper) ...@@ -276,60 +265,82 @@ static int ovl_mount_dir(const char *name, struct path *path, bool upper)
if (tmp) { if (tmp) {
ovl_unescape(tmp); ovl_unescape(tmp);
err = ovl_mount_dir_noesc(tmp, path); err = ovl_mount_dir_noesc(tmp, path);
if (!err && upper && path->dentry->d_flags & DCACHE_OP_REAL) {
pr_err("filesystem on '%s' not supported as upperdir\n",
tmp);
path_put_init(path);
err = -EINVAL;
}
kfree(tmp); kfree(tmp);
} }
return err; return err;
} }
static int ovl_parse_param_upperdir(const char *name, struct fs_context *fc, static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
bool workdir) enum ovl_opt layer, const char *name, bool upper)
{ {
int err; if (ovl_dentry_weird(path->dentry))
struct ovl_fs *ofs = fc->s_fs_info; return invalfc(fc, "filesystem on %s not supported", name);
struct ovl_config *config = &ofs->config;
struct ovl_fs_context *ctx = fc->fs_private;
struct path path;
char *dup;
err = ovl_mount_dir(name, &path, true); if (!d_is_dir(path->dentry))
if (err) return invalfc(fc, "%s is not a directory", name);
return err;
/* /*
* Check whether upper path is read-only here to report failures * Check whether upper path is read-only here to report failures
* early. Don't forget to recheck when the superblock is created * early. Don't forget to recheck when the superblock is created
* as the mount attributes could change. * as the mount attributes could change.
*/ */
if (__mnt_is_readonly(path.mnt)) { if (upper) {
path_put(&path); if (path->dentry->d_flags & DCACHE_OP_REAL)
return -EINVAL; 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);
} }
return 0;
}
dup = kstrdup(name, GFP_KERNEL); static void ovl_add_layer(struct fs_context *fc, enum ovl_opt layer,
if (!dup) { struct path *path, char **pname)
path_put(&path); {
return -ENOMEM; struct ovl_fs *ofs = fc->s_fs_info;
} struct ovl_config *config = &ofs->config;
struct ovl_fs_context *ctx = fc->fs_private;
if (workdir) { switch (layer) {
kfree(config->workdir); case Opt_workdir:
config->workdir = dup; swap(config->workdir, *pname);
path_put(&ctx->work); swap(ctx->work, *path);
ctx->work = path; break;
} else { case Opt_upperdir:
kfree(config->upperdir); swap(config->upperdir, *pname);
config->upperdir = dup; swap(ctx->upper, *path);
path_put(&ctx->upper); break;
ctx->upper = path; default:
WARN_ON(1);
} }
return 0; }
static int ovl_parse_layer(struct fs_context *fc, struct fs_parameter *param,
enum ovl_opt layer)
{
char *name = kstrdup(param->string, GFP_KERNEL);
bool upper = (layer == Opt_upperdir || layer == Opt_workdir);
struct path path;
int err;
if (!name)
return -ENOMEM;
err = ovl_mount_dir(name, &path);
if (err)
goto out_free;
err = ovl_mount_dir_check(fc, &path, layer, name, upper);
if (err)
goto out_put;
/* Store the user provided path string in ctx to show in mountinfo */
ovl_add_layer(fc, layer, &path, &name);
out_put:
path_put(&path);
out_free:
kfree(name);
return err;
} }
static void ovl_reset_lowerdirs(struct ovl_fs_context *ctx) static void ovl_reset_lowerdirs(struct ovl_fs_context *ctx)
...@@ -417,7 +428,11 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc) ...@@ -417,7 +428,11 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
for (nr = 0; nr < nr_lower; nr++, l++) { for (nr = 0; nr < nr_lower; nr++, l++) {
memset(l, 0, sizeof(*l)); memset(l, 0, sizeof(*l));
err = ovl_mount_dir(iter, &l->path, false); err = ovl_mount_dir(iter, &l->path);
if (err)
goto out_put;
err = ovl_mount_dir_check(fc, &l->path, Opt_lowerdir, iter, false);
if (err) if (err)
goto out_put; goto out_put;
...@@ -505,10 +520,8 @@ static int ovl_parse_param(struct fs_context *fc, struct fs_parameter *param) ...@@ -505,10 +520,8 @@ static int ovl_parse_param(struct fs_context *fc, struct fs_parameter *param)
err = ovl_parse_param_lowerdir(param->string, fc); err = ovl_parse_param_lowerdir(param->string, fc);
break; break;
case Opt_upperdir: case Opt_upperdir:
fallthrough;
case Opt_workdir: case Opt_workdir:
err = ovl_parse_param_upperdir(param->string, fc, err = ovl_parse_layer(fc, param, opt);
(Opt_workdir == opt));
break; break;
case Opt_default_permissions: case Opt_default_permissions:
config->default_permissions = true; config->default_permissions = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment