Commit 16ae562e authored by Andrew Vagin's avatar Andrew Vagin Committed by Pavel Emelyanov

mount: dump a file system only if a mount point isn't overmounted

Here we try to enumerate all mount points and try to find one,
which allows us to dump content of a file system.

It's should be a root mount and its mount point should not be
overmounted.

We don't have a separate call-back to dump content of a file system.
fstype->dump() isn't always requires access to a mount point (e.g.
autofs), so we check overmounts in open_mountpoint().

$ cat /proc/61693/root/etc/redhat-release
Fedora release 23 (Twenty Three)

$ cat /proc/61692/mountinfo  | grep '\s/tmp'
234 199 0:57 / /tmp rw shared:97 master:76 - tmpfs tmpfs rw,size=131072k,nr_inodes=32768
235 234 0:57 /systemd-private-dd74de99e1104383aa7cd6e27d3d0b8a-httpd.service-uFqNHk/tmp /tmp rw,relatime shared:98 master:76 - tmpfs tmpfs rw,size=131072k,nr_inodes=32768

v2: return an error if we can't dump a file system
v3: try to find a mount point which allows to dump a file system
v4: check that children are not overmounted a target mount instead
of getting a mnt_id for a file descriptor.
v5: add a special error code for unreachable mount points
Signed-off-by: 's avatarAndrew Vagin <avagin@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 392c2f0b
...@@ -1151,8 +1151,10 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_ ...@@ -1151,8 +1151,10 @@ static char *get_clean_mnt(struct mount_info *mi, char *mnt_path_tmp, char *mnt_
return mnt_path; return mnt_path;
} }
#define MNT_UNREACHABLE INT_MIN
static int open_mountpoint(struct mount_info *pm) static int open_mountpoint(struct mount_info *pm)
{ {
struct mount_info *c;
int fd = -1, ns_old = -1; int fd = -1, ns_old = -1;
char mnt_path_tmp[] = "/tmp/cr-tmpfs.XXXXXX"; char mnt_path_tmp[] = "/tmp/cr-tmpfs.XXXXXX";
char mnt_path_root[] = "/cr-tmpfs.XXXXXX"; char mnt_path_root[] = "/cr-tmpfs.XXXXXX";
...@@ -1168,6 +1170,13 @@ static int open_mountpoint(struct mount_info *pm) ...@@ -1168,6 +1170,13 @@ static int open_mountpoint(struct mount_info *pm)
pr_info("Something is mounted on top of %s\n", pm->mountpoint); pr_info("Something is mounted on top of %s\n", pm->mountpoint);
list_for_each_entry(c, &pm->children, siblings) {
if (!strcmp(c->mountpoint, pm->mountpoint)) {
pr_debug("%d:%s is overmounted\n", pm->mnt_id, pm->mountpoint);
return MNT_UNREACHABLE;
}
}
/* /*
* To create a "private" copy, the target mount is bind-mounted * To create a "private" copy, the target mount is bind-mounted
* in a temporary place w/o MS_REC (non-recursively). * in a temporary place w/o MS_REC (non-recursively).
...@@ -1250,7 +1259,7 @@ static int tmpfs_dump(struct mount_info *pm) ...@@ -1250,7 +1259,7 @@ static int tmpfs_dump(struct mount_info *pm)
fd = open_mountpoint(pm); fd = open_mountpoint(pm);
if (fd < 0) if (fd < 0)
return -1; return fd;
/* if fd happens to be 0 here, we need to move it to something /* if fd happens to be 0 here, we need to move it to something
* non-zero, because cr_system_userns closes STDIN_FILENO as we are not * non-zero, because cr_system_userns closes STDIN_FILENO as we are not
...@@ -1461,7 +1470,7 @@ static int binfmt_misc_dump(struct mount_info *pm) ...@@ -1461,7 +1470,7 @@ static int binfmt_misc_dump(struct mount_info *pm)
fd = open_mountpoint(pm); fd = open_mountpoint(pm);
if (fd < 0) if (fd < 0)
return -1; return fd;
fdir = fdopendir(fd); fdir = fdopendir(fd);
if (fdir == NULL) { if (fdir == NULL) {
...@@ -1632,7 +1641,7 @@ static int fusectl_dump(struct mount_info *pm) ...@@ -1632,7 +1641,7 @@ static int fusectl_dump(struct mount_info *pm)
fd = open_mountpoint(pm); fd = open_mountpoint(pm);
if (fd < 0) if (fd < 0)
return -1; return fd;
fdir = fdopendir(fd); fdir = fdopendir(fd);
if (fdir == NULL) { if (fdir == NULL) {
...@@ -1686,10 +1695,10 @@ static int cgroup_parse(struct mount_info *pm) ...@@ -1686,10 +1695,10 @@ static int cgroup_parse(struct mount_info *pm)
static int dump_empty_fs(struct mount_info *pm) static int dump_empty_fs(struct mount_info *pm)
{ {
int fd, ret = -1; int fd, ret = -1;
fd = open_mountpoint(pm);
fd = open_mountpoint(pm);
if (fd < 0) if (fd < 0)
return -1; return fd;
ret = is_empty_dir(fd); ret = is_empty_dir(fd);
close(fd); close(fd);
...@@ -1885,6 +1894,41 @@ uns: ...@@ -1885,6 +1894,41 @@ uns:
return &fstypes[0]; return &fstypes[0];
} }
static int dump_one_fs(struct mount_info *mi)
{
struct mount_info *pm = mi;
struct mount_info *t;
bool first = true;
if (mi->is_ns_root || mi->need_plugin || mi->external || !mi->fstype->dump)
return 0;
/* mnt_bind is a cycled list, so list_for_each can't be used here. */
for (; &pm->mnt_bind != &mi->mnt_bind || first;
pm = list_entry(pm->mnt_bind.next, typeof(*pm), mnt_bind)) {
int ret;
first = false;
if (!fsroot_mounted(pm))
continue;
ret = pm->fstype->dump(pm);
if (ret == MNT_UNREACHABLE)
continue;
if (ret < 0)
return ret;
list_for_each_entry(t, &pm->mnt_bind, mnt_bind)
t->dumped = true;
return 0;
}
pr_err("Unable to dump a file system for %d:%s\n",
mi->mnt_id, mi->mountpoint);
return -1;
}
static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img) static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img)
{ {
MntEntry me = MNT_ENTRY__INIT; MntEntry me = MNT_ENTRY__INIT;
...@@ -1897,17 +1941,10 @@ static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img) ...@@ -1897,17 +1941,10 @@ static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img)
if (me.fstype == FSTYPE__AUTO) if (me.fstype == FSTYPE__AUTO)
me.fsname = pm->fsname; me.fsname = pm->fsname;
if (pm->parent && !pm->dumped && !pm->need_plugin && !pm->external &&
pm->fstype->dump && fsroot_mounted(pm)) {
struct mount_info *t;
if (pm->fstype->dump(pm)) if (!pm->dumped && dump_one_fs(pm))
return -1; return -1;
list_for_each_entry(t, &pm->mnt_bind, mnt_bind)
t->dumped = true;
}
me.mnt_id = pm->mnt_id; me.mnt_id = pm->mnt_id;
me.root_dev = pm->s_dev; me.root_dev = pm->s_dev;
me.parent_mnt_id = pm->parent_mnt_id; me.parent_mnt_id = pm->parent_mnt_id;
......
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