Commit 32db5107 authored by Amir Goldstein's avatar Amir Goldstein

ovl: fix regression in showing lowerdir mount option

Before commit b36a5780 ("ovl: modify layer parameter parsing"),
spaces and commas in lowerdir mount option value used to be escaped using
seq_show_option().

In current upstream, when lowerdir value has a space, it is not escaped
in /proc/mounts, e.g.:

  none /mnt overlay rw,relatime,lowerdir=l l,upperdir=u,workdir=w 0 0

which results in broken output of the mount utility:

  none on /mnt type overlay (rw,relatime,lowerdir=l)

Store the original lowerdir mount options before unescaping and show
them using the same escaping used for seq_show_option() in addition to
escaping the colon separator character.

Fixes: b36a5780 ("ovl: modify layer parameter parsing")
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
parent c34706ac
...@@ -339,6 +339,18 @@ The specified lower directories will be stacked beginning from the ...@@ -339,6 +339,18 @@ The specified lower directories will be stacked beginning from the
rightmost one and going left. In the above example lower1 will be the rightmost one and going left. In the above example lower1 will be the
top, lower2 the middle and lower3 the bottom layer. top, lower2 the middle and lower3 the bottom layer.
Note: directory names containing colons can be provided as lower layer by
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:
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.
Metadata only copy up Metadata only copy up
--------------------- ---------------------
......
...@@ -192,7 +192,8 @@ static ssize_t ovl_parse_param_split_lowerdirs(char *str) ...@@ -192,7 +192,8 @@ static ssize_t ovl_parse_param_split_lowerdirs(char *str)
for (s = d = str;; s++, d++) { for (s = d = str;; s++, d++) {
if (*s == '\\') { if (*s == '\\') {
s++; /* keep esc chars in split lowerdir */
*d++ = *s++;
} else if (*s == ':') { } else if (*s == ':') {
bool next_colon = (*(s + 1) == ':'); bool next_colon = (*(s + 1) == ':');
...@@ -267,7 +268,7 @@ static void ovl_unescape(char *s) ...@@ -267,7 +268,7 @@ static void ovl_unescape(char *s)
} }
} }
static int ovl_mount_dir(const char *name, struct path *path) static int ovl_mount_dir(const char *name, struct path *path, bool upper)
{ {
int err = -ENOMEM; int err = -ENOMEM;
char *tmp = kstrdup(name, GFP_KERNEL); char *tmp = kstrdup(name, GFP_KERNEL);
...@@ -276,7 +277,7 @@ static int ovl_mount_dir(const char *name, struct path *path) ...@@ -276,7 +277,7 @@ static int ovl_mount_dir(const char *name, struct path *path)
ovl_unescape(tmp); ovl_unescape(tmp);
err = ovl_mount_dir_noesc(tmp, path); err = ovl_mount_dir_noesc(tmp, path);
if (!err && path->dentry->d_flags & DCACHE_OP_REAL) { if (!err && upper && path->dentry->d_flags & DCACHE_OP_REAL) {
pr_err("filesystem on '%s' not supported as upperdir\n", pr_err("filesystem on '%s' not supported as upperdir\n",
tmp); tmp);
path_put_init(path); path_put_init(path);
...@@ -297,7 +298,7 @@ static int ovl_parse_param_upperdir(const char *name, struct fs_context *fc, ...@@ -297,7 +298,7 @@ static int ovl_parse_param_upperdir(const char *name, struct fs_context *fc,
struct path path; struct path path;
char *dup; char *dup;
err = ovl_mount_dir(name, &path); err = ovl_mount_dir(name, &path, true);
if (err) if (err)
return err; return err;
...@@ -500,7 +501,7 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc) ...@@ -500,7 +501,7 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
l = &ctx->lower[nr]; l = &ctx->lower[nr];
memset(l, 0, sizeof(*l)); memset(l, 0, sizeof(*l));
err = ovl_mount_dir_noesc(dup_iter, &l->path); err = ovl_mount_dir(dup_iter, &l->path, false);
if (err) if (err)
goto out_put; goto out_put;
...@@ -979,16 +980,23 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry) ...@@ -979,16 +980,23 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry)
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
struct ovl_fs *ofs = OVL_FS(sb); struct ovl_fs *ofs = OVL_FS(sb);
size_t nr, nr_merged_lower = ofs->numlayer - ofs->numdatalayer; size_t nr, nr_merged_lower = ofs->numlayer - ofs->numdatalayer;
char **lowerdatadirs = &ofs->config.lowerdirs[nr_merged_lower];
/*
/* lowerdirs[] starts from offset 1 */ * lowerdirs[] starts from offset 1, then
seq_printf(m, ",lowerdir=%s", ofs->config.lowerdirs[1]); * >= 0 regular lower layers prefixed with : and
/* dump regular lower layers */ * >= 0 data-only lower layers prefixed with ::
for (nr = 2; nr < nr_merged_lower; nr++) *
seq_printf(m, ":%s", ofs->config.lowerdirs[nr]); * we need to escase comma and space like seq_show_option() does and
/* dump data lower layers */ * we also need to escape the colon separator from lowerdir paths.
for (nr = 0; nr < ofs->numdatalayer; nr++) */
seq_printf(m, "::%s", lowerdatadirs[nr]); seq_puts(m, ",lowerdir=");
for (nr = 1; nr < ofs->numlayer; nr++) {
if (nr > 1)
seq_putc(m, ':');
if (nr >= nr_merged_lower)
seq_putc(m, ':');
seq_escape(m, ofs->config.lowerdirs[nr], ":, \t\n\\");
}
if (ofs->config.upperdir) { if (ofs->config.upperdir) {
seq_show_option(m, "upperdir", ofs->config.upperdir); seq_show_option(m, "upperdir", ofs->config.upperdir);
seq_show_option(m, "workdir", ofs->config.workdir); seq_show_option(m, "workdir", ofs->config.workdir);
......
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