Skip to content

Commit 32db510

Browse files
committed
ovl: fix regression in showing lowerdir mount option
Before commit b36a578 ("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: b36a578 ("ovl: modify layer parameter parsing") Signed-off-by: Amir Goldstein <[email protected]>
1 parent c34706a commit 32db510

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

Documentation/filesystems/overlayfs.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,18 @@ The specified lower directories will be stacked beginning from the
339339
rightmost one and going left. In the above example lower1 will be the
340340
top, lower2 the middle and lower3 the bottom layer.
341341

342+
Note: directory names containing colons can be provided as lower layer by
343+
escaping the colons with a single backslash. For example:
344+
345+
mount -t overlay overlay -olowerdir=/a\:lower\:\:dir /merged
346+
347+
Since kernel version v6.5, directory names containing colons can also
348+
be provided as lower layer using the fsconfig syscall from new mount api:
349+
350+
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir", "/a:lower::dir", 0);
351+
352+
In the latter case, colons in lower layer directory names will be escaped
353+
as an octal characters (\072) when displayed in /proc/self/mountinfo.
342354

343355
Metadata only copy up
344356
---------------------

fs/overlayfs/params.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ static ssize_t ovl_parse_param_split_lowerdirs(char *str)
192192

193193
for (s = d = str;; s++, d++) {
194194
if (*s == '\\') {
195-
s++;
195+
/* keep esc chars in split lowerdir */
196+
*d++ = *s++;
196197
} else if (*s == ':') {
197198
bool next_colon = (*(s + 1) == ':');
198199

@@ -267,7 +268,7 @@ static void ovl_unescape(char *s)
267268
}
268269
}
269270

270-
static int ovl_mount_dir(const char *name, struct path *path)
271+
static int ovl_mount_dir(const char *name, struct path *path, bool upper)
271272
{
272273
int err = -ENOMEM;
273274
char *tmp = kstrdup(name, GFP_KERNEL);
@@ -276,7 +277,7 @@ static int ovl_mount_dir(const char *name, struct path *path)
276277
ovl_unescape(tmp);
277278
err = ovl_mount_dir_noesc(tmp, path);
278279

279-
if (!err && path->dentry->d_flags & DCACHE_OP_REAL) {
280+
if (!err && upper && path->dentry->d_flags & DCACHE_OP_REAL) {
280281
pr_err("filesystem on '%s' not supported as upperdir\n",
281282
tmp);
282283
path_put_init(path);
@@ -297,7 +298,7 @@ static int ovl_parse_param_upperdir(const char *name, struct fs_context *fc,
297298
struct path path;
298299
char *dup;
299300

300-
err = ovl_mount_dir(name, &path);
301+
err = ovl_mount_dir(name, &path, true);
301302
if (err)
302303
return err;
303304

@@ -500,7 +501,7 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
500501
l = &ctx->lower[nr];
501502
memset(l, 0, sizeof(*l));
502503

503-
err = ovl_mount_dir_noesc(dup_iter, &l->path);
504+
err = ovl_mount_dir(dup_iter, &l->path, false);
504505
if (err)
505506
goto out_put;
506507

@@ -979,16 +980,23 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry)
979980
struct super_block *sb = dentry->d_sb;
980981
struct ovl_fs *ofs = OVL_FS(sb);
981982
size_t nr, nr_merged_lower = ofs->numlayer - ofs->numdatalayer;
982-
char **lowerdatadirs = &ofs->config.lowerdirs[nr_merged_lower];
983-
984-
/* lowerdirs[] starts from offset 1 */
985-
seq_printf(m, ",lowerdir=%s", ofs->config.lowerdirs[1]);
986-
/* dump regular lower layers */
987-
for (nr = 2; nr < nr_merged_lower; nr++)
988-
seq_printf(m, ":%s", ofs->config.lowerdirs[nr]);
989-
/* dump data lower layers */
990-
for (nr = 0; nr < ofs->numdatalayer; nr++)
991-
seq_printf(m, "::%s", lowerdatadirs[nr]);
983+
984+
/*
985+
* lowerdirs[] starts from offset 1, then
986+
* >= 0 regular lower layers prefixed with : and
987+
* >= 0 data-only lower layers prefixed with ::
988+
*
989+
* we need to escase comma and space like seq_show_option() does and
990+
* we also need to escape the colon separator from lowerdir paths.
991+
*/
992+
seq_puts(m, ",lowerdir=");
993+
for (nr = 1; nr < ofs->numlayer; nr++) {
994+
if (nr > 1)
995+
seq_putc(m, ':');
996+
if (nr >= nr_merged_lower)
997+
seq_putc(m, ':');
998+
seq_escape(m, ofs->config.lowerdirs[nr], ":, \t\n\\");
999+
}
9921000
if (ofs->config.upperdir) {
9931001
seq_show_option(m, "upperdir", ofs->config.upperdir);
9941002
seq_show_option(m, "workdir", ofs->config.workdir);

0 commit comments

Comments
 (0)